[FEATURE] Emit semantic marks for assistant-message boundaries and Stop-hook verdicts, so superseded drafts can be collapsed
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
Stop hooks are the documented enforcement layer: a hook that returns {"decision":"block"} to enforce output standards (e.g., validating the final message and
demanding a rewrite) makes rewrite loops normal operation, not an edge case. But every draft streams to the terminal before the Stop hook can evaluate it —
the hook needs the complete message, so printing always precedes the verdict. Result: each rejected draft prints in full, followed by the rewrite in full. With
a retry cap, the user reads near-identical walls of text multiple times per gated turn.
No external fix is possible: terminal scrollback cannot be selectively retracted, and the byte stream carries no mark a wrapper or terminal could key on — no
message-boundary sequence, no verdict sequence. The inside has the signal (the Stop event); the outside has silence.
Proposed Solution
Claude Code already serializes session state as semantic escape sequences — OSC 133 prompt zones (#32635, completed), OSC 9;4 progress state, OSC 21337 tab
status. Extend that shipped pattern with two small marks:
- an assistant-message-end mark, and
- a verdict mark when Stop-hook evaluation completes:
accepted, orsuperseded(blocked; rewrite follows).
That single protocol addition lets every surface solve the duplication its own way: terminals with rich integration can dim or fold marked-superseded regions,
transcript views can collapse them, and external tooling can distinguish drafts from final answers. #78260 asks for the VS Code UI treatment of this same
event; marks at the protocol layer would give that issue — and every other surface — a common foundation.
Alternative Solutions
- External PTY wrapper filtering stdout: impossible today — no message-boundary or verdict marks exist in the stream to key on, and scrollback can't be
retroactively edited.
- Buffering output until the Stop verdict: rejected as an ask — it would sacrifice live streaming; this request adds information to the stream rather than
delaying it.
- Per-surface UI fixes (e.g., #78260 for VS Code): works surface-by-surface, but protocol-level marks would give all surfaces one foundation.
- Current workaround: lowering the hook's retry cap and loosening its thresholds — reduces how often duplicates appear, but every enforcement fire still
prints at least one superseded draft.
Priority
Medium - Would be very helpful
Feature Category
Interactive mode (TUI)
Use Case Example
- Register a Stop hook that validates the final assistant message against an output standard and returns
{"decision":"block", "reason":"..."}on violation. - Ask any question whose answer violates the standard.
- The draft streams to the terminal in full → the hook blocks it → the rewrite streams in full. The transcript now shows two (or with retries, three)
near-identical long responses back to back.
- With message-end + verdict marks emitted, my terminal or a transcript tool could fold the superseded drafts automatically, showing only the accepted answer
with the drafts collapsed behind a disclosure.
Additional Context
Related: #78260 (same event, VS Code rendering), #32635 (OSC 133 semantic prompt marks — precedent, shipped), #74408 (same request genre: OSC marks on cwd
change). The OSC 9;4 progress implementation already gates on terminal capability detection and a config flag — the same pattern (capability-detected, opt-in)
would suit these marks.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗