docs: finish reconciling the agent write fence across the toolchain
The previous round taught agent-audit's validator to permit disallowedTools but left the skill that writes agents still forbidding it, in six places. Running agent-author on any of the three fenced orchestrators would have stripped the fence, and nothing would have caught it: the validator's allowlist is a permit list, so an absent field passes. The template was the worst of them, since its comment is copied verbatim into every new plugin-scope agent. Where a list had to be restated it is now a pointer to field-inventory.md's apm-agent-allowlist instead -- the same data validate.sh reads -- because a roster copied into a template goes stale one step further out than the roster itself. Where the text has to teach something it teaches the shape rule rather than the exception: tools is an allowlist whose vocabulary differs per harness, so verbatim copy makes one value wrong on one target; disallowedTools is a denylist, where an unrecognised name denies nothing, so the worst case is a missing fence rather than a wrongly granted capability. ADR-0016's amendment claimed an unrecognised key is inert on Copilot while the same ADR's Context says that behaviour is unconfirmed by research -- asserting as settled the exact thing it flags as unknown, and justifying it with apm's compile-time behaviour, which says nothing about Copilot's runtime. It is rewritten into labelled tiers: confirmed for Claude Code with citations, inferred by analogy for Copilot with the analogy's limits stated, unverified where it is unverified, and the residual risk accepted explicitly with its blast radius. It also no longer claims to restore a write sandbox: the denylist does not deny Bash, which these agents inherit and legitimately need. docs/hooks.md called the old root hooks.json a stale sync artifact -- it was added in the plugin's creating commit and pointed at by main's Copilot manifest -- and claimed both ecosystems now resolve hooks/hooks.json. Copilot does not: its hooks field has no default and no compiled manifest declares one, so it resolves nothing. Recorded as the gap it is, with re-injection noted as a follow-up rather than asserted away. Its event list is marked partial. Also: new-agent.bats asserted a hardcoded four-field allowlist and would have rejected a scaffolded agent carrying the field the ADR now blesses; it reads field-inventory.md too. And ADR-0016's premise that Claude's tools: is space-separated was wrong -- it takes a comma-separated string or a YAML list. The incompatibility with Copilot is the vocabulary, not the punctuation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
This commit is contained in:
@@ -2,18 +2,25 @@
|
||||
<!-- Vendor-neutral APM agent definition (plugin/APM scope).
|
||||
Path: <package-root>/.apm/agents/<name>.agent.md — one file, no counterpart.
|
||||
`apm compile` copies this frontmatter verbatim to BOTH the Claude Code and
|
||||
Copilot CLI targets — there is no per-target field integrator. Claude's
|
||||
`tools:` (space-separated string) and Copilot's `tools:` (alias list) are
|
||||
incompatible vocabularies, and Claude-only fields (isolation, maxTurns,
|
||||
effort, memory, permissionMode) have no Copilot equivalent. A value correct
|
||||
for one harness is guaranteed wrong on the other, so this scope carries
|
||||
ONLY the fields below — full stop (see ADR-0016). `source_keys` is
|
||||
provenance metadata, not a runtime field, and is exempt from that rule.
|
||||
Copilot CLI targets, with no per-target field integrator to reconcile
|
||||
anything, so a harness-specific value is wrong on at least one of them.
|
||||
|
||||
Do NOT add: tools, isolation, maxTurns, effort, memory, permissionMode,
|
||||
disallowedTools, skills, color, initialPrompt, background, hooks, or
|
||||
mcpServers. Omitting `tools` means inherit-all-tools on both harnesses,
|
||||
which is never wrong.
|
||||
This template does not restate the permitted-field list. The authoritative
|
||||
list is the `apm-agent-allowlist` section of agent-audit's
|
||||
references/field-inventory.md, which agent-audit's validate.sh reads from
|
||||
there as data — a list copied into a template goes stale one step further
|
||||
out than the list itself. Every field scaffolded below is on it; before
|
||||
adding any other field, check that section.
|
||||
|
||||
The shape rule behind the list (ADR-0016 and its 2026-08-14 amendment):
|
||||
`tools` is an ALLOWLIST whose vocabulary differs per harness — Claude tool
|
||||
names vs Copilot's execute/read/edit/search/agent/web — so one value is
|
||||
wrong on one target. Never add it here; omitting it means inherit-all-tools
|
||||
on both harnesses, which is never wrong. `disallowedTools` is a DENYLIST
|
||||
and is allowed for exactly that reason: a name the other harness does not
|
||||
recognise denies nothing, so the worst case is a missing fence, never a
|
||||
wrongly granted capability. Claude-only knobs (isolation, maxTurns, effort,
|
||||
memory, permissionMode) have no Copilot equivalent and stay out.
|
||||
|
||||
Fill in all FILL IN: placeholders. Delete template comments before shipping. -->
|
||||
|
||||
@@ -30,6 +37,16 @@ description: FILL IN: Action-first description of what this agent does and when
|
||||
Optional. Aliases: sonnet, opus, haiku, fable. Or full model ID.
|
||||
Omit to inherit the runtime default on whichever harness compiles this file. -->
|
||||
|
||||
<!-- disallowedTools: Edit, Write, NotebookEdit
|
||||
Optional. Denylist, applied before `tools` and taking precedence over it.
|
||||
Add it when this agent is read-only — it is the one tool restriction that
|
||||
survives verbatim copy (see the header comment). Claude Code honours it for
|
||||
plugin subagents — confirmed. Copilot's handling of the key is unconfirmed;
|
||||
ADR-0016 accepts that as a stated risk rather than a settled fact.
|
||||
It denies only the tools it names. It does NOT deny Bash, which this agent
|
||||
inherits, so a shell redirect still writes — state the read-only boundary
|
||||
in the system prompt body as well, not in frontmatter alone. -->
|
||||
|
||||
<!-- source_keys:
|
||||
- slug-name
|
||||
Development-only. Add when research sources informed this agent (slugs must match
|
||||
|
||||
@@ -14,8 +14,9 @@ description: FILL IN: Action-first description of what this agent does and when
|
||||
Be specific about the triggering condition and domain.
|
||||
Example: "Reviews pull request diffs for security issues. Use proactively after code changes." -->
|
||||
|
||||
<!-- tools: Read Bash Grep
|
||||
Optional. Space-separated allowlist. Omit to inherit all tools from parent.
|
||||
<!-- tools: Read, Bash, Grep
|
||||
Optional. Allowlist of tool names: a comma-separated string or a YAML list.
|
||||
Omit to inherit all tools from parent.
|
||||
Use Agent(type1,type2) to restrict which subagent types this agent can spawn.
|
||||
Omit Agent entirely to prevent this agent from spawning subagents.
|
||||
Never available to subagents regardless of tools field:
|
||||
@@ -47,9 +48,13 @@ description: FILL IN: Action-first description of what this agent does and when
|
||||
<!-- background: false
|
||||
Optional. Set true to force background execution. -->
|
||||
|
||||
<!-- disallowedTools: mcp__filesystem__write_file
|
||||
Optional. Space-separated denylist, applied before the tools allowlist.
|
||||
Supports mcp__* glob patterns (e.g. mcp__filesystem__* to block all filesystem tools). -->
|
||||
<!-- disallowedTools: Edit, Write, NotebookEdit
|
||||
Optional. Denylist, applied before the tools allowlist and taking precedence over it.
|
||||
Accepts a YAML list or a delimited string; use the comma-separated string form for
|
||||
consistency with the plugin-scope agents in this repo.
|
||||
Supports mcp__* glob patterns (e.g. mcp__filesystem__* to block all filesystem tools).
|
||||
Denies only the tools it names — it does not deny Bash, so an agent that inherits
|
||||
Bash can still write via a shell redirect. State read-only intent in the body too. -->
|
||||
|
||||
<!-- skills:
|
||||
- skill-name
|
||||
|
||||
Reference in New Issue
Block a user