chore(apm): regenerate content mirrors

Output of scripts/sync-plugin-content.sh --all against this round's .apm/
source edits. No file here is hand-edited.

Carries the agent-author and agent-audit documentation changes into the flat
mirrors. No compiled manifest changed: nothing in this round touched apm.yml,
so apm pack and sync-marketplace-mirror.sh both produced byte-identical output.

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 12:30:38 +00:00
parent f4bb1cf4e5
commit c16ec2d45a
8 changed files with 80 additions and 55 deletions

View File

@@ -7,11 +7,14 @@ plugin/APM scope, or a Claude Code and Copilot file pair at project/user scope.
At **plugin/APM scope**, accepts the single `.apm/agents/<name>.agent.md` file — there is no
counterpart. Structural checks via `validate.sh` hard-`FAIL` any frontmatter field outside the
vendor-neutral allowlist (`name`, `description`, `model`, `source_keys` — the last for
provenance tracking, checked separately by `validate-provenance.sh` against `sources.md`; see
ADR-0016), since `apm compile`
copies frontmatter verbatim to both harnesses and an unsafe field can't be silently dropped for
just one of them.
vendor-neutral allowlist, since `apm compile` copies frontmatter verbatim to both harnesses and an
unsafe field can't be silently dropped for just one of them. The allowlist itself lives in the
`apm-agent-allowlist` section of `references/field-inventory.md` and is read from there as data —
consult that section rather than any restatement of it, including this one. As of 2026-08-14 it
admits `name`, `description`, `model`, `source_keys`, and `disallowedTools`; `source_keys` is
provenance metadata checked separately by `validate-provenance.sh` against `sources.md`, and
`disallowedTools` is admitted because a denylist survives verbatim copy where the `tools` allowlist
does not (ADR-0016 and its 2026-08-14 amendment).
At **project/user scope**, accepts either file in a CC `.md` / Copilot `.agent.md` pair, derives
the counterpart automatically, and validates both. Runs structural checks via `validate.sh`

View File

@@ -8,9 +8,11 @@ Usage: validate.sh <agent-file>
Validate an agent definition file against the agent definition spec.
At plugin/APM scope, <agent-file> is a single vendor-neutral
.apm/agents/<name>.agent.md file (frontmatter allowlist: name, description,
model — no counterpart file). At project or user scope, <agent-file> is
either half of a Claude Code .md / Copilot .agent.md pair.
.apm/agents/<name>.agent.md file with no counterpart. Its frontmatter allowlist
is not restated here: it is read at load time from the apm-agent-allowlist
section of references/field-inventory.md, which is the authoritative list.
At project or user scope, <agent-file> is either half of a Claude Code .md /
Copilot .agent.md pair.
Arguments:
agent-file Path to the agent file (or either half of a project/user-scope pair).

View File

@@ -29,7 +29,9 @@ metadata:
## Gotchas
- At plugin/APM scope, bump the resolved package's `apm.yml` `version` after every change — minor for a new agent, patch for a fix. Consumers compare this version to detect updates; skipping it hides the change.
- At plugin/APM scope, `tools` and all Claude-only fields (`isolation`, `maxTurns`, `effort`, `memory`, `permissionMode`, `disallowedTools`, `skills`, `color`, `initialPrompt`, `background`, `hooks`, `mcpServers`) are omitted entirely, not merely restricted (ADR-0016: `apm compile` copies frontmatter verbatim to both harnesses with no per-target integrator, so a harness-specific value is wrong on at least one). Only project/user scope supports these fields.
- At plugin/APM scope, `tools` and all Claude-only fields (`isolation`, `maxTurns`, `effort`, `memory`, `permissionMode`, `skills`, `color`, `initialPrompt`, `background`, `hooks`, `mcpServers`) are omitted entirely, not merely restricted (ADR-0016: `apm compile` copies frontmatter verbatim to both harnesses with no per-target integrator, so a harness-specific value is wrong on at least one). Only project/user scope supports these fields.
- `disallowedTools` is the one exception, on **shape**, not favouritism. `tools` is an *allowlist* whose vocabulary differs per harness (Claude tool names vs Copilot's `execute`/`read`/`edit`/`search`/`agent`/`web`), so verbatim copy makes one value wrong on one target. A *denylist* cannot fail that way: an unrecognised name denies nothing, so the worst case is a missing fence, never a wrong grant. Claude Code honours it for plugin subagents — `docs/research/docs/claude-code-plugins/agent-definition.md:99` lists the three fields plugin agents ignore (`hooks`, `mcpServers`, `permissionMode`) and this is not one. Write it on every read-only plugin-scope agent (ADR-0016's 2026-08-14 amendment).
- That fence is partial: it denies only the tools it names. It does not deny `Bash`, which a plugin-scope agent with no `tools` inherits, so a shell redirect still writes. Say the agent is read-only in the body too.
- An `apm.yml` with no top-level `type:` field is a marketplace-only manifest, not a package root — the walk-up skips it and keeps going.
- `AskUserQuestion`, `EnterPlanMode`, `ExitPlanMode`, `ScheduleWakeup`, and `WaitForMcpServers` are never available to any subagent regardless of the `tools` field. Exception: `ExitPlanMode` is available when the parent session runs in `permissionMode: plan`.
- Duplicate `name` values in the same scope: Claude Code silently discards one without warning. Always verify uniqueness before shipping.
@@ -90,7 +92,7 @@ The script is file-by-file no-op — it skips any file that already exists.
### Step 2 — Fill in the agent file(s)
**At plugin/APM scope**, there is exactly one file: `<package-root>/.apm/agents/<name>.agent.md`. Frontmatter carries ONLY `name`, `description`, optionally `model`, and optionally `source_keys` (provenance metadata, not a runtime field — see the template) — never `tools` or the other Claude-only fields listed in Gotchas (ADR-0016). Fill in `name`, `description`, `model`, and the system prompt body per the guidance below; the rest of this step's field-by-field guidance (tools, maxTurns, effort, memory, isolation, disallowedTools, skills, color, initialPrompt, background) is project/user scope only. Skip Step 3 and go to Step 4.
**At plugin/APM scope**, there is exactly one file: `<package-root>/.apm/agents/<name>.agent.md`. Its frontmatter allowlist is the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md`, read from there as data: `name`, `description`, `model`, `source_keys` (provenance metadata, not a runtime field — see the template), and `disallowedTools` for a read-only agent. Never `tools` or the other Claude-only fields listed in Gotchas (ADR-0016). Fill those in plus the system prompt body per the guidance below; the rest of this step's field-by-field guidance is project/user scope only. Skip Step 3 and go to Step 4.
**At project/user scope**, continue below to fill in both provider files — this step covers the Claude Code file (`<name>.md`); Step 3 covers the Copilot file.
@@ -106,13 +108,14 @@ Open the scaffolded Claude Code file. Replace every `FILL IN:` placeholder. **Re
**`tools`** (project/user scope only — never at plugin/APM scope) — restrict to what the agent actually needs. Omit to inherit all tools. Use `Agent(type1,type2)` to limit which subagent types this agent can spawn; omit `Agent` entirely to prevent spawning.
**Optional fields worth considering (project/user scope only — never at plugin/APM scope):**
**`disallowedTools`** (all scopes, including plugin/APM) — denylist applied before `tools` and taking precedence over it; supports `mcp__<server>`, `mcp__<server>__*`, and `mcp__*` globs. `api-reference.md:40` types it `string / list` and `agent-definition.md:71` types it `string[]`, so a YAML list or a delimited string both work; this repo's plugin-scope agents use the comma-separated string (`disallowedTools: Edit, Write, NotebookEdit`) — match that.
**Optional fields worth considering (project/user scope only — never at plugin/APM scope, with the exception of `model`, which is allowed at every scope):**
- `model`: set when this agent needs a different capability tier (`haiku` for fast tasks, `opus` for deep reasoning)
- `maxTurns`: set a cap to prevent runaway agents on bounded tasks
- `effort`: set to `low` for single-lookup tasks, `high` or above for deep reasoning or multi-file analysis — overrides session effort level; omit to inherit
- `memory`: `user`, `project`, or `local` — only when cross-session state is genuinely needed
- `isolation: worktree` — only when the agent modifies files and needs an isolated copy
- `disallowedTools`: space-separated denylist applied before `tools`; supports `mcp__*` glob patterns (e.g. `disallowedTools: mcp__filesystem__*`)
- `skills`: list of skill names preloaded at agent startup — different from the `source_keys` metadata field
- `color`: UI color for the agent tile (`red`, `blue`, `green`, `yellow`, `purple`, `orange`, `pink`, `cyan`)
- `initialPrompt`: auto-submitted as the first turn when this agent activates as the main session thread; only set when this agent is intended for main-thread activation
@@ -152,7 +155,7 @@ Skip this step entirely at plugin/APM scope — there is no separate Copilot fil
**`source_keys`** — add the same top-level list as the CC file when research sources were used. Omit when no research was used.
**Remove all template documentation comments from the YAML frontmatter after filling in required fields** — these are marked with `<!--` and `-->` and must be deleted before shipping.
**Delete the `<!-- -->` template comments from the frontmatter**, as in Step 2.
The system prompt body should match the Claude Code version — the agent's task definition is the same across providers.
@@ -183,37 +186,32 @@ If no research sources are in context, delete `sources.md`.
### Step 5 — Validate and close
Run this checklist before invoking the audit:
Run this checklist before invoking the audit.
**Every file, at every scope:**
- [ ] `name` present and kebab-case; `description` present
- [ ] System prompt body present and non-empty
- [ ] No `FILL IN:` placeholders and no `<!-- -->` template comments remain
**Plugin/APM scope — single file (`<name>.agent.md`):**
- [ ] `name` field present, kebab-case, unique in scope
- [ ] `description` field present and action-first
- [ ] Frontmatter contains ONLY `name`, `description`, and optionally `model` (plus `source_keys` if research-sourced) — no `tools`, `isolation`, `maxTurns`, `effort`, `memory`, `permissionMode`, `disallowedTools`, `skills`, `color`, `initialPrompt`, `background`, `hooks`, or `mcpServers`
- [ ] System prompt body present and non-empty
- [ ] No `FILL IN:` placeholders remain
- [ ] No `<!-- -->` template comments remain in frontmatter
- [ ] `name` unique in scope; `description` action-first
- [ ] Every frontmatter field is in the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md` — the single source of truth, read as data by `validate.sh`. As of 2026-08-14: `name`, `description`, `model`, `source_keys`, `disallowedTools`. Nothing else — in particular no `tools`
- [ ] A read-only agent carries `disallowedTools` **and** says so in the body
**Project/user scope — Claude Code file (`<name>.md`):**
- [ ] `name` field present, kebab-case, unique in scope
- [ ] `description` field present and action-first
- [ ] System prompt body present and non-empty
- [ ] No `FILL IN:` placeholders remain
- [ ] No `<!-- -->` template comments remain in frontmatter
- [ ] `name` unique in scope; `description` action-first
**Project/user scope — Copilot CLI file (`<name>.agent.md`):**
- [ ] File extension is `.agent.md` (not `.md`)
- [ ] `name` field matches the filename stem (e.g. `name: my-agent` in `my-agent.agent.md`)
- [ ] `description` field present
- [ ] `name` matches the filename stem (e.g. `name: my-agent` in `my-agent.agent.md`)
- [ ] No Claude Code-only fields (`maxTurns`, `isolation`, `memory`, `permissionMode`, `effort`, `hooks`, `mcpServers`)
- [ ] System prompt body present and non-empty
- [ ] Body does not exceed 30,000 characters
- [ ] No `<!-- -->` template comments remain in frontmatter
At plugin/APM scope, apply a **minor bump** to the resolved package's `apm.yml` `version` (single manifest, e.g. `1.0.4` → `1.1.0`).
Invoke `kyberforge:agent-audit` on the created file(s) before closing — validates the pair at project/user scope, the single file at plugin/APM scope.
**Commit verification.** Capture `git log --oneline -1` before Step 1 and keep it. Once the audit is clean, run `git add` and `git commit` for the new agent files — do not stop at staging. Then run `git log --oneline -1` again and confirm the hash changed from the one you captured at the start. A non-empty `git diff --stat` is not sufficient proof of completion: staged-but-uncommitted work isn't part of any commit and can be silently lost if the working tree is cleaned up before a commit lands. Only report the agent as done once the hash has actually changed.
**Commit verification.** Once the audit is clean, run `git add` and `git commit` for the new agent files — do not stop at staging. Then confirm `git log --oneline -1` differs from the hash captured before Step 1. A non-empty `git diff --stat` is not proof of completion: staged-but-uncommitted work is part of no commit and can be silently lost if the working tree is cleaned up. Only report the agent as done once the hash has actually changed.
## Improving an existing agent
@@ -223,9 +221,7 @@ Confirm the agent files exist and at least one improvement signal is present in
If no signals: "This skill applies existing signals to an agent. For a blind review, examine the files manually or run a grill session first."
Verify `kyberforge:agent-audit` is available — it ships with the kyberforge plugin and is co-installed with this skill. If unavailable, stop and tell the user to install the kyberforge plugin before continuing.
Capture `git log --oneline -1` now, before making any edits — Step 5 needs it to verify a real commit landed.
Verify `kyberforge:agent-audit` is available, as in the create flow's Prerequisites. Capture `git log --oneline -1` now, before making any edits — Step 5 needs it to verify a real commit landed.
**Partial state (project/user scope only)** — if one provider file exists but not the other, scaffold the missing one (`bash scripts/new-agent.sh <name> <root>`, file-by-file no-op) then continue. Doesn't apply at plugin/APM scope — single file, no partial-pair state.
@@ -248,7 +244,7 @@ Before editing, state which root causes were identified, what evidence supports
### Step 4 — Apply changes
Edit any file the signals point to. Generalize the fix — find the underlying gap, not the specific example that failed. For every sentence you add, ask: "Would the agent get this wrong without it?" A shorter, focused definition consistently outperforms an exhaustive one. For Copilot files, verify no Claude Code-only fields are introduced. For a plugin/APM-scope single file, verify no field beyond `name`, `description`, `model`, and `source_keys` is introduced.
Edit any file the signals point to. Generalize the fix — find the underlying gap, not the specific example that failed. For every sentence you add, ask: "Would the agent get this wrong without it?" A shorter, focused definition consistently outperforms an exhaustive one. For Copilot files, verify no Claude Code-only fields are introduced. For a plugin/APM-scope single file, verify every field is still in the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md`, and that an existing `disallowedTools` fence was not dropped by the edit.
If the edit adds or removes research-sourced content, update `source_keys` in the edited file(s) and the corresponding entry in `sources.md` per Create flow's Step 4.
@@ -260,4 +256,4 @@ At plugin/APM scope, apply a **patch bump** to the resolved package's `apm.yml`
Invoke `kyberforge:agent-audit` on the edited file(s) to confirm no regressions — the pair at project/user scope, the single file at plugin/APM scope.
**Commit verification.** Capture `git log --oneline -1` at the start of Step 1 and keep it. Once the audit is clean, run `git add` and `git commit` for the changed files — do not stop at staging. Then run `git log --oneline -1` again and confirm the hash changed from the one you captured at the start. A non-empty `git diff --stat` is not sufficient proof of completion: staged-but-uncommitted work isn't part of any commit and can be silently lost if the working tree is cleaned up before a commit lands. Only report the improvement as done once the hash has actually changed.
**Commit verification.** Exactly as in the create flow's Step 5, against the hash captured at Step 1: commit the changed files once the audit is clean, and only report the improvement as done once `git log --oneline -1` shows a different hash.

View File

@@ -6,4 +6,4 @@ Annotated agent definition templates copied by `scripts/new-agent.sh` when scaff
- **`claude-code.md`** — Claude Code agent definition template (project/user scope). Includes all supported frontmatter fields (required and optional) with inline guidance comments and `FILL IN:` placeholders.
- **`copilot.agent.md.template`** — Copilot CLI agent definition template (CLI format, project/user scope). Excludes cloud/IDE-only fields (`target`, `user-invocable`, `disable-model-invocation`, `mcp-servers`) and Claude Code-only fields. Uses Copilot tool aliases (`execute`, `read`, `edit`, `search`, `agent`, `web`).
- **`apm-agent.md`** — Vendor-neutral APM agent definition template (plugin/APM scope). Only `name`, `description`, optional `model`, and optional `source_keys` (provenance metadata, not a runtime field) in frontmatter — no `tools` and no Claude-only fields, since `apm compile` copies frontmatter verbatim to both the Claude Code and Copilot CLI targets with no per-target integrator (ADR-0016).
- **`apm-agent.md`** — Vendor-neutral APM agent definition template (plugin/APM scope). Frontmatter is limited to the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md` — the authoritative list, read from there as data by `agent-audit`'s `validate.sh`; this file deliberately does not restate it. No `tools` and no Claude-only knobs, since `apm compile` copies frontmatter verbatim to both the Claude Code and Copilot CLI targets with no per-target integrator; `disallowedTools` is scaffolded as an opt-in comment because a denylist, unlike the `tools` allowlist, survives that copy (ADR-0016 and its 2026-08-14 amendment).

View File

@@ -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

View File

@@ -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

View File

@@ -6,7 +6,7 @@ source_keys: []
## deployment-modes.md
Agent scope hierarchy, precedence rules, and per-scope restrictions. Covers: which fields are silently ignored for plugin agents (Claude Code and Copilot CLI), scoped identifiers for plugin subdirectory agents, cache isolation behaviour, and Copilot CLI path conventions. Loaded conditionally from SKILL.md when the destination is a plugin directory.
Agent scope hierarchy, precedence rules, and per-scope restrictions. Covers: which frontmatter fields a plugin/APM-scope agent may carry and the allowlist-vs-denylist shape rule that decides it (deferring to `agent-audit`'s `references/field-inventory.md` for the list itself), scoped identifiers for plugin subdirectory agents, cache isolation behaviour, and Copilot CLI path conventions. Loaded conditionally from SKILL.md when the destination is a plugin directory.
## scripts.md

View File

@@ -24,9 +24,11 @@ When the same agent `name` appears at multiple scopes, **user scope wins over pr
## Plugin scope restrictions
Plugin/APM agents (`.apm/agents/<name>.agent.md`) carry only `name`, `description`, optionally `model`, and optionally `source_keys` (provenance metadata, not a runtime field — silently ignored by both harnesses) in frontmatter — full stop (see ADR-0016). `apm compile` copies this frontmatter verbatim to both the Claude Code and Copilot CLI compile targets with no per-target integrator: Claude's `tools:` (space-separated string) and Copilot's `tools:` (alias list) are incompatible vocabularies, and Claude-only fields have no Copilot equivalent, so any harness-specific value is guaranteed wrong on at least one target.
Plugin/APM agents (`.apm/agents/<name>.agent.md`) carry only the fields in the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md`. That section is the authoritative list — `agent-audit`'s `validate.sh` reads it from there as data, and it changes — so consult it rather than any restatement of it. `apm compile` copies this frontmatter verbatim to both the Claude Code and Copilot CLI compile targets with no per-target integrator, so a harness-specific value is guaranteed wrong on at least one target (ADR-0016).
This makes the old "silently ignored at plugin scope" framing moot. It's not that `hooks`, `mcpServers`, `permissionMode`, `tools`, `isolation`, `maxTurns`, `effort`, `memory`, `disallowedTools`, `skills`, `color`, `initialPrompt`, or `background` are merely ignored at this scope — they are never written to the file at all. Copy the agent to `.claude/agents/` (project scope) or `~/.claude/agents/` (user scope) to use any of them.
**The rule is about a field's shape, not a fixed roster.** `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 under verbatim copy one value is wrong on one target. It stays out. `disallowedTools` is a **denylist**, and denying by name has no such conflict: a name the other harness does not recognise denies nothing, so the worst case is that the fence is absent there, never that a capability is wrongly granted. That asymmetry is why the denylist is admitted where the allowlist is not (ADR-0016's 2026-08-14 amendment). Claude Code honours it for plugin subagents — `docs/research/docs/claude-code-plugins/agent-definition.md:99` names the three fields plugin agents silently ignore (`hooks`, `mcpServers`, `permissionMode`) and `disallowedTools` is not among them. It is a partial fence: it denies only the tools it names, not `Bash`, which a plugin-scope agent with no `tools` inherits — so state read-only intent in the body too.
This makes the old "silently ignored at plugin scope" framing moot for the excluded fields. It's not that `hooks`, `mcpServers`, `permissionMode`, `tools`, `isolation`, `maxTurns`, `effort`, `memory`, `skills`, `color`, `initialPrompt`, or `background` are merely ignored at this scope — they are never written to the file at all. Copy the agent to `.claude/agents/` (project scope) or `~/.claude/agents/` (user scope) to use any of them.
## Scoped identifiers (Claude Code plugin agents only)