--- source_keys: - context7-websites-code-claude - claude-code-subagents-docs - context7-github-en-copilot - github-custom-agents-configuration --- # Agent Description Quality Reference Upstream source: Claude Code subagent reference, GitHub Copilot custom-agents configuration. House contract: ADR-0020, the context budget. The house contract is narrower than either platform's schema rather than a reinterpretation of it: where both speak, both must be satisfied. ## Why the description is the expensive part At startup an agent loads only the `name` and `description` of every installed skill and agent. The body is never seen until the agent is invoked. The description therefore carries the entire triggering burden **and** is paid for in every session, whether the agent fires or not. A second cost is less obvious and is a correctness hazard rather than a token cost: a description that summarises the workflow is a shortcut the caller takes *instead of* reading the body. A measured failure upstream — a description saying "code review between tasks" — produced one review where the body's flowchart specified two. ## Step 0 — establish which contract applies Read the frontmatter before judging a single word. - **`disable-model-invocation: true` or `user-invocable: false`** — the agent is hand-invoked. Its description is never matched against user intent, so it is not a routing string. It carries **one plain human-facing sentence** stating what the agent does. Audit it for that and nothing else. Reporting a missing trigger clause, a missing boundary clause or absent indirect triggers on a hand-invoked agent is a wrong finding, not a strict one. Both fields are Copilot-only and neither is on the vendor-neutral APM allowlist, so this case arises in a Copilot `.agent.md` at project/user scope and nowhere else. Its Claude Code counterpart has no equivalent field and stays model-invoked, so the two halves of the pair carrying differently shaped descriptions is expected there rather than a pair-consistency finding. - **No such flag** — the agent is model-invoked and the rest of this file applies. ## The three-part shape A model-invoked description carries exactly three things: 1. **Trigger clause.** When to invoke, phrased imperatively: `Use when ...`. Not `This agent ...` — the caller is deciding whether to act, not reading a catalogue entry. 2. **At most one capability clause.** What it does, in one clause. Never an enumeration. 3. **Boundary clause.** Compressed form: `Not -> .` The target must resolve to a real skill directory or agent file in the authoring source. Everything else belongs in the body or in the plugin's `README.md`. ## Indirect triggers — conditional, never blanket Add "even if the user doesn't say X" **only where the user's natural phrasing genuinely omits the domain word.** True for the `gitea-*` family: people say "create an issue", not "create a Gitea issue". False for `git-commits`: nobody asks for a commit without saying commit. A blanket indirect-trigger clause on an agent whose domain word is unavoidable is padding charged to every session. ## Near-miss exclusions Add a boundary clause only where a sibling skill or agent could plausibly steal the activation. Use strong near-misses — queries that share keywords but need something different — not weak ones. One boundary clause per genuine near-miss; a list of four is enumeration wearing a boundary's clothes. ## Before / after ```yaml # FAIL — a noun-phrase opener rather than a trigger, capability enumeration in # place of one capability clause, and no boundary clause at all, preloaded into # every session forever. (The live git-orchestrate description, 254 chars.) description: Orchestrates git workflow operations for other agents. Invoke when a caller needs a multi-step or destructive git operation (rebase, force-push, branch deletion) coordinated across domain skills with safety gates, session context, and structured results. # PASS — trigger, one capability clause, boundary. The operation list and the # safety-gate mechanics are the body's job; the router cannot act on them. description: > Use when an agent caller needs a multi-step or destructive git operation dispatched and safety-gated. Not conversational git help -> git-workflow. ``` ## Auditing guidance Flag as FAIL if: - **Over 400 characters.** Measured on the folded YAML value, not the raw source lines. `validate.sh` reports the number; do not re-derive it, but do point the Fix at what to cut. Agent descriptions have no platform-documented ceiling of their own — unlike a skill's 1,024-character spec limit, the 400-character house ceiling is the only hard limit there is, so do not go looking for a backstop behind it. - **Internal mechanics appear in the description.** Any of: - capability enumeration or a feature list; - output-format detail ("Produces a compact findings report with Why and Fix per finding"); - composition or architecture notes ("composes X rather than duplicating Y", "a cross-cutting shared agent", "the human-facing entry point", "replaces the old flat invocation"); - implementation detail ("self-validates via a bundled deterministic script"). None of it can change a routing decision and all of it is preloaded. `Kyberforge.CompositionNote` catches the common phrasings deterministically; the rest is judgment. This is the rule that deflates a description, so apply it before reaching for length. - **The same trigger stated twice in two registers** — a verb list, then the same verbs re-quoted as user phrasings, usually in the same order. One register, whichever routes better. - **Descriptive rather than imperative phrasing** (`This agent ...`, `This is the ...`). `Kyberforge.DescriptionOpener` catches any opener matching `^This`. There is no action-verb rule here and never was a defensible one: an `Orchestrates ...` or `Audits ...` opener is a catalogue entry, not a trigger. - **Vague capabilities** ("helps with agents" where "audits an agent definition pair" was available). `Kyberforge.VagueWording` catches the known filler; imprecision outside that list is judgment. - **A boundary clause naming a target that does not resolve** to a real skill directory or agent file in the authoring source. `validate.sh` resolves this for agent files at both scopes and reports each unresolved target itself — take its verdict rather than re-resolving the name by hand, because a hand-walk over a different universe can contradict it. What is left to you is semantic and the script cannot reach it: whether a target that *does* resolve is the right sibling to exclude, and whether a clause naming no target at all ("examine the files manually") should have named one. - **`Use proactively` in a Copilot or vendor-neutral description.** `KyberforgeCopilot.ProactivePhrase` catches it. The phrase steers the Claude Code runtime and does nothing anywhere else, so in a `.agent.md` it is preloaded text that buys no behaviour. - **Trigger-list, boundary or indirect-trigger content on a hand-invoked agent** — see Step 0. Flag as SUGGESTION if: - **Over 250 characters** but at or under 400. This tier is what moves the corpus average; the FAIL tier only stops outliers. Report it rather than treating a 399-character description as clean. - A near-miss exclusion is present but targets a weak near-miss. - An indirect trigger is present and warranted but could name the omitted phrasing more precisely.