Agent OrchestrationFleet phase 2 — Live operator surface

Agent Runtime Status Authority

Status: Partially implemented. The evidence-arbitration authority is live enough to ship the first operator-visible status pass: PTY output and keystrokes update recency only (the byte-driven flap engine is deleted; sessions start Unknown); the daemon tick is the sole state path — assemble EvidenceSnapshotarbitrateapply_watchdog (Linux-gated) → debounce → publish; the semantic reporter channel (report-event CLI → control socket → gating → AuthorityEvidence), /proc physics, OSC evidence (title / OSC 9;4 progress / OSC 133), and the screen rule-pack engine all feed arbitration. The rule engine carries line_regex/forbids_regex, the prompt-caret region family, the recursive nested all/any/not gate grammar, a RULE_ENGINE_VERSION floor, and semver-bounded validated_versions. Seen/ack, flap/stuck telemetry, status explain / status capture, per-launch reporter installation (merge-safe; Amp installs none), and derived-image asset copying have landed. The remaining work is the live-evidence pass: record whole-tab sessions, turn real frames into fixtures, continue pack rewrites from observed agent behavior, and decide production pack-distribution policy.

Shipped facts

crates/jackin-agent-status/src/lib.rs (and its arbitrate/policy/gating/process/rules children) is the source of truth for pure detection and arbitration. Capsule's crates/jackin-capsule/src/agent_status.rs re-exports that crate and keeps the container reporter installers under hook_installer. This page carries only the stable status contract other roadmap items depend on, the per-runtime detection contract, and the remaining refinements. The prior-art review and the original forward-looking design proposal that shaped the implementation now live in Agent runtime status: prior art and original design proposal — read that page for why the design took this shape, and for the specific list of proposed details that did not survive contact with the real implementation (notably the session.report_agent_state control-message family, and a "hook/API report wins" arbitration precedence — the shipped protocol instead uses a single ReportRuntimeEvent message plus an events-not-states gating layer, and Claude/Codex hooks are identity-only rather than state-authoring, per Decision 0a below).

The built-in runtimes are claude, codex, amp, kimi, and opencode, defined in crates/jackin-core/src/agent.rs; runtime setup centralizes agent-home seeding in crates/jackin-capsule/src/runtime_setup.rs; launch flags live in docker/runtime/entrypoint.sh and are tracked separately by Agent launch flags API. Capsule owns the PTY reader, jackin-term screen state, session lifecycle, the 1Hz ticker, the control socket at /jackin/run/jackin.sock, and in-container setup hooks; host-side code consumes structured state, it does not scrape terminal output through docker exec/docker attach.

Status vocabulary (stable contract)

One consistent status vocabulary across jackin console, jackin hardline, the daemon, Desktop Agent Hub, and scripts. Downstream items (agent attention prompts, autonomous task queue, Desktop Agent Hub, console agent session control, terminal observation automation) consume this surface.

Public statusMeaning
workingActively generating, running tools, processing — not ready for operator input.
blockedWaiting on an operator decision: approval prompt, question, auth prompt, interactive input.
doneReturned to idle after work; the operator has not yet reviewed that pane.
idleIdle and already seen, or a shell pane with no active agent.
unknownNo reliable evidence. Unknown is safer than pretending.
stuckDiagnostic overlay: progress was expected, no reliable transition arrived in time. Never replaces blocked. Shipped today only as daemon clog! telemetry (status.stuck: …); there is no wire-level Stuck state, console glyph, or rate-limited operator affordance yet — that surfacing work belongs to the cross-process event stream tracked by jackin Capsule and Agent attention prompts, not to this item.

Raw detector states are unknown | working | blocked | idle plus per-pane seen; done is derived as raw idle + !seen and is never reported by any detector or reporter. The wire carries the public AgentState (including Unknown); the capsule derives done from seen. Roll-up is blocked > done > working > idle > unknown.

Non-goals (unchanged): probabilistic state estimation, Windows ConPTY, LLM-provider traffic interception, autonomous recovery after stuck (this authority reports and routes attention only), per-tool/per-command granularity, and built-in support for agents beyond the five runtimes (custom roles use the reporter contract and the unknown fallback).

Per-runtime detection (stable contract)

Decision 0a — Claude and Codex hooks are identity-only, not state authorities. Their hooks report session identity (which agent owns the pane, the resumable session id) and refresh freshness/liveness; they do not author working/blocked/idle. State for both comes from the always-on rule pack + OSC evidence + physics watchdog. Completion-class hook events for these two CLIs are unreliable in order and timing (a SubagentStop/recap/away-summary can fire after the turn's Stop and revive an idle pane); because jackin pins each CLI version in the role image, the co-versioned screen pack is a dependable state owner, so identity-only eliminates that failure class. If a future Claude/Codex release ships a documented, ordered, permission-result-complete event surface, revisit and promote to graded state authority.

RuntimeState ownerNotes
Claude CodeRule pack (primary) + OSC 9-family / OSC 9;4 edges + physics watchdog. Hook = identity/freshness only (Decision 0a).No Stop→idle / SubagentStop→idle, so the post-Stop revive hazard can't occur. Reporter is a dumb pipe; installer merges additively.
CodexRule pack (primary) + title-spinner busy/idle + OSC 9 approval edge + physics watchdog. Hook = identity/freshness only.The title-spinner and approval OSC plus the pack own state, removing dependence on Codex's permission-result ordering.
OpenCodeContainer-local plugin (session.status/session.idle/permission.*/tool.execute.*/session.error). Grade: Complete.Cross-checked by rule pack + watchdog. Status can stick after async prompts; idle handlers are fire-and-forget.
AmpScreen rule pack + /proc physics + watchdog. No reporter installed.Amp has no plugins.json node-plugin mechanism (writing one crashes it); a real reporter needs Amp's MCP/toolbox surface — see remaining work.
KimiRule pack (primary) + process evidence + watchdog.The worked example of vendor-independence: the co-versioned screen pack carries Kimi at full quality with no upstream hook.
Custom role agentsRole-authored reporter over the capsule socket (events-not-states contract).unknown is the default; a future role-manifest contract may declare named visible states + ship rule packs.

Runtime setup hard rules (unchanged): assets under /jackin/runtime/agent-status/, state under /jackin/state/agent-status/, socket under /jackin/run/; hook/plugin config merged only into container-local agent homes; nothing written to the host or bind-mounted project trees; drift repaired every launch.

Remaining / deferred work

  • Whole-session evidence collection and replay — current live pack coverage was expanded from operator-provided captures, but the workflow is still too manual. A follow-up should add an opt-in tab/session recording path so contributors can replay exact capsule frames, inspect tab glyph/state transitions, and extract detector fixtures without relying on screenshots.
  • Capture-driven pack completion — continue collecting real blocked/working/idle captures for supported agents and update packs from evidence. The current PR lands basic coverage for Claude, Codex, Amp, Kimi, OpenCode, and Grok, but follow-up PRs should keep treating new live frame shapes as fixtures rather than relying on guessed strings.
  • Runtime pack-vs-CLI co-versioning enforcementproven-blocked, not deferred-by-effort. Agents are bind-mounted (not baked), so the daemon has no runtime source for the running agent's CLI version. validated_versions stays as bounded pack provenance metadata and min_engine_version is the wired floor on the engine axis, but enforcing the pack-vs-CLI window needs a launch-time <agent> --version probe (which this design discourages). Revisit if a non-invasive version source appears.
  • Dirty-session sub-1 Hz faster-recheck cadence — the 700 ms IDLE_HOLD_CAP (the latency contract) is landed and governs at the 1 Hz floor; the sub-1 Hz accelerator needs a one-shot timer armed on PTY damage in the biased daemon select loop and risks render thrash, so it stays deferred with that architectural reason.
  • OSC-9 notify-edge capture and BEL — a plain OSC 9 is currently host-forwarded only, not captured as an OscEvidence field, and BEL needs a jackin-term Bell passthrough variant. The notification attention-edge consumer lives in the unbuilt agent attention prompts item; capturing them now would be written-but-never-read fields. They land with that consumer.
  • A real Amp reporter — Amp falls back to screen + physics today. A graded Amp authority needs its MCP/toolbox surface rather than the (unsupported) OpenCode-style plugin shape.
  • stuck operator surfacing — currently daemon-internal telemetry only (see the vocabulary table above). Promoting it to a console-visible affordance needs the cross-process event stream, which is jackin Capsule Phase 4 / jackin daemon work, not a change to this authority itself.
  • Recursive-gate compile cache — the nested-gate regex leaves compile once at load via CompiledGate; a shared compiled cache keyed across packs is a noted micro-optimization, not a correctness gap.

On this page