2026-07-17

Claude Code Subagents: A 28-Case Definition Admission Drill

Validate one Claude Code subagent definition, bind its exact task and revision, allow three read tools, and reject stale or untraceable handoffs.

Claude Code Subagents: A 28-Case Definition Admission Drill cover illustration

A Claude Code subagent definition can look disciplined and still be useless in practice. The name may not route, the description may never say when to delegate, a read-only role may quietly expose Edit, or the returned report may not identify the revision it inspected. None of those failures requires a model mistake. They are contract mistakes.

I built a deterministic 28-case admission drill around one project-scoped Claude Code subagent: an API-contract scout that may read, grep, and glob, but cannot edit. The local probe checked the definition, one bound invocation, tool use, and the final handoff. All 28 actual decisions matched the expected decisions. It did not launch Claude Code or judge the quality of a finding. That narrower result is the point: reject a malformed worker before paying for its opinion.

A role file can fail before Claude ever sees it

Anthropic describes subagents as specialized assistants that run in separate context windows with their own prompts, tool access, and permissions. Claude uses the description to decide when delegation fits. Current Claude Code also ships built-in Explore, Plan, and general-purpose workers, while custom definitions live in Markdown files with YAML frontmatter.

That feature set creates two different layers. Claude Code loads and runs the subagent. An operator still needs to decide whether a particular definition is acceptable for a repository. The drill implements the second layer as a small admission wrapper. It is deliberately stricter than the product schema.

The role name describes intent. The tool list and run manifest define the boundary.

The tested role is intentionally boring: one repeated review question, three read tools, a visible stopping rule, and an evidence-shaped return packet. A broad “senior engineer” persona would add prose without improving admission.

One parent coding session routing a narrow repository question into an isolated specialist workspace
The useful isolation boundary is one bounded question with one accountable parent, not an extra personality.

Requirements: six fields before admission

The local definition contract has eight fields: name, description, tools, model, scope, mode, output contract, and stop condition. Only some belong to Claude Code frontmatter. The rest are operating rules for this repository and can live in the prompt body or in an external validator.

---
name: api-contract-scout
description: Finds API contract drift. Use after request or response types change.
tools: Read, Grep, Glob
model: sonnet
---

Read only the admitted paths.
Return path, line, evidence, and a parent verification command.
If the current diff or generated schema is missing, stop and name it.

The exact model is not the interesting control. The description has to contain both the job and its trigger. The tool set has to be unique and drawn from the local read allowlist. The output and stop rules have to be concrete enough for a parent to test.

Seven definition cases exercised those decisions. One project definition passed. Six were rejected for a malformed name, vague description, write tool, duplicate tool, unknown scope, or missing stop condition. This does not mean Claude Code itself would reject every one of those files. It means our workflow refuses to launch them.

Local policy should be explicit about being local.

Scope is deployment, not decoration

Claude Code supports managed, session, project, user, and plugin sources for subagents, with documented precedence when names collide. A project definition under .claude/agents/ can travel with the repository. A user definition under ~/.claude/agents/ follows one developer. The current documentation also notes that a newly created user agents directory may require a restart before an existing session discovers it.

For a shared API-contract rule, project scope is the least surprising choice. Teammates can review the definition beside the code it governs. Personal exploration habits belong in user scope. Organization-wide prohibitions belong in managed settings, not in a friendly sentence inside the worker prompt.

Duplicate names deserve operational attention. Claude Code documents precedence between scopes and, for nested project directories, selects the definition nearest the working directory. Inside the same agents tree, duplicate names can depend on filesystem read order. The safe convention is simpler than memorizing every tie-break: keep names unique, and confirm the active setting source before trusting a run.

Bind each invocation to one task and revision

A good definition does not make every invocation good. The run in the drill binds seven values:

  • the exact subagent name;
  • the current head identifier;
  • a SHA-256 digest of the task text;
  • one or more unique target paths;
  • an explicit exclusion list;
  • mutate: false;
  • a stopping condition for this run.

Eight invocation cases produced one admission. The other seven caught the wrong worker, a stale head, a changed task digest, an empty target list, duplicate targets, a mutation request, and an absent stopping rule. The task digest matters more than it first appears. Without it, a report can be attached to a prompt that was edited after the worker started.

{
  "agentName": "api-contract-scout",
  "head": "c0ffee12",
  "taskSha256": "abababab...abababab",
  "targetPaths": [
    "src/api/invoices.ts",
    "src/client/invoices.ts"
  ],
  "exclusions": ["generated/**"],
  "mutate": false,
  "stopCondition": "Stop after five findings or a missing schema."
}

This is a lease on specific evidence, not a permanent delegation.

Failure modes: a read-only role with write tools

Claude Code permission rules are enforced by the application rather than by the model. The documented evaluation order is deny, then ask, then allow. A broad deny therefore wins over a narrower allow. Bare tool denies can remove a tool from the model's context entirely; scoped rules can leave the tool visible while blocking matching calls.

The drill's tool gate is smaller. Read, Grep, and Glob returned ALLOW_READ. Edit and Bash returned DENY_TOOL. Five of five decisions matched.

A prompt that says “do not edit” is still worth keeping because it explains the role. It is not a substitute for withholding edit capability. Likewise, a reviewer does not need a shell merely because shells are common in coding sessions. Start with the three inputs the job actually consumes; add another tool only after a named case proves why it belongs.

Permissions also inherit context. Built-in subagents inherit the parent conversation's permissions with added restrictions, and custom subagents can carry focused controls. That makes the parent's starting mode part of the design. A child cannot manufacture a safer parent.

Reject a handoff you cannot review

The last gate evaluates the packet returned to the parent. A complete finding needs a supported kind, path, positive line number, evidence, and a verification action. The packet also repeats the agent name and head. A blocked packet is valid only when it names the missing input.

{
  "agentName": "api-contract-scout",
  "head": "c0ffee12",
  "status": "complete",
  "findings": [{
    "kind": "contract-drift",
    "path": "src/client/invoices.ts",
    "line": 47,
    "evidence": "Client still reads invoice.total_cents.",
    "verification": "Run the invoice contract test."
  }],
  "missingInputs": []
}

Eight packet cases accepted two handoffs: one complete finding and one honest blocker. A stale head, six-finding overflow, line zero, thin evidence, a blocker with no missing input, and an unsupported finding kind were rejected. The five-finding ceiling is a local review-budget choice. It forces prioritization and keeps the parent from receiving a repository inventory disguised as a decision.

A developer checking a compact evidence packet returned from an isolated code review specialist
A subagent result becomes useful when the parent can open the cited path, inspect the evidence, and rerun the smallest check.

Blocked is not failed. Guessing because a schema is absent is failed.

Testing: 28 matches, four different gates

GateCasesMatchedAdmitted or accepted
Definition771
Invocation881
Tool use553
Handoff882
Total28287 gate decisions

The fixture SHA-256 is dc8bca63289e8c3f3b907edd425e4c1ee0341046d171b0e7665c3d5dd801cf57. Recording it binds this result to the exact test inputs. Change one case and the evidence gets a new identity.

The result does not show that the scout finds real contract drift. No Claude Code subagent ran. No model was called, no repository or diff was opened, no search tool executed, and no permission prompt or hook fired. The probe touched no secret, network service, edit, commit, merge, release, or deployment. It measures deterministic admission behavior only—not context saved, token cost, latency, recall, false positives, or production safety.

This is plumbing evidence, not an AI benchmark.

When a subagent is the wrong primitive

Anthropic positions subagents inside one Claude Code session. They are useful when a side task would flood the main context with searches, logs, or file contents that the parent does not need to retain. They are a poor fit when the task is a tiny lookup, when several workers must negotiate directly, or when work must continue as a durable service after the session closes.

Parallel writing deserves extra skepticism. If two workers can edit the same path, tool permissions do not solve the merge problem. Use isolated worktrees or serialize ownership. For a read-only scout, the cleaner answer is to keep mutation out of the phase entirely. The parent can verify the packet and start a separate implementation task.

Subagents also consume their own model and tool work. Separate context is not free context. Route a repeated, noisy, bounded question to a specialist; keep one-off questions in the parent.

Keep the stable contract beside the repository

The durable pieces belong under version control: the project subagent file, a sample invocation manifest, the packet schema, and the 28-case fixture. Keep volatile head identifiers and task digests out of the role file; those belong to each run. Keep organization-wide permission denies in managed settings where a local prompt cannot weaken them.

Before relying on the role, confirm four things:

  1. Claude Code loaded the intended definition and setting sources.
  2. The invocation binds the current head, exact task, paths, exclusions, and stop rule.
  3. The available tools match the read-only claim.
  4. The parent rejects stale, oversized, or untraceable packets before acting.

That is enough structure to make a subagent boring in the best way. It receives one narrow question, returns inspectable evidence, and cannot quietly turn review into implementation. The parent retains the product goal and the decision about what changes.

Primary sources