7.7 KiB
| name | description |
|---|---|
| claude-subagents | Spin up a short-lived headless `claude` sub-instance to grind through a well-scoped, mechanical batch (bulk relabeling, a repetitive find/replace, a mechanical migration) instead of burning your own context on it inline. Use this when a task has a clear, describable recipe and is either big enough to eat your context or long enough that you'd rather not babysit it. Not for judgement-heavy work, anything needing operator back-and-forth, or a task whose blast radius you can't bound up front. |
Ephemeral Sub-Agents via the Claude CLI
claude is on PATH in your container, and a sub-instance you spawn
inherits the same filesystem and credentials you have. This is a
first-class tool for offloading a bounded, mechanical batch - not a hack.
When to use it
- Yes: mechanical batches with a clear recipe (relabel N issues, rewrite a call-site pattern, migrate a config field), especially when the batch would eat your context or take long enough that you'd rather not babysit it turn-by-turn.
- No: judgement-heavy work, anything needing back-and-forth with a human, or a task whose blast radius you can't bound up front.
The spawn command
Put the task recipe in a file and pass it as a path, with a short -p
trigger:
claude --name <memorable> --model <cheaper-than-you> --dangerously-skip-permissions \
--append-system-prompt-file task-prompt.md \
-p "Carry out the task described in your instructions."
--name <memorable>- names the session so you can--resumeit by name for follow-ups.--model <cheaper-than-you>- think about which model the task actually needs; don't spend a bigger model's tokens than your own on mechanical work a cheaper one handles fine. Never use a bigger model than yourself for a sub-agent - if the task needs that much capability, it's not the "mechanical batch" case this skill is for.--dangerously-skip-permissions- required in headless (-p) mode. Without it, tool calls that would normally prompt for approval are auto-denied non-interactively, so the sub-agent silently does nothing. Acceptable here because the sub-instance runs inside your already-sandboxed environment, with your already-scoped credentials, on a bounded task - don't reach for it when the task could touch things outside its intended blast radius.--append-system-prompt-file <path>- read the recipe from a file rather than inlining it in-p(which is bounded byARG_MAX- a long recipe passed as-p "$(cat …)"can blow past it and the exec fails). Keeps Claude Code's default scaffolding and adds your recipe on top.-p "<trigger>"- headless print mode. Keep this short: just tell the sub-agent to act on its file-supplied instructions.
Run it in the background, don't babysit
Wrap the launch in a background bash task and end your turn - your bash-task runner already captures stdout/stderr and hands you a completion pointer, and ending the turn keeps you reachable for other work while the sub-agent grinds.
Prompt hygiene - this is where batches succeed or fail
- Concrete constants, not "figure it out": exact ids, field names, option values, endpoints.
- Critical ordering rules, spelled out - the sub-agent won't infer invariants you don't state.
- Explicit scope + exemptions, plus a fallback rule for ambiguous cases: "leave it as-is where genuinely unclear; do not guess."
- Ask for a report file - per-item results + anything skipped and why, so you can verify without re-deriving.
- Tune on ONE item first, eyeball the result, fix the prompt, then turn it loose on the full batch. A prompt bug replicated across 100 items is 100 cleanups.
Split a big independent batch across parallel subagents
One subagent is a sequential worker — a 50-item batch takes roughly 50 items' worth of wall-clock even though nothing about the recipe forces serialization. If the items are independent (each one touches its own file/issue/row, nothing depends on another item's result) and the batch is big enough that wall-clock matters, chunk it across N subagents running at once instead of handing the whole thing to one.
- Split by natural boundaries, not an arbitrary item count — one subagent per file, per directory, per module, per label, whatever grouping keeps each worker's slice self-contained. A worker that has to coordinate with another worker mid-task isn't actually independent work; re-scope the split until it is.
- Isolate each worker's writes. For a git-based batch, give each
worker its own
git worktree(own working directory, own branch, same underlying repo — cheap, no full reclone) so N workers editing different files never race on the same working tree or index. For a non-git batch (issue relabeling, API calls), independent items don't need filesystem isolation at all — just launch N in parallel. - Launch all N in the background and don't babysit any single one — same as the one-subagent case, just N background bash tasks instead of one. Check on them as a batch, not by polling each individually in a loop.
- Mind the container's memory cap before picking N. Your whole
container shares one
MemoryMax(a few GB by default) with every subagent you spawn and your own process. Aclaudeprocess plus its MCP servers can hold several hundred MB to ~1GB depending on the task; spawning a dozen at once on a small container doesn't just slow things down, it can OOM the whole container — taking your own in-flight turn down with it, not just the subagents. Rule of thumb: 2-4 concurrent workers on a default-sized container; checkfree -h(or ask whoever owns the container's config for itsMemoryMax) before going higher, and chunk a bigger batch into successive waves of that size rather than firing everything at once. - You own the merge. Once all N report done, review + verify each worker's slice (same "don't trust the self-report blind" rule as below), then combine — for a git-based split, that's you merging N branches (or cherry-picking) into one, not each worker pushing/PRing its own slice.
Skip this for a batch small enough to finish in a couple minutes single- threaded — the coordination overhead isn't worth it below that size.
Resume for follow-ups
claude --resume <name> -p "Now run the same procedure over the second batch."
reuses the same session, so the sub-agent keeps every constant and
gotcha it already discovered instead of re-learning the surface from a
cold prompt. Spawn a new --name only for a genuinely unrelated task.
Verify, then report
On completion: read the report file, spot-check a handful of results yourself (don't trust the self-report blind), then summarize. Surface anything the sub-agent left ambiguous or exempted for a human call.
Pitfalls (all observed in practice)
- No
--dangerously-skip-permissions→ headless tool calls denied, the sub-agent burns a run doing nothing. - Using a model bigger than yourself → paying premium cost for mechanical work that didn't need it.
- Skipping the one-item tuning pass → a systematic mistake smeared across the whole batch.
- Spawning fresh instead of
--resumefor a follow-up → throws away all the context the first pass earned. - Baking an unverified assumption into the recipe - if a quick check suggests something "isn't possible" or "doesn't exist," confirm it before writing that conclusion into the prompt; a wrong assumption gets replicated across the whole batch.
- Handing a big independent batch to one subagent instead of splitting it across several in parallel - a 50-item sequential run burns wall- clock the split-by-worktree approach above would've avoided for free.