Mid-turn assistant text persisted as empty thinking blocks (narration) — text lost from transcript JSONL (2.1.170)

Resolved 💬 2 comments Opened Jun 10, 2026 by acighi Closed Jun 14, 2026

Summary

On Claude Code 2.1.170 with claude-fable-5, short assistant text messages emitted between tool calls (mid-turn status updates / "narration") are rendered in the UI but persisted to the session transcript JSONL as empty thinking-type blocks — the text content is lost. Longer substantive texts and turn-final messages persist normally as type:"text" blocks.

Environment

  • Claude Code 2.1.170 (CLI, macOS Darwin 25.4.0)
  • Model: claude-fable-5
  • Transcript: ~/.claude/projects/<project>/<session>.jsonl

What we observed

A mid-turn assistant message (shown on screen) is stored as:

{"type":"assistant","message":{"content":[{"type":"thinking","thinking":"","signature":"CAIS8AIKYwgOGAIqQOtX...QgluYXJyYXRpb24..."}]},...}
  • thinking content is the empty string; the rendered text appears nowhere in the record.
  • The base64 signature metadata contains the string narration (vs thinking for genuine thinking blocks), suggesting these are a distinct "narration" output channel serialized down the thinking path.
  • In one 3-hour session, 5 of 7 short mid-turn messages were lost this way; the 2 that persisted as type:"text" were longer, substantive messages. Turn-final messages always persisted.

Why it matters

  1. Hooks that read the transcript can't see those messages. PreToolUse/Stop hooks that grep assistant text for required markers false-fire: we measured 865 blocks from two marker-checking hooks in one week, a large share caused by markers posted in chat but never persisted. (Local workaround: carry markers in a tool call's description field, which always persists.)
  2. Session logs are lossy as a record. Post-hoc session analysis, handoff generation, and compliance-style review lose all mid-turn assistant commentary.

Expected

Mid-turn assistant text should persist in the transcript with its content (as type:"text", or as a narration block carrying the text), matching what the user saw on screen.

Repro sketch

  1. CC 2.1.170, claude-fable-5, any project with a PreToolUse hook that greps the transcript for a marker string.
  2. Ask for a multi-step task; have the assistant emit a short one-line status message between two tool calls.
  3. grep the session JSONL for that line: absent; the corresponding record is an empty thinking block whose signature metadata decodes to narration.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗