Session state hook events for multi-tab terminal integration
Summary
When running multiple Claude Code sessions in parallel terminal tabs (e.g., Ghostty with 4+ tabs), there's no reliable way to show at-a-glance which session is working, available for input, or blocked on a permission prompt. The information exists internally (mobile and desktop Claude Code show session state), but it's not exposed to terminal integrations via hooks.
Three related gaps
1. Missing session state hook events
Current state: We infer session state from PreToolUse (working), Stop (available), PermissionRequest (needs permission), and Notification (needs attention). This is unreliable:
- No event fires when the agent starts thinking (between
UserPromptSubmitand firstPreToolUse) — gap of 5-15 seconds where the tab looks idle but the agent is processing Stopfires but the state gets overwritten (see #2 below)- Permission prompts and elicitation dialogs need to be inferred from
Notification.notification_type
Request: Explicit session state events that mirror what mobile/desktop Claude Code already shows:
| Event | Fires when | Use case |
|-------|-----------|----------|
| AgentWorking | Agent starts processing (thinking or tool use) | Tab → green "working" |
| AgentAvailable | Agent finished, waiting for user input | Tab → blue "available" |
| AgentNeedsInput | Elicitation dialog or other input request | Tab → red "needs attention" |
| AgentNeedsPermission | Permission prompt shown | Tab → red "needs attention" |
These are the four states visible in mobile/desktop Claude Code. Exposing them as hook events would let terminal integrations (Ghostty, iTerm2, tmux, etc.) show the same status indicators.
2. Claude Code overwrites user-set OSC sequences after Stop
Reproduction:
- Configure a
Stophook that writes OSC 2 (tab title) and OSC 11 (background color) to/dev/tty - Run a Claude Code session in Ghostty
- Send a message, wait for the agent to respond and stop
- The Stop hook fires and writes the new title/bg — confirmed via event logging
- Claude Code's own rendering immediately overwrites the title/bg
Evidence: We built an event logger that confirms Stop fires reliably (within 11 seconds of last tool call). But the tab title and background color set by the Stop hook are immediately clobbered by Claude Code's own OSC 2 writes. The hook runs, the write lands, and then Claude Code overwrites it.
Impact: This makes it impossible to build terminal tab indicators that reflect session state. The "working" state persists visually even after the agent stops, because the hook's "available" write gets overwritten.
Expected behavior: After Stop, Claude Code should either (a) not write OSC 2/11 sequences, or (b) respect user-set values, or (c) provide an official mechanism for terminal integrations to set tab appearance.
3. No external session state query
There's no way to query session state from outside the session:
- No
claude --session-status <id>command - No state file (e.g.,
~/.claude/sessions/{id}/state.json) - No Unix socket or local API
For multi-session setups (4-6 terminal tabs running different agents), the only option is hook-based inference, which is unreliable per #1 and #2 above.
Request: Any of:
- A
claude sessions --statuscommand that shows running sessions and their state - A state file per session that terminal integrations can poll
- A way for hooks to read the authoritative session state
Environment
- Claude Code v2.1.91
- Ghostty terminal with 4-6 tabs, each running a Claude Code session
- macOS Darwin 25.4.0
- Model: Claude Opus 4.6 (1M context)
- Hooks configured in
.claude/settings.jsonfor SessionStart, PreToolUse, PostToolUse, Stop, Notification, SessionEnd, PermissionRequest, UserPromptSubmit
Evidence
Event log from a live session showing the state transitions:
18:30:02 PostToolUse (last tool call finished)
18:30:13 Stop (agent finished — 11s later)
18:31:13 Notification type=idle_prompt msg="Claude is waiting for your input"
^^^ 60 seconds after Stop — timer, not immediate
19:06:25 UserPromptSubmit (user sends message)
^^^ 12 seconds of "thinking" with NO events
19:06:37 PreToolUse tool=Bash (first tool call)
This confirms: Stop fires, idle_prompt is delayed 60s, and there's a 12-second gap after UserPromptSubmit where no state event fires.
Use case
OrdinaryFolk runs a 6:1 agent-to-human development workflow with 4+ parallel Claude Code sessions. Each session runs in a Ghostty tab. The engineer needs to see at a glance which tab is working (leave it alone), available (ready for input), or blocked (needs attention). This is the same information shown in mobile/desktop Claude Code — we just need it exposed for terminal integrations.
Related issues
- #42670 — Scrollback history loss (we also experience this, likely from rapid OSC writes)
- #41136 — Dynamic tab title updates
- #41484 — Ghostty notification support (OSC 9/99)
---
Reporter: Jordan Dea-Mattson (@jordan-of)
Email: jordan@ordinaryfolk.co
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗