Feature: configurable reasoning effort level for subagents
Feature Request
Is your feature request related to a problem?
When using the Agent tool to dispatch subagents, the model parameter allows selecting which model the subagent runs on (opus, sonnet, haiku). However, there is no way to configure the reasoning effort level (low/medium/high) for subagents. Effort level only applies to the parent conversation via /model.
Describe the solution you'd like
Add an optional effort parameter to the Agent tool (and/or subagent YAML frontmatter) that controls the reasoning effort level for the spawned subagent:
# In .claude/agents/my-agent.md frontmatter:
---
model: opus
effort: high
---
Or per-invocation:
{
"subagent_type": "senior-dev",
"model": "opus",
"effort": "high",
"prompt": "..."
}
Use case
I run a 28-agent orchestration system for an algorithmic trading platform:
- Orchestrator: Opus at low effort (fast routing, summarization)
- Code-writing agents (10): Should run at high effort (deep reasoning for correctness)
- Review agents (12): Could run at medium effort (structured analysis)
- Lookup agents (6): Should run at low effort (fast data queries)
Currently all subagents spawn at default effort regardless of task complexity. Being able to set effort per-agent would optimize both cost and quality across the swarm.
Additional context
- The model resolution already has a clean priority chain: env var > invocation param > frontmatter > parent. Effort could follow the same pattern.
- This would pair well with the existing
modelparameter on the Agent tool.
🤖 Generated with Claude Code
16 Comments
+1
+1
+100
Adding empirical evidence supporting this request. I tested the currently-documented
effortfrontmatter field on Claude Code 2.1.128 (Linux) and found it produces zero observable signal, which makes it indistinguishable from a no-op.Setup
Added
effort: highto~/.claude/agents/sdd-explore.md(model: sonnet). Restarted Claude Code. Triggered the sub-agent on a non-trivial codebase exploration task. Repeated witheffort: max. No config errors at load time.Observation surfaces checked — all blind
| Surface | Exposes resolved sub-agent effort? |
|---|---|
|
/status| No ||
/doctor| No ||
~/.claude/projects/<cwd>/<session>/subagents/agent-*.meta.json| No — onlyagentTypeanddescription(80 bytes total) ||
~/.claude/projects/<cwd>/<session>/subagents/agent-*.jsonl| No — keys areagentId, cwd, entrypoint, gitBranch, isSidechain, message, parentUuid, promptId, requestId, sessionId, timestamp, type, userType, uuid, version. Noeffort,thinking, orbudget_tokensanywhere. || Per-turn
usageblock | Nothinking_tokensfield. Onlyinput_tokens, cache_creation_input_tokens, cache_read_input_tokens, output_tokens, service_tier, speed, iterations. |Quantitative scan
Scanned all 835 sub-agent transcripts in my local
~/.claude/projects/:Claude Code appears to strip thinking content from persisted transcripts for user-defined sub-agents, regardless of model or declared
effort. The 2 outliers are internal Claude Code helpers, not user-configurable agents.Why this matters for this feature request
Even if Anthropic implements per-sub-agent effort tomorrow (which #43083 and #39220 are asking for), users will still have no way to verify the resolved configuration is being applied. Two distinct gaps:
/agents inspect <name>,/statusper sub-agent, or restored thinking blocks /thinking_tokensin saved usage stats.Without (2), (1) becomes undebuggable in practice — exactly the situation today with the documented-but-unverifiable
effortfrontmatter field.Related observations
effortas a supported frontmatter field ("Overrides the session effort level"). The docs and the observed behavior disagree, or the application is silent.CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1exists as an undocumented escape hatch that forces effort on sub-agents — implying the default behavior is to NOT propagate frontmatter effort. This matches the empirical scan above.effortLevel, sub-agent frontmatter useseffort, env vars useCLAUDE_CODE_EFFORT_LEVELandCLAUDE_CODE_ALWAYS_ENABLE_EFFORT. Four different names for the same concept across four surfaces.Happy to provide the scan script or run mitmproxy capture against
api.anthropic.com/v1/messagesto confirm whetherthinking.budget_tokensis being included or omitted at the network layer if that would help triage.Status update from v2.1.129: docs already promise this, implementation is broken
Hi @AndrewGoodson — I verified on Claude Code v2.1.129 that this feature is already documented but does not work.
Docs say it exists
The official subagents docs list:
Both behaviors asked for in this issue — explicit YAML override AND session inheritance — are documented as supported.
Implementation: neither path works
Captured outbound HTTP request bodies via
ANTHROPIC_LOG=debug claude --print "..."and compared thethinkingfield:| Test | Setup | Subagent's
thinkingfield ||---|---|---|
| A | Built-in
general-purpose, parent has"effortLevel": "xhigh"insettings.json(should inherit) |undefined|| B | Custom agent in
~/.claude/agents/think-test.mdwith frontmattereffort: xhigh(should override) |undefined|| C (control) | Same parent session running the prompt itself (no Task dispatch) |
[Object ...](set, works) |When
thinkingisundefined, the SDK strips it duringJSON.stringify, so the API receives a body with nothinkingfield at all → no extended thinking server-side. The parent session sets it correctly; the moment it dispatches via Task tool, it's dropped.The frontmatter IS parsed (the binary contains
let Y=H.effort,w=Y!==void 0?Ta(Y):void 0in the YAML loader), but the parsed value never reaches the subagent's API requestthinkingconfig.Token-level corroboration
Same prompt ("smallest n such that n!/(n-3)! > 2^n, show step by step"), captured via
--output-format=stream-json --verbose:output_tokensoutput_tokens(≈ 36%)Both consistent with thinking being completely disabled in the subagent.
Note on related tickets
#25669 was auto-closed by github-actions as duplicate of #25591 (which was also closed as duplicate). Neither was actually shipped. This (#43083) appears to be the only open ticket. Not just a missing feature — a documentation/implementation contradiction.
My Opus 4.7 was looking into this for me and concluded it's a bug: either missing implementation, or docs that overpromise. It wanted me to post this:
Subagent effort: frontmatter ignored on Task-tool spawn but honored on claude -p --agent
Adding empirical evidence to issue #43083. The same subagent
.mdfile actuates extended thinking via the CLI path but not via the in-session Task tool spawn — quantified below.Environment: Claude Code
2.1.146, Linux WSL2, parent session Opus 4.7.Repro: Create
~/.claude/agents/sonnet-low.mdand~/.claude/agents/sonnet-high.mddiffering only in theeffort:value:Run the same prompt four ways. I used a 12-step combinatorics problem (lattice paths (0,0)→(7,5) avoiding two interior points, inclusion-exclusion; answer 286), designed so deep reasoning shows up as more output tokens, not just better quality.
| Dispatch path | low | high | Δ output_tokens |
|---|---|---|---|
| Task tool
subagent_type: sonnet-{low,high}(in-session) | 18,437 total | 18,343 total | −0.5% (noise) || Task tool
subagent_type: opus-{high,xhigh}(intra-model effort) | 27,013 | 27,072 | +0.2% (noise) ||
claude -p --model sonnet --effort {low,high}| 1,451 | 2,181 | +50.3% ||
claude -p --agent sonnet-{low,high}(same.mdfiles) | 1,746 | 2,529 | +44.8% |Run-to-run variance on the in-session path measured 3.6% on tokens / 26% on wall time across same-effort repeats — both Task-tool deltas sit inside that noise band; both
claude -pdeltas are two orders of magnitude beyond it.Confirmed it's not just JSONL stripping. Inspected
~/.claude/projects/{slug}/{sid}/subagents/agent-{id}.jsonldirectly:type:"thinking"content blocks in the assistant messagethinking_*fields in theusageblockservice_tier: "standard"andspeed: "standard"identical across all runsIf thinking were actuated server-side and stripped client-side, billed
output_tokensand wall time would still differ — they don't.What works:
claude -p --agent <name>honors the frontmatter and actuates ~45% more output tokens with ~42% longer wall time on the same prompt. So the wiring exists in the CLI; the Task tool just isn't using it.Docs reference:
code.claude.com/docs/en/sub-agents.md§ Supported frontmatter fields listseffort:as overriding the session effort level. Either the docs should scope the actuation claim to the--agentCLI path, or the Task tool should be wired to honor the same frontmatter on spawn.+1 - waiting too long for this simple feature.
Adding a use case the thread hasn't covered: parallel-fanout orchestration. I run an orchestrator that dispatches many implementation subagents at once via the Agent tool, each in its own worktree. The Agent tool already lets me right-size
modelper dispatch (opus/sonnet/haiku), and that's valuable — but effort is the finer cost/quality lever on the same model, and it's exactly where per-unit control pays off most: in one wave I want Max effort on an ambiguous multi-file refactor and Low on a mechanical single-file edit. Today I can size the model per unit but not the effort.An optional
effortparam on the Agent tool, defaulting to the parent session's effort when omitted (precisely howmodelalready behaves), would close the gap.Confirming the frontmatter workaround others reported:
effort:in an agent.mdis a no-op on the Task-tool spawn path, so there's no usable per-subagent lever right now. +1.+1 with a concrete protocol-level use case, plus the symmetry argument.
Setup: a Rust workspace whose session protocol runs an 8-subagent double review (8 reviewer lenses → remediate → 8 again) on every plan and every code change. The Agent tool already accepts a per-call
modeloverride, so we can vary which model a reviewer runs on — buteffortis session-global, so we cannot express the thing the workflow actually wants:Today the only lever is raising the whole session's effort, which prices every mechanical fire at the verifier's tier. We measured this within our own protocol and ended up retiring
maxeffort entirely (review fan-out substitutes for marginal solo effort at lower cost) — but that conclusion was forced partly because effort is all-or-nothing per session. Role-scoped effort would let cost track where reasoning depth actually matters.Ask (matching this issue): an
effortparameter on the Agent tool call, symmetric with the existingmodelparameter, plus aneffort:field in custom-agent frontmatter with the same precedence rule (call-site param > frontmatter > inherit session).Adding controlled measurements from a multi-agent orchestration setup (one coordinator dispatching ~17 specialist subagents), on Claude Code 2.1.170 (subscription / OAuth). Short version:
model:per-agent works;effort:per-agent does not, and the only dependable lever is session-level.Method: headless
claude -pA/B on one fixed hard reasoning prompt, tools disabled so output tokens ≈ reasoning, and subagent tokens isolated viamodelUsage(parent and subagent run different models).1. The
--effortflag works, so the plumbing exists. Same prompt, Sonnet low→max: 616→5,556 output tokens (9×); Opus 471→2,694 (5.7×). Same model, same correct answer, so the delta is reasoning. Effort is real; it just isn't exposed on the per-agent surfaces.2. Frontmatter
effort:is not honored (run-as--agent). 3 trials/cell, the--effortflag as in-experiment goalposts:| path | model | low→max out_tok | ratio |
|---|---|---|---|
| flag | opus | 337 → 1984 | 5.9× |
| flag | sonnet | 797 → 3002 | 3.8× |
| frontmatter | opus | 808 → 596 | 0.7× |
| frontmatter | sonnet | 1668 → 1676 | 1.0× |
The flag spreads low→max cleanly; the same effort set in the agent file produces no spread and never reaches the flag's max. The file's
model:was honored on every run — onlyeffort:is dropped.3. On Task-tool spawns, session effort dominates (controlled 2×2). A real agent, varied session effort × file effort, 4 trials/cell, subagent tokens isolated (parent opus / subagent sonnet):
| session | file effort | subagent out_tok |
|---|---|---|
| low | low | 8 |
| low | max | 8 |
| max | low | 229 |
| max | max | 569 |
Main effects: session 391 tok vs file 170. At session=low the file effort did nothing (8 vs 8); it only mattered when the session was already max — i.e. no independent per-agent control. Consistent with #64706.
Why this matters (the cost is task-dependent). Max vs low is ~5–9× output tokens on pure reasoning but only ~1.6× on I/O-bound web research (gated by fetches, not thinking). With one session knob, a mixed pipeline is always mis-budgeted: run it high and you overpay 5–9× on mechanical/research steps; run it low and you starve the high-leverage reasoning roles. Per-agent effort — an Agent-tool param plus honored frontmatter, with the same per-model fallback semantics as
/effort— would let orchestrators spend reasoning only where it pays off. +1.Yes please!
+1. Use case: skills that dispatch subagents for different roles in the same workflow — some mechanical (checklist marking), some judgment-heavy (tradeoff classification). Both inherit session effort today; there's no way to encode "this role needs depth, that one doesn't" in the skill itself. An
effortparam on Agent tool, same precedence asmodel, would close this.+1
Every time I come back to Claude code, I run into some silly oversight like this. It's honestly kinda odd how often Claude code feels like a beta product - is anthropic understaffed?
+1
This is still an issue as of Claude Code
2.1.211.