Diffing each retrofitted SKILL.md against its replacement references/ files found rules that existed on main and now existed nowhere — relocated in intent, deleted in fact. A trim that loses a rule is not progressive disclosure, it is data loss with a smaller word count. Three had no survivor. The least-privilege guidance for `tools` kept its mechanics and lost the "restrict to what the agent needs" half, so the remaining text read as encouragement to omit the field. The improve flow lost its regression check, so nothing compared the closing audit against the pre-edit state and a PASS quietly becoming a SUGGESTION went unnoticed — restored on both halves of the author pair, since agent-author had dropped its equivalent too. And agent bodies lost "would the agent get this wrong without it?", which mattered more than it looks: ADR-0020 deliberately sets no body word gate for agents, three of the four already sit between 933 and 1,199 words, and the delegation check only fires on procedure a skill already owns. That heuristic was the only brake left. Two more were reachable only from the wrong scope. agent-author tells the reader to load only the file for the resolved scope, but the mcp__ glob syntax for disallowedTools and the five tools no subagent ever receives had both landed in project-user-scope.md. disallowedTools is the ONLY permitted fence at plugin/APM scope, so the scope that needs the syntax most could not reach it, and a plugin-scope run could write a body telling the agent to ask the user a question. Two documents were actively wrong rather than merely thin. agent-audit told auditors that validate.sh resolves boundary targets for skills only; it runs at both scopes, so the auditor was hand-resolving what the script had already decided and could contradict it. And skill-audit routed to its script-troubleshooting reference whenever validate.sh "fails" — but it exits 1 on ordinary content FAILs, the normal outcome for the whole #99 population, so 1,302 words loaded on nearly every audit. A context-budget regression inside the skill that enforces the context budget. Finally, two illustrations taught the shape the gate ERRORs on, unfenced, while an adjacent rubric called it a hard ERROR. LESSONS.md records the reference-chain depth rule flipping from "one level deep" to "two hops, never three". ADR-0020 is silent on it and the reversal rode entirely on the diff; the looser rule is what mandatory dispatch requires. Refs: #99 ADR: 0020 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015W3iwF9ncfRZddGBxsMCYi
65 lines
4.6 KiB
Markdown
65 lines
4.6 KiB
Markdown
---
|
|
name: agent-author
|
|
description: >
|
|
Use when the user wants to create a new agent definition file from scratch, or
|
|
apply grill findings, audit findings, or inline feedback to an existing one.
|
|
Not read-only review -> `agent-audit`. Not skills -> `skill-author`.
|
|
allowed-tools: Bash Read Write Edit
|
|
metadata:
|
|
category: factory
|
|
source_keys:
|
|
- context7-websites-code-claude
|
|
- claude-code-plugins-docs
|
|
- claude-code-subagents-docs
|
|
---
|
|
|
|
## Gotchas
|
|
|
|
- At plugin/APM scope `tools` and every Claude-only field are omitted entirely, not merely ignored: `apm compile` copies frontmatter verbatim to both harnesses, so fencing a read-only agent with `tools:` is wrong on one of them. `disallowedTools` is the one restriction that survives (ADR-0016).
|
|
- That fence is partial. It denies only the tools it names, never `Bash`, which a plugin-scope agent inherits — a shell redirect still writes. State the read-only boundary in the body too.
|
|
- An agent body carries no word gate; delegation replaces it. A plugin/APM agent is one file with no sibling `references/` directory, so it cannot disclose to itself, only invoke skills — and a body restating a procedure an invocable skill owns is an `agent-audit` FAIL.
|
|
- Duplicate `name` values in one scope: Claude Code discards one silently. Verify uniqueness before shipping.
|
|
|
|
## Step 1 — Dispatch
|
|
|
|
| Condition | Flow | Reference |
|
|
|---|---|---|
|
|
| No agent file at the target path(s) | Create | `references/create.md` |
|
|
| A file exists, at least one improvement signal present | Improve | `references/improve.md` |
|
|
| A file exists, no signals | Stop and ask | — |
|
|
|
|
Signals: grill output, `agent-audit` findings, inline feedback, session context describing what went wrong. With none, ask: "No improvement signals found. Did you mean to create a new agent, or do you have feedback to apply?"
|
|
|
|
Read only the reference for the resolved flow. Capture `git log --oneline -1` before touching the filesystem; Step 4 needs it.
|
|
|
|
## Step 2 — Scope
|
|
|
|
Scope decides which fields exist, so resolve it first. `scripts/new-agent.sh` walks up for a `type:`-bearing `apm.yml` and prints the scope it chose — read that output.
|
|
|
|
| Resolved scope | Emits | Read |
|
|
|---|---|---|
|
|
| plugin/APM | one vendor-neutral `.apm/agents/<name>.agent.md` | `references/plugin-scope.md` |
|
|
| project or user | a Claude Code `.md` + Copilot `.agent.md` pair | `references/project-user-scope.md` |
|
|
|
|
Read only the file for the resolved scope; the other describes fields this run cannot use. If precedence, cache isolation or path conventions matter, read `references/deployment-modes.md`.
|
|
|
|
## Step 3 — Contract
|
|
|
|
Before writing or editing a `description`, or restructuring a body, read `references/contract.md` — the three-part shape, banned content, the delegation rule and the body pattern.
|
|
|
|
Gates `agent-audit` enforces at every scope:
|
|
|
|
- **Description** — a trigger clause, at most one capability clause, and a boundary clause shaped `Not <thing> -> <name>` that resolves to a real skill or agent. 250 characters SUGGESTION, 400 FAIL, value only: an agent's `name` and `description` is preloaded into every session exactly as a skill's is.
|
|
- **Body** — no word gate, and a delegation check in its place: name the skill to invoke rather than restating what it does.
|
|
- **Invocation** — decide whether the agent is model-delegated or reached only by name. Only Copilot's cloud/IDE format expresses that in frontmatter (`disable-model-invocation`, `user-invocable`).
|
|
|
|
At every scope, five tools reach no subagent whatever `tools` says — `AskUserQuestion`, `EnterPlanMode`, `ExitPlanMode`, `ScheduleWakeup`, `WaitForMcpServers`. Never write a body that has the agent ask the user a question or enter plan mode; it describes a turn the runtime cannot give it.
|
|
|
|
## Step 4 — Validate and close
|
|
|
|
Invoke `agent-audit` on each file written and resolve every FAIL before reporting done. It checks the field allowlist, name-to-stem match, leftover placeholders and template comments, the description budget and the Copilot body limit — do not hand-check those.
|
|
|
|
At plugin/APM scope bump the resolved package's `apm.yml` `version` — **minor** on create, **patch** on improve — because consumers compare it to detect updates. Project and user scope have no manifest.
|
|
|
|
**Commit verification.** Once the audit is clean, run `git add` and `git commit` — do not stop at staging. Re-run `git log --oneline -1` and confirm the hash changed from Step 1's. A non-empty `git diff --stat` is not proof: staged-but-uncommitted work is part of no commit and is lost if the tree is cleaned up. Report done only once the hash has changed.
|