docs: correct the claims this review found false

AGENTS.md told an offline agent to push with SKIP=apm-marketplace-check and
asserted that hook was "the only one whose failure mode is 'no network'".
Running all 12 pre-push hooks under a network namespace shows two fail, for
one shared cause: apm-pack-check-clean resolves the same remote entry. An
exact pin does not remove the ls-remote, so both hooks are named now.

AGENTS.md also said everything in a plugin root except .apm/ is generated.
Plugin roots carry hand-authored README.md, docs/, bin/, sources.md and
.mcp.json, so an agent would hunt for an .apm/ source that does not exist or
refuse the edit. The rule is positional: immunity belongs to the plugin root,
and anything inside a mirrored directory is still rm -rf'd.

ADR-0017 said apm strips a hooks field. The real loop is (agents, skills,
commands, instructions) -- hooks absent, instructions never mentioned -- and
it can never fire, because synthesize_plugin_json_from_apm_yml only emits the
eight identity fields. The decision stands; the mechanism was overstated. Its
mcpServers amendment is rewritten for the pointer payload and now records the
real reason: inlining bypassed apm's credential sanitizer.

ADR-0015's owner.email and version-pin passages are corrected against the apm
source, and ADR-0016 gains the disallowedTools amendment. agent-audit's
allowlist is data, so it gains disallowedTools too -- the ADR and the
validator that enforces it had come apart.

architecture.md described a root CLAUDE.md that imports two files (it imports
one, plus an RTK block) and pointed at an ADR index that does not exist.
Seven skill READMEs listed tests/ files the mirror strips, promising installed
users files their install lacks; those rows are marked source-only, with the
depth-4 template tests explicitly called out as surviving. And
plugins/kyberforge/hooks/README.md, deleted during the conversion and
preserved nowhere, is restored to a path the mirror does not own -- verified
by running a sync against a scratch copy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
This commit is contained in:
2026-08-14 11:04:56 +00:00
parent 7ba3d9cf1d
commit 430f46b8e8
19 changed files with 313 additions and 97 deletions

View File

@@ -25,4 +25,25 @@ target disable-model-invocation user-invocable mcp-servers metadata
## apm-agent-allowlist
name description model source_keys
name description model source_keys disallowedTools
Parsing note: `validate.sh` reads the **first** non-empty, non-`#`, non-`---` line under each
heading as a whitespace-separated token list, and stops there. Keep the token line immediately
below its heading; explanatory prose goes after it, as here.
Why `disallowedTools` is on a list that is otherwise vendor-neutral, when `tools` is not
(ADR-0016 and its 2026-08-14 amendment): the two are not symmetric. `tools` is an **allowlist**
whose vocabulary differs per harness — Claude Code names its own tools, Copilot CLI uses aliases
(`execute`/`read`/`edit`/`search`/`agent`/`web`) — so a value correct for one is wrong for the
other, and `apm compile` copies frontmatter verbatim with no per-target integrator to reconcile
them. `disallowedTools` is a **denylist**, and denying by name is safe under verbatim copy: a name
the other harness does not recognise denies nothing, so the worst case is that the fence is absent
there, never that the wrong capability is granted. Claude Code honours it for plugin subagents —
`docs/research/docs/claude-code-plugins/agent-definition.md:99` names the fields plugin agents
silently ignore (`hooks`, `mcpServers`, `permissionMode`) and `disallowedTools` is not among them.
`disallowedTools` also appears in `claude-code-only-fields` above, and that stays correct: at
project/user scope it is still a Claude-only field and must not appear in a Copilot `.agent.md`.
The two lists answer different questions — "may this field cross the CC/Copilot file boundary" for
a real pair, versus "is this field safe under verbatim copy to every target" for a single
vendor-neutral APM file.