VS Code extension: Stop-hook-blocked draft and its rewrite both render as duplicate full responses

Status Open
Reported on v2.1.210
Maintainer reply None cached
Activity 1 comment · opened Jul 16, 2026

Environment

  • Claude Code 2.1.210, VS Code native extension
  • macOS (Darwin 25.5.0)

What happens

When a Stop hook returns {"decision": "block", "reason": ...}, the rejected draft has already streamed into the conversation view. Claude then generates the corrected response, and the VS Code extension renders both: two near-identical, full-length message bubbles back to back. The only differences between them are the spots the rewrite fixed, e.g.:

| First bubble (blocked draft) | Second bubble (re-send) |
|---|---|
| get_editor_state — if it connects | get_editor_state. If it connects |
| ⌘⇧P → "Reload Window" | ⌘⇧P, then "Reload Window" |

To a user this reads as the assistant stuttering a duplicate wall of text, every single time the gate fires.

Repro

  1. Register a Stop hook that blocks on some detectable property of last_assistant_message (mine blocks on em dashes / prose length):

``json
{"hooks": {"Stop": [{"hooks": [{"type": "command", "command": "/usr/bin/python3 ~/.claude/hooks/enforce-response-contract.py"}]}]}}
``

  1. In the VS Code extension, elicit a response that violates the rule.
  2. Observe: blocked draft renders in full, followed by the rewritten response in full.

Expected

The transcript legitimately contains both messages, and I understand the draft cannot be un-streamed. This is a request for UI treatment: the extension knows the first message was rejected by a Stop hook, so it could

  • collapse the superseded draft behind a "draft rejected by Stop hook (click to expand)" affordance, or
  • visually mark it (dimmed / struck header) as superseded by the message that follows.

Prior art / not duplicates

  • #39499 asked to suppress the intermediate output at the hook level; closed as not planned. This issue asks for rendering treatment instead, not suppression.
  • #31301 was about a PostToolUse block reason rendering twice; this is about the full draft + rewrite pair.
  • #40029 / #49851 are Stop hooks not firing in the VS Code extension at all; here the hook works correctly.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗