Skill name+description pairs are preloaded into every session, costing ~6,200 tokens across 39 skills before any skill is invoked. The authoring rules mandated that growth: skill-author:104 and description-quality.md:21 both required padding, while skill-author:102 (the deflating rule) had no FAIL condition behind it. Gates (blocking, no baseline file): - description 250 chars SUGGESTION / 400 FAIL, measured on the folded YAML value - body-only 600 words SUGGESTION / 900 FAIL, independent of the unchanged whole-file 2770-word / 500-line spec backstop - every boundary-clause routing target must resolve to a real skill or agent; catches skill-improve, neuledge-context and gitea-labels - agents take the description gates but deliberately no body gate; a test pins that absence Vale: DescriptionOpener widened to ^This\b, new CompositionNote rule banning architecture notes from descriptions. 10 hits, 0 false positives. Kyberforge's own four skills retrofitted: descriptions 3,364 -> 938 chars (-72%), bodies 8,306 -> 2,487 words (-70%), all via the apm-workflow dispatch pattern. Fixes the skill-improve dangling route and the agent-author misroute to manual review. Also fixes a pre-existing false positive where any line-initial 'read ' was flagged as interactive input, which had already caused two scripts to be rewritten around it. Refs: ADR-0020
128 lines
7.2 KiB
Markdown
128 lines
7.2 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` 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 <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.
|
|
```
|
|
|
|
## 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. No script checks this for an agent file — `validate.sh` resolves
|
|
boundary targets for skills only, so resolve the name yourself against `plugins/*/.apm/skills/`
|
|
and `plugins/*/.apm/agents/`.
|
|
- **`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.
|