Feature request: reliable session state detection API
Problem
There is no reliable way to programmatically detect whether a Claude Code session is idle, working, or waiting for input from outside the session.
Current workarounds and their limitations
1. Hook-based status tracking (Stop, UserPromptSubmit, Notification hooks writing to status files)
- Tracks state transitions, not current state. If a transition is missed (restart, race condition,
SessionEndcleanup), the state is stuck until the next event fires. SessionEndhook must clean up, but then there's no record that the session existed at all — new sessions that--continuemay not fireSessionStartreliably.- Status files become stale with no self-correction mechanism.
2. Tmux pane scraping (capturing pane content, looking for ❯ prompt, spinner characters, etc.)
- Fragile: depends on TUI rendering details that can change between versions.
- Point-in-time snapshot with race conditions.
- Cannot distinguish all states (e.g., thinking with no visible spinner).
3. JSONL transcript file modification time
- Only tells you when the file was last written, not what state the session is in now.
- Undocumented internal format.
Real-world use case
We run 10-20+ concurrent Claude Code sessions in tmux, managed by an orchestration layer that:
- Queues messages for sessions that are busy
- Delivers messages when sessions become idle
- Shows a dashboard with real-time status of all sessions
- Announces via TTS when sessions finish work
We've spent months battling detection bugs across multiple fallback tiers. The fundamental issue is that Claude Code doesn't expose its internal state.
Proposed solution
A first-party mechanism to query the current state of a running Claude Code session. Some options:
Option A: Status file written by Claude Code itself
Claude Code writes/updates a well-known file (e.g., ~/.claude/sessions/<session-id>/status.json) with its current state: idle, working, waiting_for_permission, waiting_for_input. Updated atomically on every state change. Cleaned up on exit.
Option B: CLI query command
claude --status # current session in this terminal
claude --status --session <id> # specific session
# Output: {"state": "idle", "session_id": "...", "uptime": 3600, ...}
Option C: Unix socket / IPC
Each running session exposes a socket at a well-known path that accepts simple state queries.
Option D: Enhanced hook data
Add a session_state field to all hook event payloads, and/or add a periodic heartbeat hook that fires every N seconds with current state.
Any of these would eliminate the need for fragile tmux scraping and stale-file workarounds.
Context
The Claude Code TUI already knows its own state internally (the statusline shows "Active...", "Running...", idle prompt, etc.). Exposing this externally would unlock reliable multi-session orchestration.
Related issues: #38015 (external interfaces for sessions), #37986 (statusLine refresh), #37629 (lifecycle hook gaps)
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗