v0.40.0: capture task telemetry via SubagentStop (confirmed root cause)#38
Merged
Conversation
Resolves the multi-release "0 task events" mystery with a clean,
in-session empirical proof — not another guess.
The proof (run this session, fresh 0.39.3, async already reverted):
1. Captured a cutoff timestamp.
2. Dispatched a real subagent via the Agent tool (32947 tokens,
returned). Result: ZERO events after cutoff.
3. In the SAME session, triggered a Read-deny on a large file.
Result: exactly 1 `denied` event written after its cutoff.
4. An unbounded recursive search was blocked by hook-pre-bash
(hooks demonstrably live this session).
So: appendEvent + the hook runtime are healthy (Read-deny wrote),
but PostToolUse:Task produces nothing on a real dispatch. That is
the entire "0 task events" history explained — the parent-side
PostToolUse hook simply does not fire for the dispatch tool on this
Claude Code. async (v0.35.0) was never the cause; the April zeros
predate it. Releases v0.33.1 / v0.39.2 chased the wrong layer.
The fix — SubagentStop:
Claude Code's SubagentStop is the canonical subagent-completion
event (bundle schema: agent_id, agent_type, agent_transcript_path,
last_assistant_message). It fires once per subagent by definition.
New hook-subagent-stop writes the `event:"task"` record from it:
- subagent_type = agent_type (the adoption signal v0.30 needs:
was a subagent used, tp-* or not)
- estTokens = best-effort sum from the transcript usage
(agent_transcript_path), 0 on any failure
- code:"subagent_stop" marks the source so a future revival of
PostToolUse:Task can be deduped, not double-counted
Routing-miss detection (general-purpose where tp-* fit) stays in
the PreToolUse:Task diagnostic, which has the task description
SubagentStop lacks.
Wiring:
- src/hooks/subagent-stop.ts — buildSubagentTaskEvent +
tokensFromTranscript (both pure / injectable, fully tested).
- index.ts case hook-subagent-stop (synchronous — writes telemetry).
- hooks/hooks.json + installer.ts: SubagentStop section, installed
+ uninstalled idempotently alongside the others.
- typo-guard registers hook-subagent-stop.
Verified end-to-end against the built dist: a SubagentStop payload
for tp-pr-reviewer writes event:"task" subagent_type=tp-pr-reviewer
code=subagent_stop.
PostToolUse:Task is KEPT (harmless; carries tokens if CC ever fixes
it; code-marked events let stats dedup).
Tests: 1328/1328 pass (+9 subagent-stop + typo-guard).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves the multi-release "0 task events" mystery with a clean in-session proof.
Proof (fresh 0.39.3 session, async already reverted)
deniedevent written.hook-pre-bashblocked an unbounded search → hooks demonstrably live.So appendEvent + runtime are healthy (Read-deny wrote), but PostToolUse:Task produces nothing on a real dispatch — the entire "0 task events" history explained. async was never the cause (April zeros predate it); v0.33.1 / v0.39.2 chased the wrong layer.
Fix — SubagentStop
CC's canonical subagent-completion event (fires once per subagent). New
hook-subagent-stopwrites theevent:"task"record:subagent_type = agent_type(the adoption signal v0.30 needs)estTokens= best-effort transcript usage sum (0 on failure)code:"subagent_stop"source marker for future dedupRouting-miss detection stays in the PreToolUse:Task diagnostic (it has the description). PostToolUse:Task kept (harmless, carries tokens if CC fixes it).
Wiring
src/hooks/subagent-stop.ts(pure, tested) ·index.js hook-subagent-stop(sync) · hooks.json + installer SubagentStop section (install + uninstall idempotent) · typo-guard.Verified e2e against dist. 1328/1328 tests (+9).