Files
holocron/docs/adr/0027-a-skill-body-and-its-allowed-tools-must-agree.md
Defame1297 6683da54ac fix(research): restore subagent fan-out, record that a skill body and its allowed-tools must agree
research instructed "spawn one subagent per URL" while its allowed-tools
granted no spawn tool, so it silently degraded to serial fetches. Three
other skills spawn subagents without trouble because they declare no
allowed-tools. The defect was the mismatch, not the spawning.

ADR-0027 records the agreement rule. research drops allowed-tools and
gets its steps 4-5 fan-out and the orchestrator-writes gotcha back
(1.0.1 -> 1.1.0).

Closes #116

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
2026-09-21 07:04:17 +00:00

2.9 KiB

A skill's body and its allowed-tools must agree — a spawning step needs a spawn tool or no list

Status: Accepted (2026-09-21)

plugins/bin/.apm/skills/research/SKILL.md once told the agent to "spawn one subagent per URL" while its allowed-tools granted nothing that spawns. WebFetch was granted, so it never hard-failed: it degraded to serial fetches in the orchestrator's own context, and the "in parallel" wording, the page cap and the "subagents summarise, orchestrator writes" gotcha all quietly stopped meaning anything. The #99 retrofit rewrote steps 4 and 5 as honest serial reads with a real page cap and per-page reduction to notes (#116).

The defect was a mismatch between what the body instructs and what allowed-tools permits. It was not that a skill spawned subagents. Three skills spawn today and work: write-docs (Reader Testing sub-agent), improve-codebase-architecture (Explore, and 3+ parallel sub-agents in references/interface-design.md) and forge (fork and clean-context subagents). None declares allowed-tools, so all inherit every tool, spawning included. research was the only one that both restricted the list and instructed spawning.

Decision: a skill may instruct spawning subagents, provided its allowed-tools agrees with its body. Either:

  • omit allowed-tools, so the skill inherits every tool on every target; or
  • list the spawn tool — only once its per-target name is known, since allowed-tools is a flat list and claude, copilot and codex name it differently.

A step that needs a tool the list does not grant must be rewritten as a step that does not need it. That is what the #99 retrofit did to research, and it stays correct until one of the two options above is taken.

Fan-out is not confined to agents. CONTEXT.md says a plugin-scope agent delegates to skills because it cannot disclose to itself; it does not say skills may not delegate.

Consequence for research

Its fan-out is restored, and allowed-tools is dropped to do it (version 1.0.1 → 1.1.0). That is the first of the two options above; the second is unavailable until the per-target spawn tool names are known.

The cost is stated rather than hidden: research fetches arbitrary web pages, and inheriting every tool widens what an injected page could reach for. Two things bound it. The subagents only read and summarise, and the orchestrator alone writes files, so the write surface is unchanged in intent. And the least-privilege list was never enforceable across targets anyway, since it could not name a spawn tool. If a per-target form of allowed-tools appears, restore a list that includes the spawn tool.

Rejected: banning spawning in skills (contradicted by three working skills, and unsupported by CONTEXT.md), and guessing a per-target spawn tool name in allowed-tools (no per-target form exists, and a wrong guess reproduces the defect silently).