Regenerate plugins/*/skills/ from plugins/*/.apm/ after the previous four commits, via scripts/sync-plugin-content.sh --all. The mirror is generated output (ADR-0017) that check-plugin-content-sync's pre-push hook diffs against .apm/; nothing here is hand-edited. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
94 lines
4.9 KiB
Markdown
94 lines
4.9 KiB
Markdown
---
|
|
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`** — 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. The field is Copilot-only and not 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.
|
|
`user-invocable: false` does not belong in this bullet: it only blocks manual invocation and is
|
|
independent of `disable-model-invocation` — an agent can be `user-invocable: false` and still
|
|
model-routed, in which case the three-part shape below still applies. It carries no
|
|
description-quality contract of its own and is out of this file's scope entirely.
|
|
- **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 <thing> -> <skill-name>.` 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.
|
|
```
|
|
|
|
## Where the criteria live
|
|
|
|
Every FAIL and SUGGESTION criterion for this dimension is in `references/finding-criteria.md`,
|
|
which Step 3 reads on every run. This file is the reasoning behind them, loaded only when that file
|
|
puts the description dimension in play.
|