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
Ran a normal Claude Code session with Entire enabled and the Claude Code hooks
installed (entire enable, entire agent add claude-code). The session dispatched
background subagents, and used skills that fan out into further subagents.
"Claude Code exposes task lifecycle events and separate subagent transcripts. Entire
records each task as a nested session and attributes its files and tokens to the parent
session."
So: one record per subagent, with its files and tokens attributed to the parent.
What actually happened
Entire detects the subagents but discards almost all of them. entire session list shows
one session. No nested session, no task record, and no per-subagent token figure is
reachable from any CLI command.
The dropped events log this pair:
{"level":"WARN","msg":"subagent-stop payload missing tool_use_id or session_id — structurally impossible for a well-formed payload","component":"agent.claudecode","agent":"claude-code","has_tool_use_id":false,"has_session_id":true}
{"level":"WARN","msg":"no in-flight marker for completed subagent — foreground dedup, a duplicate event, or a misintegrated agent setting Final without launch markers","component":"lifecycle","agent":"claude-code","tool_use_id":"","agent_id":"a1b2c3d4e5f60718"}
agent_id is present and well formed. It is written to the log and then thrown away.
Is it reproducible?
Every time. A deterministic, offline reproduction is in "Steps to reproduce" below. It
needs no Claude Code session — it drives the installed hooks with synthetic payloads.
Root cause
Claude Code's documented contract (https://code.claude.com/docs/en/hooks) lists tool_use_id as a field of tool events only — PreToolUse, PostToolUse, PostToolUseFailure. SubagentStop does not include it. It does include:
agent_id: Unique identifier for the subagent. Present only when the hook fires inside a
subagent call. agent_type: Agent name (for example, "Explore" or "security-reviewer").
The parser expects it anyway — cmd/entire/cli/agent/claudecode/types.go on main:
cmd/entire/cli/agent/claudecode/lifecycle.go then calls the absence "structurally
impossible for a well-formed payload". Per the Claude Code spec the payload is well formed,
and the expectation is wrong.
Correlation is keyed on that field alone — cmd/entire/cli/lifecycle.go, handleSubagentStopFinal on main:
event.SubagentID (the agent_id) is populated by the parser. It is used only for logging,
and as a fallback from the marker to the event — never as a lookup key.
That branch attributes the failure to "a misintegrated agent setting Final without launch
markers", so the condition currently reads as the agent's fault rather than as a missing
fallback.
Consequence: any subagent Entire did not observe launching is unrecoverable. That is every
subagent spawned by another subagent, and every subagent launched from inside a skill,
because no PreToolUse/PostToolUseAgent hook fires for those in the parent session.
The parser also carries an open tripwire — a Debug log of the raw payload's key names —
with the comment: "Removable once real-payload key sets have been observed and the parse
below is confirmed against them." The reproduction prints that key set. See below.
Impact measured in a real session
One 27-turn Claude Code session using background subagents and fan-out skills. Counts only;
no transcript content.
Item
Count
Distinct agent_id values seen in SubagentStop
34
Correlated by Entire
7
Never correlated — dropped
27
Dropped SubagentStop events in total
36
Task records written
at most 2
Nested sessions in entire session list
0
Checkpoints with checkpoint_type other than session
0
Two further effects there:
Each of the 7 correlated subagents also fired a second, uncorrelated SubagentStop,
producing a spurious warning for work already recorded.
5 of the 7 correlated subagents were then skipped with "no file changes detected, skipping task record". A read-only research subagent
therefore leaves no record at all — not even a token figure.
entire checkpoint explain <id> --json returns keys checkpoint_id, strategy, branch, checkpoints_count, files_touched, session_count, sessions. There is no tasks or task_records key, and session_count is 1 for every checkpoint.
Suggested fix
Correlate on agent_id when tool_use_id is empty. Claude Code always sends it and the
parser already reads it.
Create a task record on SubagentStop when no launch marker exists, instead of
discarding the event. Deduplicate on agent_id so a second event for an already-recorded
subagent is a no-op rather than a warning.
Record subagents that changed no files. A read-only subagent still consumed tokens;
dropping it makes the parent's totals unattributable.
Remove or invert the "structurally impossible for a well-formed payload" tripwire. Per
the Claude Code hooks spec, a SubagentStop without tool_use_id is the normal case.
Deterministic and offline. No Claude Code session required — this drives the installed
hooks directly with synthetic payloads. Every value is made up.
#!/usr/bin/env bashset -euo pipefail
REPO=$(mktemp -d);cd"$REPO"
git init -q && git config user.email t@example.com && git config user.name Toy
echo"print('hi')"> app.py && git add -A && git commit -qm init
entire enable>/dev/null 2>&1||true
entire agent add claude-code >/dev/null 2>&1||true
SID="11111111-2222-3333-4444-555555555555"
TP="$REPO/transcript.jsonl";:>"$TP"
AID="a1b2c3d4e5f60718"
TUID="toolu_01ReproControlAAAAAAAA"hook() { echo"$2"| entire hooks claude-code "$1">/dev/null 2>&1||true; }
hook session-start '{"session_id":"'$SID'","transcript_path":"'$TP'","cwd":"'$REPO'","hook_event_name":"SessionStart","source":"startup"}'
hook user-prompt-submit '{"session_id":"'$SID'","transcript_path":"'$TP'","cwd":"'$REPO'","hook_event_name":"UserPromptSubmit","prompt":"repro"}'# CASE A - payload exactly as Claude Code documents SubagentStop: agent_id, no tool_use_id.
hook subagent-stop '{"session_id":"'$SID'","transcript_path":"'$TP'","cwd":"'$REPO'","permission_mode":"default","hook_event_name":"SubagentStop","agent_id":"'$AID'","agent_type":"Explore","last_assistant_message":"done","stop_hook_active":false}'# CASE B - control: same event, plus tool_use_id and a background launch marker.
hook pre-task '{"session_id":"'$SID'","transcript_path":"'$TP'","cwd":"'$REPO'","hook_event_name":"PreToolUse","tool_name":"Agent","tool_use_id":"'$TUID'","tool_input":{"description":"repro","prompt":"look","subagent_type":"Explore","run_in_background":true}}'
hook post-task '{"session_id":"'$SID'","transcript_path":"'$TP'","cwd":"'$REPO'","hook_event_name":"PostToolUse","tool_name":"Agent","tool_use_id":"'$TUID'","tool_input":{"description":"repro","prompt":"look","subagent_type":"Explore","run_in_background":true},"tool_response":{"agentId":"'$AID'"}}'
hook subagent-stop '{"session_id":"'$SID'","transcript_path":"'$TP'","cwd":"'$REPO'","hook_event_name":"SubagentStop","agent_id":"'$AID'","agent_type":"Explore","tool_use_id":"'$TUID'","last_assistant_message":"done"}'
grep -hE 'subagent started|subagent completed|no in-flight marker|missing tool_use_id' \
.entire/logs/entire.log |
python3 -c "import sys, jsonfor line in sys.stdin: d = json.loads(line) print('%-5s | %-58s | tool_use_id=%r' % (d['level'], d['msg'][:58], d.get('tool_use_id', '-')))"
entire session list | tail -3
Observed output:
WARN | subagent-stop payload missing tool_use_id or session_id — | tool_use_id='-'
WARN | no in-flight marker for completed subagent — foreground de | tool_use_id=''
INFO | subagent started | tool_use_id='toolu_01ReproControlAAAAAAAA'
INFO | subagent completed | tool_use_id='toolu_01ReproControlAAAAAAAA'
1 session
Case A (the spec-shaped payload) is dropped. Case B (same event with tool_use_id added and
a launch marker present) is recorded. The single differing field is tool_use_id.
Entire CLI version
Entire CLI 0.10.3 (Go go1.26.6, linux/amd64)
OS and architecture
Linux 7.0.0-30-generic x86_64 GNU/Linux
Agent
Claude Code
Terminal
No response
Logs / debug output
# Case A, the dropped event. From .entire/logs/entire.log in the reproduction repo.
{"level":"WARN","msg":"subagent-stop payload missing tool_use_id or session_id — structurally impossible for a well-formed payload","component":"agent.claudecode","agent":"claude-code","has_tool_use_id":false,"has_session_id":true}
{"level":"WARN","msg":"no in-flight marker for completed subagent — foreground dedup, a duplicate event, or a misintegrated agent setting Final without launch markers","component":"lifecycle","agent":"claude-code","tool_use_id":"","agent_id":"a1b2c3d4e5f60718"}
# The key set your own Debug tripwire asks for. Re-run the script with ENTIRE_LOG_LEVEL=debug.
{"level":"DEBUG","msg":"subagent-stop payload keys present","component":"agent.claudecode","agent":"claude-code","keys":["agent_id","agent_type","cwd","hook_event_name","last_assistant_message","permission_mode","session_id","stop_hook_active","transcript_path"]}
# No tool_use_id. No alternate spelling of it. Also no agent_transcript_path -- Entire# already degrades to the agent-layout convention for that one, so it is a lesser problem,# but it comes from the same unverified assumption.# Case B, the control. Same event with tool_use_id present and a launch marker stored.
{"level":"INFO","msg":"subagent started","component":"lifecycle","agent":"claude-code","event":"SubagentStart","tool_use_id":"toolu_01ReproControlAAAAAAAA"}
{"level":"INFO","msg":"subagent completed","component":"lifecycle","agent":"claude-code","event":"SubagentEnd","tool_use_id":"toolu_01ReproControlAAAAAAAA","agent_id":"a1b2c3d4e5f60718"}
Additional context
Shell: bash. Not in a git worktree. Not over tmux or SSH. Git hooks and Claude Code hook
config both pass entire doctor.
Searched for duplicates.SubagentStop across open and closed issues and PRs in this
repo returns 21 results. None reports this for Claude Code.
Related, and why the in-flight PR does not cover this. PR #2067
("fix(cursor): correlate subagentStop without subagent_id via task description") addresses
the same class of defect and edits the shared handleLifecycleSubagentEnd path, so it looks
like it would help. It does not. It recovers an empty ToolUseID from a stored pre-task
state file via ResolvePreTaskToolUseID. Every subagent dropped here has no pre-task record
— that is exactly why it was dropped. Case B above, which does have one, already works
today. So #2067 fixes a case that is not broken here and cannot reach the ones that are. The
fallback this needs is agent_id.
What happened?
What I did
Ran a normal Claude Code session with Entire enabled and the Claude Code hooks
installed (
entire enable,entire agent add claude-code). The session dispatchedbackground subagents, and used skills that fan out into further subagents.
What I expected
Per https://docs.entire.io/integrations/claude-code:
So: one record per subagent, with its files and tokens attributed to the parent.
What actually happened
Entire detects the subagents but discards almost all of them.
entire session listshowsone session. No nested session, no task record, and no per-subagent token figure is
reachable from any CLI command.
The dropped events log this pair:
agent_idis present and well formed. It is written to the log and then thrown away.Is it reproducible?
Every time. A deterministic, offline reproduction is in "Steps to reproduce" below. It
needs no Claude Code session — it drives the installed hooks with synthetic payloads.
Root cause
Claude Code's documented contract (https://code.claude.com/docs/en/hooks) lists
tool_use_idas a field of tool events only —PreToolUse,PostToolUse,PostToolUseFailure.SubagentStopdoes not include it. It does include:The parser expects it anyway —
cmd/entire/cli/agent/claudecode/types.goonmain:cmd/entire/cli/agent/claudecode/lifecycle.gothen calls the absence "structurallyimpossible for a well-formed payload". Per the Claude Code spec the payload is well formed,
and the expectation is wrong.
Correlation is keyed on that field alone —
cmd/entire/cli/lifecycle.go,handleSubagentStopFinalonmain:event.SubagentID(theagent_id) is populated by the parser. It is used only for logging,and as a fallback from the marker to the event — never as a lookup key.
That branch attributes the failure to "a misintegrated agent setting Final without launch
markers", so the condition currently reads as the agent's fault rather than as a missing
fallback.
Consequence: any subagent Entire did not observe launching is unrecoverable. That is every
subagent spawned by another subagent, and every subagent launched from inside a skill,
because no
PreToolUse/PostToolUseAgenthook fires for those in the parent session.The parser also carries an open tripwire — a Debug log of the raw payload's key names —
with the comment: "Removable once real-payload key sets have been observed and the parse
below is confirmed against them." The reproduction prints that key set. See below.
Impact measured in a real session
One 27-turn Claude Code session using background subagents and fan-out skills. Counts only;
no transcript content.
agent_idvalues seen inSubagentStopSubagentStopevents in totalentire session listcheckpoint_typeother thansessionTwo further effects there:
SubagentStop,producing a spurious warning for work already recorded.
"no file changes detected, skipping task record". A read-only research subagenttherefore leaves no record at all — not even a token figure.
entire checkpoint explain <id> --jsonreturns keyscheckpoint_id, strategy, branch, checkpoints_count, files_touched, session_count, sessions. There is notasksortask_recordskey, andsession_countis 1 for every checkpoint.Suggested fix
agent_idwhentool_use_idis empty. Claude Code always sends it and theparser already reads it.
SubagentStopwhen no launch marker exists, instead ofdiscarding the event. Deduplicate on
agent_idso a second event for an already-recordedsubagent is a no-op rather than a warning.
dropping it makes the parent's totals unattributable.
the Claude Code hooks spec, a
SubagentStopwithouttool_use_idis the normal case.describes task records under the parent checkpoint, not nested sessions. The docs and
the design do not agree, separately from this bug.
Steps to reproduce
Deterministic and offline. No Claude Code session required — this drives the installed
hooks directly with synthetic payloads. Every value is made up.
Observed output:
Case A (the spec-shaped payload) is dropped. Case B (same event with
tool_use_idadded anda launch marker present) is recorded. The single differing field is
tool_use_id.Entire CLI version
Entire CLI 0.10.3 (Go go1.26.6, linux/amd64)
OS and architecture
Linux 7.0.0-30-generic x86_64 GNU/Linux
Agent
Claude Code
Terminal
No response
Logs / debug output
Additional context
Shell: bash. Not in a git worktree. Not over tmux or SSH. Git hooks and Claude Code hook
config both pass
entire doctor.Searched for duplicates.
SubagentStopacross open and closed issues and PRs in thisrepo returns 21 results. None reports this for Claude Code.
Related, and why the in-flight PR does not cover this. PR #2067
("fix(cursor): correlate subagentStop without subagent_id via task description") addresses
the same class of defect and edits the shared
handleLifecycleSubagentEndpath, so it lookslike it would help. It does not. It recovers an empty
ToolUseIDfrom a stored pre-taskstate file via
ResolvePreTaskToolUseID. Every subagent dropped here has no pre-task record— that is exactly why it was dropped. Case B above, which does have one, already works
today. So #2067 fixes a case that is not broken here and cannot reach the ones that are. The
fallback this needs is
agent_id.Also related:
section states the
SubagentStoppayload "carries ...tool_use_id". The Claude Codedocs and the reproduction above both disagree.