Repository navigation
Conversation
Claude Code fires Stop before it writes the turn's final assistant row; in interactive sessions often only after the hook exits. A turn that used tools was emitted at Stop without its final answer or last LLM call, and the late row was then dropped as an assistant row with no prompt in front of it. Hold the trailing turn when its last chat row is a tool_result, or when none of its assistant rows carries the end of the Stop payload's last_assistant_message. The next hook run emits it whole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…port A background subagent ends with a SubagentHandback tool call instead of a final text message, so its span's output was empty. Fall back to the call's message. Also document the trailing-turn hold rules in CLAUDE.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dinmukhamedm
approved these changes
Oct 12, 2026
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.
Problem
I tested the plugin end to end against a local Laminar, with headless
claude -psessions and interactive sessions driven throughexpect. Every turn that used a tool lost its final answer:"";LLM Call Nspan was missing;The cause is that Claude Code fires
Stopbefore it writes the turn's final assistant row. A probe hook measured this:claude -p(4/4 runs)The hook saw an assistant row, assumed the turn was complete, and emitted it. The late final row then had no user prompt in front of it, so it was ignored.
Replaying the finished transcript through the same bundle produced correct traces, so the parser was fine and timing was the only problem. Because interactive sessions write the row only after the hook exits, waiting inside the hook can't fix this; I tried a 2 s wait and it timed out.
Fix
splitTrailingIncompleteTurnnow also holds the trailing turn (inpendingTurnRows, as it already does for a prompt with no reply) when either:tool_result: the reply to it hasn't been written yet; orlast_assistant_message. That field is the turn's final text, so this also covers a final message whose thinking row landed but whose text row didn't.The held turn is emitted whole on the next hook run: the next
Stop, orSessionEnd, which never holds. When the row is late, the trace arrives one hook later; in-p, SessionEnd runs right after Stop, so the delay is about a second. Nothing is lost, and the hook adds no wait.Also fixed: empty output on background subagents
A background subagent ends with a
SubagentHandbacktool call instead of a final text message, so theSubagent: …span's output was"". Its output now falls back to the call'smessage.Testing
npm run typecheck, andnpm testwith 61/61 passing. That includes 3 new tests: a turn ending in atool_result, a turn whose payload text isn't written yet, and theSubagentHandbackreport."", noLLM Call 2notes.txthas 2 lines…",LLM Call 2"", noLLM Call 2notes.txthas 2 lines…",LLM Call 2Subagent:output""Subagent:output "14…"CLAUDE.mdnow documents the hold rules.dist/hook.cjsis rebuilt. The version bump is in #9.🤖 Generated with Claude Code
Note
Medium Risk
Changes transcript→turn gating and export timing for every Stop hook; wrong hold logic could delay or duplicate traces, but SessionEnd flush and existing offset/export retry limits blast radius.
Overview
Fixes incomplete Laminar traces when Claude Code’s
Stophook runs before the transcript has the turn’s final assistant row (common after tool use).Trailing-turn hold (
pendingTurnRows):splitTrailingIncompleteTurnno longer treats “any assistant row” as complete. It also holds when the tail ends on atool_result, or when assistant rows don’t yet include the suffix of the Stop payload’slast_assistant_message(wired fromhook.tsasfinalAssistantText). Held rows replay on the next hook run;SessionEndstill flushes everything.Subagent spans:
getSubagentReportsets subagent output from normal assistant text or from aSubagentHandbacktool’smessagewhen background subagents don’t end with text.Docs (
CLAUDE.md), tests (tool-result race, payload text race, handback), anddist/hook.cjsare updated.Reviewed by Cursor Bugbot for commit 561dc75. Bugbot is set up for automated code reviews on this repo. Configure here.