I was going back through a review on a client site late one evening when I noticed the agent had written a raw color value straight into the stylesheet. The workspace conventions say to reference a token instead.
When I went looking, the same note existed in two places. One was the conventions file. The other was a pre-delivery checklist. I had rewritten the conventions a while back and left the old wording sitting in the checklist.
The agent read the old one.
The cause was not the content of the instruction. It was that I had never decided where instructions belong. Antigravity gives you two separate containers — one for things you want in force every time, and one for things you want walked through only when asked — and the two load at completely different moments.
The two containers load at different moments
Rules hold constraints you want the agent to follow. Global rules live in ~/.gemini/GEMINI.md and apply across every workspace. Workspace rules live in the .agents/rules folder of your workspace or git root. Each file is capped at 12,000 characters.
Each rule also carries an activation setting, and you have four to choose from: manual (you call it with @ in the input box), always on, model decision (the model reads a natural-language description and decides whether to apply it), and glob (applied to files matching a pattern such as *.js or src/**/*.ts).
Skills hold procedures and knowledge as a bundle. A workspace skill lives at .agents/skills/<name>/SKILL.md, a global one at ~/.gemini/config/skills/<name>/SKILL.md. Because it is a folder rather than a single file, you can keep scripts/ and examples/ alongside it.
The difference that matters most is how each one gets read. Skills follow progressive disclosure. When a conversation starts, the agent sees only the name and description. The body is read later, and only if the skill looks relevant to what you asked for.
| Rules | Skills | |
|---|---|---|
| Workspace path | .agents/rules/<name>.md | .agents/skills/<name>/SKILL.md |
| Global path | ~/.gemini/GEMINI.md | ~/.gemini/config/skills/<name>/SKILL.md |
| Shape | A single Markdown file | A folder (SKILL.md plus assets) |
| How it loads | Full text, every turn, when active | Heading first, body on demand |
| Invocation | @ mention / always on / model decision / glob | /name, or the agent decides |
| Size limit | 12,000 characters per file | No practical ceiling — split it up |
One footnote on paths. The current default is .agents, but the older .agent is still read for backward compatibility. If both exist in your workspace, it is worth confirming once which one is actually being picked up.
Things that break if ignored, and things that break if forgotten
The question I settled on is a single one.
If breaking it costs you, put it in Rules. If forgetting it costs you, put it in Skills.
The first kind has no sequence to it. "Do not add a new configuration that connects to the production database." "Do not write raw color values." "Never run git push --force — propose it instead." None of these is about when; they are about always. An always-on rule fits.
The second kind is a procedure. Sweep for broken links before delivery, confirm every image carries width and height, write the report to the agreed folder. There is an order, skipping a step hurts, and yet you do not need any of it most of the time. That belongs in a skill.
Some cases genuinely sit between the two. A typographic convention you only want in force while touching CSS, for example. Always on means it rides along on unrelated work; a skill means it may never get invoked.
Glob activation is what stands in the gap here. Scope the rule to *.css and it applies only when a matching file is in play, without adding to what you carry the rest of the time. Once I stopped treating this as a binary between Rules and Skills and started including the activation setting as a third axis, the hesitation dropped away.
Measure what you carry each turn
Understanding this in the abstract is not the same as seeing the numbers. I wrote a small script to look at it.
#!/usr/bin/env bash
# instruction-budget.sh — lists what loads every turn vs. what loads only on demand.
# Usage: ./instruction-budget.sh [workspace root]
set -euo pipefail
ROOT="${1:-.}"
RULES_DIR="$ROOT/.agents/rules"
SKILLS_DIR="$ROOT/.agents/skills"
# Fall back to the legacy .agent layout when .agents is absent.
[ -d "$RULES_DIR" ] || RULES_DIR="$ROOT/.agent/rules"
[ -d "$SKILLS_DIR" ] || SKILLS_DIR="$ROOT/.agent/skills"
rules_total=0
echo "== Rules (active ones ride along every turn) =="
while IFS= read -r -d '' f; do
n=$(wc -m < "$f" | tr -d ' ')
printf ' %-28s %6s chars\n' "$(basename "$f")" "$n"
rules_total=$((rules_total + n))
# 12,000 characters is the per-file cap; anything past it may not be read.
[ "$n" -gt 12000 ] && echo " WARNING: over the 12,000-character cap"
done < <(find "$RULES_DIR" -maxdepth 1 -name '*.md' -print0 2>/dev/null | sort -z)
meta_total=0
body_total=0
echo "== Skills (only the heading loads up front) =="
while IFS= read -r -d '' f; do
body=$(wc -m < "$f" | tr -d ' ')
# The block between the first --- and the next --- is what gets indexed.
meta=$(awk '/^---[[:space:]]*$/{c++; next} c==1{print} c>1{exit}' "$f" | wc -m | tr -d ' ')
printf ' %-28s heading %4s chars / body %6s chars\n' \
"$(basename "$(dirname "$f")")" "$meta" "$body"
meta_total=$((meta_total + meta))
body_total=$((body_total + body))
done < <(find "$SKILLS_DIR" -mindepth 2 -maxdepth 2 -name 'SKILL.md' -print0 2>/dev/null | sort -z)
echo "---"
echo "Carried every turn : Rules ${rules_total} chars + Skill headings ${meta_total} chars"
echo "Only when invoked : Skill bodies ${body_total} chars"Run against a small workspace holding two rule files and two skills, it prints something like this.
== Rules (active ones ride along every turn) ==
house-style.md 156 chars
no-destructive-ops.md 104 chars
== Skills (only the heading loads up front) ==
imageset-build heading 101 chars / body 266 chars
release-check heading 101 chars / body 313 chars
---
Carried every turn : Rules 260 chars + Skill headings 202 chars
Only when invoked : Skill bodies 579 charsAt that size the gap is negligible. What matters is not the totals but the split: carried every turn on one line, only when invoked on the other. Add a rule file and the first line grows by the whole thing. Add a skill and it grows only by the heading. That asymmetry compounds as the files grow.
For a long time I put everything into Rules, because I wanted certainty that it would apply. That did not work out well. The conventions rode along on work they had nothing to do with, and the one line I most wanted respected got buried among the rest.
I did try splitting the conventions file itself. What I learned is that splitting reduces some costs and leaves others untouched — I wrote that up with measurements in What actually shrinks when you split rule files with @ imports.
Workflows retire on November 1
There is a second reason to revisit this now. Legacy Workflows are deprecated, and the official documentation states they will be retired on November 1, 2026. They keep working until then, after which the directories are no longer indexed or callable as slash commands.
The migration itself is light. Running the command below in Antigravity 2.0 scans both the global directory (~/.gemini/config/workflows/) and the workspace one (.agents/workflows/).
/migrate-workflowsEach workflow is scaffolded into .agents/skills/<name>/SKILL.md, and the original file is archived with a .bak suffix. If a workflow and a skill share a name, the skill takes precedence.
There is one thing a mechanical migration will drop, though. The description.
Workflows capped out at 12,000 characters, so I had trimmed my descriptions down to make room for the steps. In Skills, that description is exactly what the agent uses to decide. The name and description are all it sees at the start of a conversation, so a thin description means the skill never gets picked up.
After migrating, rewrite them. State what the skill does and when to use it, in the third person, with specifics.
# Rarely picked up
description: Checks the release.
# Actually picked up
description: Inspects a site before delivery and lists broken links, missing images, and absent meta tags. Use before handing off a client site or promoting to production.If you check only one thing right after migrating, check that the .bak files are still there. As long as they are, a rewrite that goes wrong is recoverable.
Three questions when you are stuck
These days I ask myself three things before writing any instruction at all.
- Does it have a sequence? If so, it is a skill.
- Would breaking it force me to redo work? If so, it is an always-on rule.
- Does it only matter while touching a certain kind of file? If so, it is a glob rule.
Looking back, anything that answered no to all three usually did not need writing down anywhere. The same held on the indie developer side of my work, where I run the asset pipeline for my wallpaper apps: notes I added without deciding where they belonged were, six months later, going almost entirely unread.
Start by counting the files in .agents/rules. The script above works, and so does a single wc -m .agents/rules/*.md. Once you can see the numbers, which ones to move into Skills tends to decide itself.
Decide where an instruction lives before writing it. The more instructions accumulate, the more that order seems to pay off. Thank you for reading this far.