User pushback: live-graph showed only "main" node, no pulses on agents.
Root cause: hook stdin doesn't carry parent_tool_use_id for sub-agent
tool calls — we only get the sub-agent's own session_id, which doesn't
link back to the spawn's tool_use_id.
Sequential heuristic via shared state file:
- agent-event-spawn.sh appends tool_use_id to /tmp/kei-active-children.tsv
- tool-use-event.sh reads the LAST line of that file → uses that
tool_use_id as agent_id for the emitted event
- agent-event-done.sh removes the spawn's line (grep -v + atomic mv)
Verified end-to-end: a code-implementer agent ran 5 Bash calls during
its lifetime — all 5 tool_use events were correctly attributed to the
spawn's tool_use_id. After agent_done, subsequent orchestrator-direct
tool calls correctly fall back to agent_id="main".
Limitation: parallel agents may misattribute. The "most recent live
spawn" heuristic works for single-agent-at-a-time which is the common
case. Parallel spawns share /tmp/kei-active-children.tsv and a sub-
agent's tool calls all attribute to whichever spawn appended last.
Acceptable for v1 demo; proper parent-tool-use-id propagation requires
Claude Code to expose it in sub-agent stdin (upstream change).
The `mv` after `grep -v` runs UNCONDITIONALLY (not gated on grep's
exit code) — grep -v returns 1 when ALL lines match, which would
otherwise leave the stale file in place.
Bypass: `KEI_EVENTS_BYPASS=1` (existing) covers all 3 hooks.
Override path: `KEI_ACTIVE_SPAWNS_FILE=/path/to/file`.
=== STATUS-TRUTH MARKER ===
shipped: functional
stubs: 0
cargo-check: NOT-RUN
behaviour-verified: yes
follow-up-required:
- Parallel-agent attribution would need parent_tool_use_id from
Claude Code sub-agent stdin (not currently exposed).
- Race condition window between spawn append and done remove is
millisecond-scale; observed clean in single-agent demo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>