aboutsummaryrefslogtreecommitdiff
path: root/claude-rules/subagents.md
blob: e52d90694559f39ee1872e8c172563489c54983c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# Subagents — When, How, and When Not To

Applies to: `**/*`

Subagents exist to protect the main thread's context and parallelize
independent work. They are not free — every spawn pays a prompt-construction
cost and breaks the chain of context from the current conversation. Use them
deliberately, not reflexively.

## Pre-Dispatch Checks

Run these two checks before any spawn. Both can send the work back to the
main thread without the spawn ever happening.

### Availability

The dispatch path assumes a subagent/Agent capability exists in the
environment. If it doesn't — no Agent tool, no spawn mechanism — don't
block. Do the work in the main thread, but preserve the same scope
boundaries the subagent contract would have enforced: bounded scope, the
explicit "do NOT" constraints, and the named output shape. The discipline
is in the contract, not the tool. Hold the task to it even when you're the
one executing, so the work doesn't sprawl.

### Cost

Dispatching isn't free — it pays the prompt-construction cost and breaks
context continuity (see the opening paragraph). For a small task, writing
the full contract (scope, context, constraints, output format) can cost
more than just doing the task inline. When that's the case, do it inline.
The subagent earns its place by absorbing context pollution and running
work in parallel, not on tasks where the handoff exceeds the work itself.
This is the same boundary the "Don't Subagent At All" section and the
"Subagenting trivial work" anti-pattern draw; treat it as an explicit gate
at dispatch time.

Every size-based rule in this file — the cost gate here, "Don't Subagent At
All", the trivial-work anti-pattern — is subject to the isolation override
below.

## Isolation Override — When Size Doesn't Gate

Every size heuristic in this file rests on one assumption: that the main
thread could do the task itself just as well, so the only question is
whether delegating is worth the overhead. When that assumption fails, the
heuristics don't apply, and a five-line task can require a subagent that a
five-hundred-line one wouldn't.

The assumption fails whenever **the main thread is structurally disqualified
from the task** — not slower at it, disqualified. The test: would the main
thread's own context make its answer *less* trustworthy? If holding the
context is what corrupts the judgment, then doing it inline doesn't save the
overhead, it destroys the result. The isolation *is* the deliverable, and
"it's only a small diff" is not an argument against it.

**The standing instance is the pre-commit code review** (`publish` skill,
Step 1). The author cannot review their own change, because a self-review
checks the diff against the author's own model of it and cannot check the
model. Errors that survive a self-review are the ones that were never in the
diff — an inherited scope, an estimated blast radius, a fix correct for the
case in mind and wrong for the one never considered. So that review is
dispatched on *every* commit including a one-line one, and the ~10-tool-call
floor, the single-function rule, and the trivial-work anti-pattern are all
overridden there by design.

Other cases with the same shape: verifying a claim the main thread already
committed to in conversation, and any second opinion where the first opinion
is already in context. If you find yourself reasoning "I already know the
answer, so a subagent is wasteful," check whether already knowing it is the
problem.

This override widens *what* gets dispatched. Scope, constraints, and output
format are still required, and arguably matter more here, since an isolated
agent can't fall back on shared context to fill a gap.

**Field 2 of the Prompt Contract inverts under this override, and the
inversion is the whole point.** Normally field 2 says to paste the relevant
output verbatim and include what you learned in earlier turns. Do that for an
isolation dispatch and you hand over the very model you spawned the agent to
escape — a reviewer given your findings reviews your findings. So for an
isolation dispatch, field 2 is *the artifact under test and the independent
record of what was asked, and nothing else*: the diff, a one-line claim of
what it does, and the ticket or plan where one exists. The conversation, the
rationale, and the dead ends are withheld on purpose.

Keep the requirement source in. A ticket is not your model of the change; it
was written before the work, usually by someone else, and it is the only
thing that can contradict your claim about your own diff.

**The output is a judgment, so the review gate resolves differently.** The
Review-Gate Cadence below says subagent output is a claim to be verified
before moving on, which is right when the deliverable is *work*. When the
deliverable is *a judgment about your work*, verifying it against your own
reading reinstates exactly the bias the dispatch removed. Disagreement goes
to the user to adjudicate, not back to the author's own judgment.

## When to Spawn a Subagent

### Parallel-safe (spawn multiple in parallel)

- **Read-only investigation across independent domains** — "what uses
  function X?", "what are the three logging libraries in this repo?", etc.
  spread across different subsystems.
- **N independent test-file failures** where each is its own diagnosis.
- **Library/API research across unrelated topics** — doc fan-out.
- **Analysis scans over different parts of a codebase** — e.g. C4 diagram
  generation scanning distinct services.

### Sequential-with-review (one at a time, review between)

- **Plan-task execution** where each task may depend on the last.
- **Coupled edits** — related files that must stay in sync (schema + migration
  + seed script).
- **Anything where mid-course correction is likely** — the review gate is
  where course correction happens.

### Never Parallel

- **Concurrent writes to the same files or directories** — race conditions,
  conflicting edits, lost work.
- **Ordered edits where sequence matters** — e.g. add a config flag, then
  read it in code; don't fan these out.

### Don't Subagent At All

Unless the Isolation Override applies — these are efficiency rules, and they
lapse when the main thread's own context is what makes its answer untrustworthy.

- **The target is already known** and the work fits in under ~10 tool calls.
- **Single-function logic** — one Read + one Edit is faster than briefing
  an agent.
- **You can see the answer from context** — don't spawn a researcher for
  something already on screen. (The inverse of this one is the override's
  clearest case: when *having* seen it is the disqualification, dispatch.)

## Prompt Contract

Every Agent spawn must include four fields. Missing any one produces
shallow, generic work:

1. **Scope** — one bounded task, named file or domain. Not "fix the bugs"
   but "find the root cause of the NPE in `order_service.py:process_refund`."
2. **Context** — paste the relevant output, error, or prior finding. The
   subagent cannot see this conversation. If you learned something from an
   earlier turn, include it verbatim; don't paraphrase.
3. **Constraints** — explicit "do NOT" list. "Do not refactor surrounding
   code." "Do not add tests." "Do not touch files outside `src/billing/`."
4. **Output format** — what to return and in what shape. "Report root cause
   + file:line + proposed fix in under 200 words" beats "investigate this."

If you can't fill all four fields, you don't yet understand the task well
enough to delegate it. Do it yourself, or think more before dispatching.

## Context-Pollution Rule

Subagents exist to absorb noise the main thread shouldn't carry. When one
fails or produces unexpected results:

- **Do not retry the task manually in the orchestrator context.** That
  re-imports the exact noise the subagent was meant to contain — failed
  approaches, dead ends, irrelevant exploration.
- **Dispatch a fix subagent** with the failure report as its context
  (paste the subagent's output verbatim). New scope, fresh context.
- **If two fix attempts fail**, stop and surface the problem to the user.
  Don't keep spawning.

The corollary: if you're tempted to "just quickly fix it myself after the
agent failed," you are about to pollute your context. Dispatch.

## Review-Gate Cadence

Subagent output is not verified work — it's a claim about what was done.
Review before moving on:

- **Sequential execution** — review after each task completes. Read the
  diff, run the relevant tests, confirm the claim matches reality (see
  `verification.md`). Then spawn the next task.
- **Parallel execution** — review after every batch of ~3 tasks. Larger
  batches compound bugs; smaller batches make review overhead dominate.
- **Never chain subagents past a failed review.** If the review finds a
  problem, dispatch a fix subagent before continuing the plan.

## Delegation vs Understanding

Subagents execute; they do not understand *for you*. Never write prompts
like:

- "Based on your findings, fix the bug" — synthesis pushed onto the agent
- "Investigate and implement" — scope too broad, no contract

Do the understanding step yourself (read the agent's report, decide the
fix), then dispatch the fix with a specific contract.

## Anti-Patterns

- **Parallel implementation agents on overlapping files** — they will
  conflict. Fan-out is for investigation, not concurrent writes.
- **Broad prompts** — "fix the failing tests" sends the agent exploring;
  "fix the assertion at `test_cart.py:142`" gets a diff.
- **Timeout-tuning to quiet flaky tests** — the flake is usually a race
  condition. Diagnose, don't mask.
- **Retrying a failed subagent task in the orchestrator** — pollutes
  context. Dispatch a fix agent instead.
- **Subagenting trivial work** — one Read + one Edit doesn't need an
  agent; spawn overhead exceeds benefit. Except under the Isolation
  Override, where a one-line diff still gets its own reviewer.
- **Reviewing your own change inline** — the mirror-image failure, and the
  more expensive one. Skipping a dispatch to save overhead on a small diff
  costs a review that could only have come from outside your context.
- **Skipping review between tasks** — compounding bugs are much harder to
  unwind than any single bug.
- **Letting the agent decide scope** — "figure out what needs changing"
  produces sprawling, unfocused work. You decide scope; the agent
  executes it.

## Cross-References

- Completion claims must be verified regardless of who produced them —
  see `verification.md`.
- Testing discipline applies to subagent-produced tests too — see
  `testing.md`.