Terminal render loop causes unresponsive input in idle session

Resolved 💬 4 comments Opened Mar 31, 2026 by shinglokto 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 ↗