[BUG] cct = TUI: permission-gate render-duplication
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When the assistant emits a text response followed by a Bash tool_use that requires user permission to execute, the leading text + Bash command-preview block renders twice in the scrollback. The duplication appears immediately upon emission of the permission prompt — before the user grants permission. Once permission is granted and Bash runs, the actual command output follows the second emission, leaving the leading text + Bash request block visibly doubled in scrollback.
The duplication is silent: no error, no warning, no fallback placeholder. The .jsonl session storage records the turn exactly once (one user prompt + one assistant response containing one text block + one tool_use block + one tool_result after permission is granted). The duplication exists only in the live-rendered scrollback.
Reproducible on demand. In the reporter's session, every observed Bash permission prompt (9+ confirmed instances across multiple turn-transitions) produced an identical duplication. /exit + /resume of the affected session clears the existing visual artifacts in scrollback (re-render walks the .jsonl cleanly), but the next Bash permission prompt in the resumed runtime immediately produces a fresh duplication.
What Should Happen?
The assistant's leading text + Bash tool_use command-preview block should render exactly once in the scrollback, matching what the .jsonl storage records. Granting permission should reveal Bash output below a single emission of the request, not below a duplicated one.
Error Messages/Logs
None — the rendering anomaly is silent. No error path entered, no log line emitted, no fallback placeholder rendered. The silent failure is itself a diagnostic feature: no error-handling code is executing, suggesting the defect is in the normal render-emission code path rather than in error recovery.
Steps to Reproduce
The defect is manufacturable at will via any Bash command requiring permission. In the reporter's setup, every permission-gated Bash tool_use produced the duplication.
- Open a
cct(Claude Code TUI) session in any project (Konsole on Kubuntu 24.04 LTS in this reporter's case; cross-terminal reproducibility not yet tested). - Issue a user prompt that prompts the assistant to perform an action requiring a Bash tool_use needing permission (e.g., "list the contents of /etc").
- The assistant emits a text response (e.g., "Listing /etc now.") followed by a Bash tool_use; the cct UI displays the command-preview block and a permission prompt.
- Observation: the text + Bash request block appears TWICE in the scrollback at the moment the permission prompt fires, before the user has responded to the prompt.
- Grant or deny permission; the second emission persists in scrollback, with the actual command result (if granted) appearing below the second emission.
Reproducibility shape (additional observations from this reporter's investigation):
- Persistent in scrollback: re-scrolling to the affected region in the same session shows the same duplication.
- Not transient: not a flicker; remains in the rendered buffer.
- Cleared by /resume: /exit + /resume re-renders from .jsonl cleanly; the duplication is absent in the re-rendered scrollback. The next Bash permission prompt in the resumed runtime immediately produces a fresh duplication.
- Volume: 9+ captured instances in one session; effectively every permission gate.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
I don't know — defect observed at CCC 2.1.145. The original #64007 cluster's earlier patterns date back several CCC versions, but this specific permission-gate trigger has not been characterized at earlier versions.
Claude Code Version
2.1.145
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
- Terminal: Konsole 23.08.5 (Qt 5.15.13, KDE Frameworks 5.115.0)
- OS: Kubuntu 24.04.3 LTS (KDE Plasma 5.27)
- Hooks active (UserPromptSubmit):
turn_tag_inject.sh(global; injectsMM/DD @ HH:MM:SSturn-anchor as agent reply prefix). Hook activity in jsonl asattachment / hook_successrecords.
Evidence attached
| Item | Source |
|---|---|
| Original 10:51:23 duplication — Konsole buffer paste | forth-incident/forth_rendering-incident.md |
| Original 10:51:23 — 5 screenshots showing progression | forth-incident/Screenshot_20260601_111509.png through ..._111616.png |
| Post-resume clean re-render of 10:51:23 | forth-incident/Screenshot_20260601_115617.png |
| Repeated reproducibility — 9 screenshots of independent permission-gate instances | BASH-trigger/Screenshot_20260601_*.png |
| .jsonl confirming storage-side single emission | Session 80debc44-..., lines 961–964 |
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/c86bf486-c40a-4052-89c6-489f25fbc13c" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/88113c02-036b-4933-b8ee-f068a77af9e9" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/6e0ab499-2d97-4763-a86e-298d400deddf" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/a015170b-e24f-4a97-9dc3-a3a43fd406ab" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/2088286f-5d84-412a-ac7a-74d21a70e46c" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/aa6e2c1f-28c3-4585-8dc9-4f4e0a856bcc" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/57d4ff08-395c-468c-8134-2909e170e594" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/c90959ef-6a7d-4478-b7a7-f1dba833b87e" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/962d2144-c41e-4a7d-8d6e-99d1d0759960" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/f146809a-3115-45cc-8516-0a2be0ff88f0" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/5c8e7bde-f109-4b26-9746-32cc6f3988cb" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/5e3484d1-e39a-40a7-bfcf-fa0dcdfcef62" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/063b832f-9dff-4cb6-895a-7e7593d41b0b" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/2d521289-a5e9-4f01-8e88-2b118d831562" />
<img width="1810" height="1136" alt="Image" src="https://github.com/user-attachments/assets/a0eb2aa3-09bd-4504-859b-46f9858875e7" />
Verbatim .jsonl excerpt (one of the captured instances)
Session: 80debc44-5baa-4cd4-9a03-d9baae6d75a2 (hub project)
Turn: 2026-06-01 14:51:23 UTC = 10:51:23 EDT
// L961 — hook_success record (UserPromptSubmit injecting the turn anchor — single occurrence)
{
"type": "attachment",
"attachment": {
"type": "hook_success",
"hookName": "UserPromptSubmit",
"content": "Turn anchor for this response: 06/01 @ 10:51:23. Begin your reply with this anchor (in place of a Turn number).",
"command": "bash /home/rhys/homelab/scripts/turn_tag_inject.sh",
"durationMs": 145
}
}
// L964 — assistant record with single text + tool_use (one occurrence each in storage)
{
"type": "assistant",
"message": {
"role": "assistant",
"content": [
{"type": "text", "text": "06/01 @ 10:51:23\n\nTwo arcs interleaved. Starting with parallel mechanical checks — bug-pattern scan + estimation/tally."},
{"type": "tool_use", "name": "Bash", "input": {"command": "SESSION_JSONL=...", "description": "Parallel: away_summary bug scan + estimation/tally"}}
]
}
}
The .jsonl records one text block and one tool_use block. The displayed scrollback shows the text + tool_use command-preview block twice. (Visual evidence: bug-reports/forth-incident/forth_rendering-incident.md — verbatim Konsole Paste-Selection of the duplicated region; and bug-reports/forth-incident/Screenshot_20260601_111509.png through Screenshot_20260601_111616.png — sequential captures showing the progression.)
Resume-survival diagnostic
A controlled /exit + /resume of the affected session was run. Result: the captured 10:51:23 duplication is absent in the re-rendered scrollback — only the single (correct) emission appears. Confirmed via post-resume screenshot at bug-reports/forth-incident/Screenshot_20260601_115617.png.
This pinpoints the defect to the live-render code path rather than the .jsonl-driven replay-render code path. The same .jsonl content, read at resume time, produces clean output. The defect occurs at the moment of permission-gate state transition in live rendering.
Relationship to existing #64007 cluster issue
Sibling-defect to the cct render-omission cluster tracked at anthropic/claude-code#64007. Both this issue and #64007's patterns are live-state-only: storage records the content correctly, but the live-render path produces an anomaly (omission in #64007's case; duplication here). Resume-replay produces correct output from the same .jsonl. The follow-up comment on #64007 unifies the cluster under the live-state-only architectural read and references this issue as the standalone Pattern C filing.
Suggested investigation paths
- Permission-gate state-machine emission. The duplication appears at the moment a Bash tool_use enters its "awaiting permission" state. Hypothesis: the live-render path emits the assistant's text + Bash-request block once during initial response streaming, then re-emits the same block when the permission-gate state transitions (possibly when the permission prompt UI is rendered). Two emissions, one storage event.
- Audit the live-render path against the replay-render path. /resume's replay from .jsonl produces clean output for the same content. The replay-render path is the reference for "correct"; the live-render path is the one to audit for the permission-gate transition.
- Cross-terminal stability. Not tested in this report. Reporter can produce captures on xterm, alacritty, gnome-terminal, kitty on request. If the defect is in cct's escape-sequence emission, it will reproduce across terminals; if it's in Konsole's handling, it will not.
- Cross-tool stability. Not tested whether the defect occurs for non-Bash permission-gated tool_uses (e.g., Write tool requiring permission). Reporter can test on request — this would help localize whether the trigger is "Bash permission gate" specifically or "any permission gate."
Reporter context
Same reporter as #64007. Multi-project homelab structure with cross-project agent memory and hook architecture. Reporter can produce additional diagnostic capture on request:
- ANSI raw output via
script-wrapped session - Hook-disabled A/B testing (with the global
turn_tag_inject.shUserPromptSubmit hook off) - Terminal-portability tests against xterm, alacritty, gnome-terminal, kitty
- Cross-tool permission-gate tests (Write, etc.)
- Reproducer scripts deterministically triggering the permission gate
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗