You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Claude subagents show the thread's effort instead of the one their agent definition sets #24143
I searched existing issues and did not find a duplicate.
I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
An agent with shell access can run all of this.
In a project, add an agent definition that sets its own effort:
mkdir -p .claude/agents && cat > .claude/agents/effort-probe.md <<'EOF'---name: effort-probedescription: Replies OK.effort: low---Reply with exactly the word OK.EOF
Start a new Claude thread in that project at xhigh effort. Claude Code loads agent definitions when the session starts.
Send: Call the Agent tool with subagent_type "effort-probe" and the prompt "Reply OK". Do not pass effort.
Read the effort T3 stored for the subagent. ~/.t3/userdata is the state directory of an installed build:
sqlite3 -readonly ~/.t3/userdata/statev2.sqlite "select json_extract(payload_json,'$.title'), json_extract(payload_json,'$.modelSelection') from orchestration_v2_projection_subagents where origin = 'provider_native' order by started_at desc limit 1"
Read the effort the subagent ran at, from its Claude Code transcript:
updateClaudeSubagentNode in apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts (around line 5669 on main @ 66ee628) takes the effort from the Agent call's effort argument, else from the owner subagent, else from the thread. Claude Code applies a definition's effort after the call is written, so T3 never sees it.
A PreToolUse hook that sets effort through updatedInput hits the same path. With a hook that sets high, every request goes out at high and T3 shows xhigh.
Related: #14842 reported this on 0.0.40 and was closed when V2 stopped showing effort. #17496 brought the label back with the thread fallback. Open PR #17042 removes the fallback, but its "Not verified" list includes a live custom-agent run. The steps above are that run.
Confirmed on macOS: T3 Code Nightly 0.1.2-nightly.20261022.3526 (desktop), macOS 26.6.2, Claude Code 2.1.309. The definition case reproduces as described with a user-level definition in ~/.claude/agents/ (Haiku, effort: medium): from a max thread, T3 stores max and the subagent runs at medium. On earlier nightlies with the same fallback (Claude Code 2.1.306–2.1.308), it also went the other way: with the thread at medium, a definition with effort: high showed medium and ran at high.
A third path: Claude Code's maxEffortLevel clamp. Claude Code can also lower the effort after the Agent call is written, and T3 doesn't see that either. This path also applies when the Agent call passes effort explicitly, and #17042 keeps explicit values, so that case would still show the wrong effort after it merges.
Steps, using the same checks as steps 4 and 5 above:
In ~/.claude/settings.json, cap Sonnet at high (these are my exact settings):
Send: Call the Agent tool three times with subagent_type "general-purpose" and the prompt "Reply OK": model "sonnet" without passing effort, model "sonnet" with effort "xhigh", and model "haiku" without passing effort.
Run steps 4 and 5 above for each subagent.
Agent call
T3 stores
Ran at (transcript .effort)
model: "sonnet", effort not passed
max
high
model: "sonnet", effort: "xhigh"
xhigh
high
model: "haiku", effort not passed (control, no cap)
max
max
$CLAUDE_EFFORT inside each subagent matched its transcript (high, high, max). The effortLevel default isn't what lowers it: from a medium thread, the same Sonnet subagent ran at medium (earlier nightly, Claude Code 2.1.306).
The first row is the common one in practice. In my state database, 34 Sonnet general-purpose subagents launched without an effort argument from a max thread over Oct 20–23 show max and ran at high on every turn. #17042 would blank that label; the second row would keep showing xhigh. This is the subagent side of #17110, where T3 doesn't read the maxEffortLevel cap. #17496 notes that Claude Code only publishes the applied effort on Remote Control init frames and in hook inputs, not on the stream T3 reads.
The model starts from the same launch data. It ends up right only because it is later corrected from the subagent's own assistant messages (L8616–L8651). Effort gets no such correction.
Still happens on T3 Code 0.1.7 with Claude Code 2.1.318. Claude Code's new CLAUDE_CODE_SUBAGENT_EFFORT (added in 2.1.316) makes it hit every subagent launched without an effort argument, not only agents with an effort: definition.
CLAUDE_CODE_SUBAGENT_EFFORT sets the effort a subagent runs at when neither the Agent call's effort nor the agent definition's effort sets one. Without it, a subagent inherits the session's effort. Claude Code applies it when it starts the subagent, after the Agent call is written, just as it applies a definition's effort. So T3 sees no effort on the call and falls back to the thread's.
This replaces the PreToolUse hook from the report. That hook did the same thing through updatedInput and ran into the same path.
Steps:
In ~/.claude/settings.json, set "env": { "CLAUDE_CODE_SUBAGENT_EFFORT": "high" }.
Start a Claude Opus 5.5 thread at xhigh.
Send: Call the Agent tool twice with subagent_type "general-purpose" and the prompt "Reply OK": once without passing effort, once with effort "medium".
Run steps 4 and 5 from the report for each subagent.
Agent call
T3 stores
Ran at (transcript .effort)
effort not passed
xhigh
high
effort: "medium" (control)
medium
medium
The parent ran at xhigh on every turn. With the parent thread at high, the same subagent shows high and runs at high, so this only shows up when the thread and the env var differ.
T3 can't take the effort from its own launch settings: Claude Code reads the env var from settings.json, and the agent definition can override it. Dropping the thread fallback, as #17042 does, would show no effort instead of a wrong one for these subagents too. Showing the real level would need the effort Claude Code applied. Claude Code writes it into the subagent's transcript (.effort and perTurnEffort on each assistant entry), but per #17496 not on the stream T3 reads.
Parent thread: Claude Fable 5.2 at Extra High, calling Agent with subagent_type: "opus-medium" and no effort.
Every subagent transcript (subagents/agent-<id>.jsonl) has claude-opus-5-5 with "effort":"medium" on all requests. The .meta.json files have "agentType":"opus-medium".
T3 stores modelSelection: { model: "claude-opus-5-5", options: [{ id: "effort", value: "xhigh" }] } and the Lineage hover card shows Opus 5.5 · Claude · xhigh.
The wrong effort also passes to nested forks. Two of the opus-medium subagents started subagent_type: "fork" children. All six forks ran at medium according to their transcripts, but T3 stored xhigh for them too. They get it through input.owner?.effort, so the fallback's wrong value is passed down a level.
Counts from one thread: 27 Claude subagents, all of which ran at medium. T3 stored xhigh for 23 of them (17 opus-medium and 6 nested forks) and no effort for the other 4.
Same fallback at ClaudeAdapterV2.ts:6867 on the v0.1.8-nightly.20261109.4399 tag, unchanged on main.
Comment drafted by Claude Opus 5.5 in Claude Code, from a T3 Code triage session.
Parent threads: Claude Fable 5.2 and Claude Opus 5.5, calling Agent with subagent_type: "explorer" and no effort.
29 explorer subagents from one day, across 7 threads. Every subagent transcript (subagents/agent-<id>.jsonl) has claude-haiku-5-5 with "effort":"medium" on all requests.
T3 stored the parent thread's effort in modelSelection for each of them:
Parent effort
T3 stored
Transcript
Subagents
xhigh
xhigh
medium
19
low
low
medium
6
high
high
medium
1
medium
medium
medium
3
The label is wrong in both directions. It shows a higher effort than the subagent used when the thread is at xhigh, and a lower one when the thread is at low.
Reported by an AI agent: Claude Fable 5.2 at xhigh effort, running in T3 Code, posted at the account owner's request.
A working fix for the "show the real level" part, in case it helps: syz51#12 (a fork of 0.1.9).
It keeps the current guess as the first label, then replaces it with the effort from the subagent's transcript (<config>/projects/<project>/<session>/subagents/agent-<task_id>.jsonl). The adapter reads it on the subagent's first assistant frame and again when the task settles. The read runs outside the frame pump, with at most 8 tries per subagent. The child thread's model selection gets the same correction.
Because it reads what Claude Code applied, it should cover the definition, CLAUDE_CODE_SUBAGENT_EFFORT, hook and maxEffortLevel paths alike. Checked with an adapter test for both moments (label goes medium → xhigh). I have not yet run it against a live custom agent.
This could sit on top of #17042: no label until the transcript gives one.
Activity
izzat316 commentedon Oct 23, 2026
Confirmed on macOS: T3 Code Nightly 0.1.2-nightly.20261022.3526 (desktop), macOS 26.6.2, Claude Code 2.1.309. The definition case reproduces as described with a user-level definition in
~/.claude/agents/(Haiku,effort: medium): from amaxthread, T3 storesmaxand the subagent runs atmedium. On earlier nightlies with the same fallback (Claude Code 2.1.306–2.1.308), it also went the other way: with the thread atmedium, a definition witheffort: highshowedmediumand ran athigh.A third path: Claude Code's
maxEffortLevelclamp. Claude Code can also lower the effort after the Agent call is written, and T3 doesn't see that either. This path also applies when the Agent call passeseffortexplicitly, and #17042 keeps explicit values, so that case would still show the wrong effort after it merges.Steps, using the same checks as steps 4 and 5 above:
~/.claude/settings.json, cap Sonnet athigh(these are my exact settings):max.Call the Agent tool three times with subagent_type "general-purpose" and the prompt "Reply OK": model "sonnet" without passing effort, model "sonnet" with effort "xhigh", and model "haiku" without passing effort..effort)model: "sonnet",effortnot passedmaxhighmodel: "sonnet",effort: "xhigh"xhighhighmodel: "haiku",effortnot passed (control, no cap)maxmax$CLAUDE_EFFORTinside each subagent matched its transcript (high,high,max). TheeffortLeveldefault isn't what lowers it: from amediumthread, the same Sonnet subagent ran atmedium(earlier nightly, Claude Code 2.1.306).The first row is the common one in practice. In my state database, 34 Sonnet
general-purposesubagents launched without aneffortargument from amaxthread over Oct 20–23 showmaxand ran athighon every turn. #17042 would blank that label; the second row would keep showingxhigh. This is the subagent side of #17110, where T3 doesn't read themaxEffortLevelcap. #17496 notes that Claude Code only publishes the applied effort on Remote Control init frames and in hook inputs, not on the stream T3 reads.Investigated by Claude Opus 5.5 in T3 Code.
kolodziejm commentedon Oct 30, 2026
Still happens on main @
6575ce3, with a user-level agent definition and a model override.~/.claude/agents/explorer.mdsetsmodel: sonnetandeffort: medium.highand callsAgentwithsubagent_type: "explorer"and noeffortargument.claude-sonnet-5-5witheffort: "medium"on every request (perTurnEffort: "medium"too).The model is right and the effort is wrong. The fallback is now at:
t3code/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Lines 6272 to 6277 in 6575ce3
The model starts from the same launch data. It ends up right only because it is later corrected from the subagent's own assistant messages (L8616–L8651). Effort gets no such correction.
Claude Code 2.1.312.
smolpaw commentedon Nov 5, 2026
Still happens on T3 Code 0.1.7 with Claude Code 2.1.318. Claude Code's new
CLAUDE_CODE_SUBAGENT_EFFORT(added in 2.1.316) makes it hit every subagent launched without aneffortargument, not only agents with aneffort:definition.CLAUDE_CODE_SUBAGENT_EFFORTsets the effort a subagent runs at when neither the Agent call'seffortnor the agent definition'seffortsets one. Without it, a subagent inherits the session's effort. Claude Code applies it when it starts the subagent, after the Agent call is written, just as it applies a definition'seffort. So T3 sees noefforton the call and falls back to the thread's.This replaces the PreToolUse hook from the report. That hook did the same thing through
updatedInputand ran into the same path.Steps:
~/.claude/settings.json, set"env": { "CLAUDE_CODE_SUBAGENT_EFFORT": "high" }.xhigh.Call the Agent tool twice with subagent_type "general-purpose" and the prompt "Reply OK": once without passing effort, once with effort "medium"..effort)effortnot passedxhighhigheffort: "medium"(control)mediummediumThe parent ran at
xhighon every turn. With the parent thread athigh, the same subagent showshighand runs athigh, so this only shows up when the thread and the env var differ.The fallback is unchanged on main @
67eebac:t3code/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Lines 6788 to 6793 in 67eebac
T3 can't take the effort from its own launch settings: Claude Code reads the env var from
settings.json, and the agent definition can override it. Dropping the thread fallback, as #17042 does, would show no effort instead of a wrong one for these subagents too. Showing the real level would need the effort Claude Code applied. Claude Code writes it into the subagent's transcript (.effortandperTurnEfforton each assistant entry), but per #17496 not on the stream T3 reads.Investigated by Claude Opus 5.5 in T3 Code.
Collexi-Dev commentedon Nov 10, 2026
Still happens on T3 Code 0.1.8-nightly.20261109.4399 (desktop app on macOS connected to a Linux server, Claude Code 2.1.322).
~/.claude/agents/opus-medium.md:model: opus,effort: medium.Agentwithsubagent_type: "opus-medium"and noeffort.subagents/agent-<id>.jsonl) hasclaude-opus-5-5with"effort":"medium"on all requests. The.meta.jsonfiles have"agentType":"opus-medium".modelSelection: { model: "claude-opus-5-5", options: [{ id: "effort", value: "xhigh" }] }and the Lineage hover card shows Opus 5.5 · Claude · xhigh.The wrong effort also passes to nested forks. Two of the
opus-mediumsubagents startedsubagent_type: "fork"children. All six forks ran atmediumaccording to their transcripts, but T3 storedxhighfor them too. They get it throughinput.owner?.effort, so the fallback's wrong value is passed down a level.Counts from one thread: 27 Claude subagents, all of which ran at
medium. T3 storedxhighfor 23 of them (17opus-mediumand 6 nested forks) and no effort for the other 4.Same fallback at
ClaudeAdapterV2.ts:6867on thev0.1.8-nightly.20261109.4399tag, unchanged onmain.Comment drafted by Claude Opus 5.5 in Claude Code, from a T3 Code triage session.
DaavyC commentedon Nov 10, 2026
Still happens on T3 Code 0.1.9-nightly.20261110.4478 (desktop app on Windows 11, Claude Code 2.1.322).
~/.claude/agents/explorer.md:model: haiku,effort: medium.Agentwithsubagent_type: "explorer"and noeffort.explorersubagents from one day, across 7 threads. Every subagent transcript (subagents/agent-<id>.jsonl) hasclaude-haiku-5-5with"effort":"medium"on all requests.modelSelectionfor each of them:The label is wrong in both directions. It shows a higher effort than the subagent used when the thread is at xhigh, and a lower one when the thread is at low.
Reported by an AI agent: Claude Fable 5.2 at xhigh effort, running in T3 Code, posted at the account owner's request.
syz51 commentedon Nov 11, 2026
A working fix for the "show the real level" part, in case it helps: syz51#12 (a fork of 0.1.9).
It keeps the current guess as the first label, then replaces it with the
effortfrom the subagent's transcript (<config>/projects/<project>/<session>/subagents/agent-<task_id>.jsonl). The adapter reads it on the subagent's first assistant frame and again when the task settles. The read runs outside the frame pump, with at most 8 tries per subagent. The child thread's model selection gets the same correction.Because it reads what Claude Code applied, it should cover the definition,
CLAUDE_CODE_SUBAGENT_EFFORT, hook andmaxEffortLevelpaths alike. Checked with an adapter test for both moments (label goesmedium→xhigh). I have not yet run it against a live custom agent.This could sit on top of #17042: no label until the transcript gives one.
juliusmarminge commentedon Nov 12, 2026
This is the same problem as #17042, so I'm closing it in favour of that one. If it is different, say how and it will be reopened.