Expose Claude Code harness process-state to a per-instance state file
Problem
External tooling that monitors multiple Claude Code instances cannot distinguish "agent is waiting for user input" from "agent is stuck in a loop or hung." Both produce identical external signals — silence on stdout, no JSONL mtime updates. The harness internally knows its state (showing a permission prompt, idle at REPL, executing a tool, generating a response), but that state is not exposed.
For a single interactive user, this distinction is moot — they see the prompt. For multi-instance orchestration (fleet supervision, automated monitoring, idle-detection layers), it produces a high-frequency false-positive class: monitoring infrastructure flags instances as "stuck" when they are actually waiting on the user to approve a permission prompt.
Proposed solution
Have the Claude Code harness write its current state to a small file on a state-change cadence. Suggested location: alongside the existing .claude/ config, or a well-known per-project state directory.
Example schema:
{
"state": "awaiting_permission",
"tool": "Bash",
"tool_args_summary": "git push origin main",
"since": "2026-05-24T08:30:00Z",
"pid": 12345
}
State values (suggested):
awaiting_permission— permission prompt shown, waiting for Allow/Denyidle_repl— at the REPL, waiting for user inputexecuting_tool— tool call in progress (tool name intoolfield)generating— model is generating a responseawaiting_user_question— model has asked the user a question viaAskUserQuestion
The file should be written atomically (write-then-rename) on every state transition. Stale files (process no longer running) should be detectable via the embedded pid.
Use case
I run an orchestrated set of ~13 Claude Code instances, each with its own working directory. A separate monitoring instance polls the set looking for stuck or hung instances. Currently the only external signals available are:
- Transcript JSONL mtime (updates only when a turn completes)
- A custom append-only log emitted at turn boundaries
- Process existence (PID check)
None of these can distinguish a permission-prompted instance (correctly idle) from a hung instance (incorrectly idle). The current mitigation is a sticky-false-positive flag that suppresses alerts after the user acknowledges the false positive once — this is a patch on the symptom. Process-state externalization resolves the class at root.
Backward compatibility
Pure additive feature. New file appears in a well-known location; absent the feature, downstream tooling falls back to existing signals. No breaking change.
Adjacent considerations
- A subscribe/notify path (named pipe, websocket, or fsnotify-watchable file) would be ideal for low-latency probes, but a plain file polled at 1-2s cadence is sufficient for the use case.
- If a single state file is too invasive, an opt-in flag (
CLAUDE_CODE_EXPORT_STATE=1env var orsettings.jsonfield) would unblock the use case without affecting users who don't need it.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗