--- source_keys: - claude-code-subagents-docs - github-custom-agents-configuration --- # The agent description and body contract House contract, set by ADR-0020. The counts and the boundary targets are enforced by `agent-audit`'s `scripts/validate.sh`; the prose patterns by the Vale styles it bundles; the judgment calls by its reference files. ## Why the budget exists An agent's `name` and `description` is loaded into every session's context at startup, whether or not the agent is ever delegated to — the same cost a skill's description carries, so agents take the same numbers. The body is different: it is not loaded into the caller's conversation at all, it *becomes the system prompt of a fresh context* when the agent runs. That is why the body has no word gate here and a skill body has one. ## Description A description carries exactly three things: 1. **Trigger clause** — when to delegate, imperative: "Use when …", never "This agent …". Describe the user's intent and the triggering condition, not the agent's internal mechanics. 2. **At most one capability clause** — what it does, one clause, no enumeration. Be specific ("reviews a diff for injected credentials", not "helps with security"). 3. **Boundary clause** — form: `Not -> .` Add one only where a near-miss agent or skill could steal delegations. Banned from a description; move it to the body or to `README.md`: - Capability enumeration or feature lists - Per-scope emission mechanics — which files the author skill writes at which scope changes no delegation decision - Output-format detail ("Produces a compact findings report with Why and Fix per finding") - Composition or architecture notes ("composes X rather than duplicating Y", "cross-cutting") - Implementation detail ("Self-validates via a bundled deterministic script") - Restating the same trigger twice in two registers — a verb list, then the same verbs re-quoted as user phrasings. This is a FAIL, not a suggestion. **Do not open with an action verb.** "Reviews…", "Analyzes…", "Generates…" was the old house rule and ADR-0020 deleted it: the opener is `Use when`, matching every skill in this corpus, so one router reads one shape. **"Use proactively" is conditional.** Add it only where the runtime should delegate without the user naming the agent — an agent invoked by name does not need it, and it costs activations elsewhere when added by reflex. The same conditional governs indirect triggers ("even if the user doesn't say X"): add one only where the user's natural phrasing genuinely omits the domain word. **Boundary targets must resolve.** The name after the arrow is checked against real skills under `plugins/*/.apm/skills//` and real agents under `plugins/*/.apm/agents/.agent.md`. A target that does not exist sends the router nowhere. Verify it before writing it — do not invent a plausible sibling. **Length.** 250 characters SUGGESTION, 400 characters FAIL, counting the frontmatter value only with YAML folding resolved. Treat 250 as the target: the SUGGESTION tier is what moves the corpus average, the FAIL tier only stops outliers. ## Body Write the body as a direct role instruction, addressed to the agent: ````markdown You are a . When invoked, . ## Inputs ## Process ## Output ```` One job per agent. An agent covering two jobs gets delegated to for the wrong one. **Delegation discipline replaces the word gate.** A plugin/APM agent is a single file with no sibling `references/` directory: it cannot disclose progressively to itself, so its only way to stay short is to *invoke* rather than *restate*. A body that transcribes a procedure a skill it can invoke already owns is an `agent-audit` FAIL, and the fix is one line — "invoke ``". - Restating: "To commit, check the message against Conventional Commits: type, scope, description; header under 100 chars; …" - Delegating: "Author commits with `git-commits`." The same holds for a procedure another agent owns. What belongs in the body is what no invocable skill covers: the agent's role, its boundaries, the order it works in, and the format it returns. **State a read-only boundary in prose, not only in frontmatter.** `disallowedTools` denies the tools it names and nothing else — never `Bash`, which an agent with no `tools` field inherits — so an agent fenced only in frontmatter can still write through a shell redirect. ## Invocation axis Decide before writing the description whether the agent is model-delegated (the runtime picks it) or reached only by name (`@agent-`). Only Copilot's cloud/IDE format expresses that in frontmatter: `disable-model-invocation: true` requires explicit invocation, and `user-invocable: false` hides an agent from manual invocation. Both live in `.github/copilot/agents/.md` and are inert in the CLI format. Claude Code has no equivalent field, and neither does the vendor-neutral plugin/APM file, so at those scopes a name-invoked agent still needs a description precise enough not to steal delegations — the boundary clause is doing that work. ## One gate, two measurements | Gate | SUGGESTION | FAIL | Counts | |---|---|---|---| | description | 250 chars | 400 chars | the `description:` value only | | body (Copilot limit) | 30,000 chars | — | the body only; content past it is truncated silently | The 30,000-character Copilot ceiling is a runtime truncation limit, not a quality target, and it applies to a plugin/APM file too — that file compiles into a real Copilot agent downstream. An agent body long enough to approach it has a delegation defect, not a length problem.