Feature: configurable reasoning effort level for subagents

Open 💬 16 comments Opened Apr 3, 2026 by AndrewGoodson

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 model parameter on the Agent tool.

🤖 Generated with Claude Code

View original on GitHub ↗

16 Comments

jacobcxdev · 3 months ago

+1

mpolomack · 2 months ago

+1

markdiantonio · 2 months ago

+100

GerardoFC8 · 2 months ago

Adding empirical evidence supporting this request. I tested the currently-documented effort frontmatter 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: high to ~/.claude/agents/sdd-explore.md (model: sonnet). Restarted Claude Code. Triggered the sub-agent on a non-trivial codebase exploration task. Repeated with effort: 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 — only agentType and description (80 bytes total) |
| ~/.claude/projects/<cwd>/<session>/subagents/agent-*.jsonl | No — keys are agentId, cwd, entrypoint, gitBranch, isSidechain, message, parentUuid, promptId, requestId, sessionId, timestamp, type, userType, uuid, version. No effort, thinking, or budget_tokens anywhere. |
| Per-turn usage block | No thinking_tokens field. Only input_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/:

835 sub-agent JSONL files
  2 with thinking content blocks > 0  (both internal helpers — agent-acompact-*, agent-aside_question-*)
833 user-defined sub-agents with 0 thinking blocks

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:

  1. Functional (this issue + #39220): per-sub-agent effort needs to actually propagate to the API request.
  2. Observability (complementary): the resolved sub-agent config (effort, model, tools) needs to be inspectable somewhere — /agents inspect <name>, /status per sub-agent, or restored thinking blocks / thinking_tokens in saved usage stats.

Without (2), (1) becomes undebuggable in practice — exactly the situation today with the documented-but-unverifiable effort frontmatter field.

Related observations

  • Docs at https://docs.claude.com/en/docs/claude-code/sub-agents currently list effort as a supported frontmatter field ("Overrides the session effort level"). The docs and the observed behavior disagree, or the application is silent.
  • #47175 confirms CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1 exists 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.
  • Naming inconsistency worth flagging while the team is in this code: settings.json uses effortLevel, sub-agent frontmatter uses effort, env vars use CLAUDE_CODE_EFFORT_LEVEL and CLAUDE_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/messages to confirm whether thinking.budget_tokens is being included or omitted at the network layer if that would help triage.

qqzlqqzlqqzl · 2 months ago

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:

effort | No | Effort level when this subagent is active. Overrides the session effort level. Default: inherits from session. Options: low, medium, high, xhigh, max

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 the thinking field:

| Test | Setup | Subagent's thinking field |
|---|---|---|
| A | Built-in general-purpose, parent has "effortLevel": "xhigh" in settings.json (should inherit) | undefined |
| B | Custom agent in ~/.claude/agents/think-test.md with frontmatter effort: xhigh (should override) | undefined |
| C (control) | Same parent session running the prompt itself (no Task dispatch) | [Object ...] (set, works) |

When thinking is undefined, the SDK strips it during JSON.stringify, so the API receives a body with no thinking field 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 0 in the YAML loader), but the parsed value never reaches the subagent's API request thinking config.

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:

  • Parent session solving it: 839 output_tokens
  • Subagent solving it: 303 output_tokens (≈ 36%)
  • Subagent solve duration: 10.7s vs full session 24.85s

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.

jaredthirsk · 1 month ago

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 .md file 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.md and ~/.claude/agents/sonnet-high.md differing only in the effort: value:

---
name: sonnet-low      # or sonnet-high
model: sonnet
effort: low           # or high
---
Execute the assigned work with [light/careful, deliberate] reasoning.

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 .md files) | 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 -p deltas are two orders of magnitude beyond it.

Confirmed it's not just JSONL stripping. Inspected ~/.claude/projects/{slug}/{sid}/subagents/agent-{id}.jsonl directly:

  • Zero type:"thinking" content blocks in the assistant message
  • Zero thinking_* fields in the usage block
  • service_tier: "standard" and speed: "standard" identical across all runs
  • Total wall time also identical across same-prompt different-effort Task spawns

If thinking were actuated server-side and stripped client-side, billed output_tokens and 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 lists effort: as overriding the session effort level. Either the docs should scope the actuation claim to the --agent CLI path, or the Task tool should be wired to honor the same frontmatter on spawn.

privacyguy123 · 1 month ago

+1 - waiting too long for this simple feature.

aac · 1 month ago

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 model per 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 effort param on the Agent tool, defaulting to the parent session's effort when omitted (precisely how model already behaves), would close the gap.

Confirming the frontmatter workaround others reported: effort: in an agent .md is a no-op on the Task-tool spawn path, so there's no usable per-subagent lever right now. +1.

mlevkov · 1 month ago

+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 model override, so we can vary which model a reviewer runs on — but effort is session-global, so we cannot express the thing the workflow actually wants:

  • the 8 breadth lenses at high (they each have a tight scope; deep effort is wasted), and
  • one or two adversarial verifiers at xhigh (e.g. "re-derive this beacon-multiset oracle from the spec and try to refute it" — the only fires where extra reasoning depth measurably pays).

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 max effort 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 effort parameter on the Agent tool call, symmetric with the existing model parameter, plus an effort: field in custom-agent frontmatter with the same precedence rule (call-site param > frontmatter > inherit session).

elvisripley · 1 month ago

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 -p A/B on one fixed hard reasoning prompt, tools disabled so output tokens ≈ reasoning, and subagent tokens isolated via modelUsage (parent and subagent run different models).

1. The --effort flag 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 --effort flag 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 — only effort: 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.

Djentinga · 21 days ago

Yes please!

wrteam-jay · 21 days ago

+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 effort param on Agent tool, same precedence as model, would close this.

trudslev · 14 days ago

+1

ariccio · 10 days ago

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?

arthurauffray · 4 days ago

+1

creativecreatorormaybenot · 3 hours ago

This is still an issue as of Claude Code 2.1.211.