Skip to content

Health check cannot distinguish 'waiting for input' from 'idle' or 'finished' #22

Description

@lsk567

Problem

Health state is determined by pane content diff (health.rs:check()): changed → Running, unchanged → Idle. This creates a blind spot: when an agent is blocked waiting for user input (e.g., Claude Code permission prompt, clarification question, tool approval), the pane is static, so health reports Idle — same as "finished" or "genuinely stuck."

The PM prompt (line 62) acknowledges this ambiguity: "idle" = may have finished or need input, but gives PMs no way to distinguish the cases programmatically. A PM checking GET /api/agents/worker-name sees "health": "idle" and has to guess whether to wait, send input, or kill the worker.

Concrete scenarios

  1. Claude Code permission prompt — worker hits Do you want to allow Edit? → pane stops updating → health = idle → PM thinks worker may be done → PM kills or ignores a worker that just needs a y
  2. Agent asks clarification — worker outputs Which database driver should I use? → pane static → idle → PM doesn't realize input is needed
  3. Agent finished — worker outputs Done. → pane static → idle → same signal as cases 1 & 2

Potential fixes

A. Pattern-based input detection

Scan last_output (or last N lines) for known "waiting for input" patterns and add a WaitingForInput health state:

  • Claude Code: Allow, Do you want to, (Y/n), ? (y/N)
  • Generic: lines ending in ?, > , :

Pros: no architectural changes, works with existing pane capture.
Cons: fragile, pattern list needs maintenance per backend, false positives.

B. Structured agent status via sideband file

Each agent writes its status to a known file (e.g., ~/.omar/status/<session>.json) with fields like {"state": "waiting_for_input", "prompt": "Allow Edit?"}. Health checker reads this alongside pane diff.

Pros: precise, no guessing.
Cons: requires agent cooperation (custom tooling or wrapper scripts), doesn't work with unmodified Claude Code/Opencode.

C. Idle duration tiers (use existing config thresholds)

idle_warning (15s) and idle_critical (300s) are already in config but unused. Track time-since-last-change and expose graduated states: RunningIdleStuck. Short idle likely means "waiting for input"; long idle likely means "finished" or "crashed."

Pros: uses existing config, simple to implement, no pattern matching.
Cons: still heuristic — can't distinguish "waiting for input" from "thinking."

D. Combine A + C

Use idle duration tiers AND pattern detection. Short idle + input-like last line → WaitingForInput. Long idle + no input pattern → Stuck. This gives PMs the most actionable signal.

Recommendation: Start with C (idle duration tiers) since the config fields already exist, then layer on A (pattern detection) for higher fidelity. Together they cover most real-world cases without requiring agent-side changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions