Terminal render loop causes unresponsive input in idle session

Status Closed — not planned
Maintainer reply None cached
Activity 4 comments · opened Mar 31, 2026 · closed Mar 31, 2026

Environment

  • Claude Code: v2.1.87
  • macOS: 26.3.1 (ARM64)
  • Terminal: Ghostty
  • StatusLine: ccstatusline (global install)

Symptom

Session completes work normally, shows the ❯ prompt, but keyboard input becomes completely unresponsive. The session appears idle but the process is actively consuming CPU.

Evidence

1. Terminal write rate (idle session should write 0)

| | Hung Session | Healthy Session |
|--|-------------|-----------------|
| Terminal writes | ~2,082 bytes/sec (continuous) | 0 bytes |
| Total in ~10 min | ~530KB | 0 |

Measured via lsof fd offset on the terminal device — offset increases continuously on the hung session while healthy sessions remain static.

2. CPU escalation

| Time | Hung | Healthy |
|------|------|---------|
| T+0 | 15% | 0.1% |
| T+3m | 20% | 0.1% |
| T+8m | 35.6% | 0.1% |

3. Memory growth

244MB → 287MB over ~10 minutes (healthy session stable).

4. Process thinks it's active

caffeinate -i -t 300 child process is respawned every 5 minutes — the session believes it's still doing work.

5. Stale API connections

2 ESTABLISHED TCP connections to the API remain open. Healthy idle sessions have 0 TCP connections.

Call Stack (sample output)

The main thread's active time (outside kevent64 idle) goes through:

JIT-compiled JS → icu::RuleBasedBreakIterator (Unicode text segmentation)
                → __write_nocancel (terminal write)

The process is continuously re-rendering the terminal UI — running full Unicode text layout and writing the result to the terminal — while the display appears unchanged.

Suspected Trigger

The session had undergone context compression ("Churned for 1m 3s") shortly before the issue appeared. The render loop may be triggered by post-churn UI state that fails to settle.

Diagnostic Commands

Others can verify with:

# Compare terminal write offset (should be static for idle session)
lsof -p <PID> | grep "0u.*ttys"
# Take two samples 3 seconds apart — offset should NOT increase

# CPU check
ps -p <PID> -o pid,%cpu,stat

# Process sample
sample <PID> 3
# Look for icu::RuleBasedBreakIterator and __write_nocancel in call stack

View original on GitHub ↗

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