# ADR 022: Operator Interface
**Status:** accepted
**Date:** 2026-05-28
**Participants:** Claude (Opus 4.7), Codex (gpt-5.5 xhigh)
**Operator gate:** Zevs
## Context
Phase 1 defined the message protocol. Phase 2 defined workflow modes. ADR 020 defined mode switching, and ADR 021 defined conflict resolution. The operator still needs an interface pattern that makes multi-agent state easy to inspect without reading every transcript line.
The operator interface must answer:
- What status format lets Zevs intervene quickly?
- Should status updates be event-driven, periodic, or both?
- What fields are needed when agents need input?
- How can agents avoid flooding the pane while still avoiding silence during long work?
- How should status work across one active session vs several parallel sessions?
- Who summarizes when multiple agents are active?
- What artifact preserves end-of-session state?
This ADR defines the operator-facing status and summary convention. Transport audit guarantees remain in ADR 023.
## Options considered
### Option A: Event-driven compact dashboard in the pane
The operator interface is an event-driven compact dashboard, not a continuous transcript.
Agents post status at:
- Phase start.
- Phase end.
- Mode switch.
- Blocker or escalation.
- Decision gate.
- Before long-running work.
Minimum fields:
- `phase`
- `mode`
- `artifact` or `ref`
- `status`
- `completed_since_last_update`
- `in_progress`
- `next_action`
- `blockers_or_asks`
- `decisions_needed_from_Zevs`
- `risk_or_residual_uncertainty`
- `expected_wait`
For multi-agent work, one lead agent summarizes so Zevs does not receive duplicate status messages.
Strengths:
- Simple and immediately usable in the live pane.
- Keeps messages shorter than full transcript narration.
- Gives Zevs enough fields to intervene quickly.
Trade-offs:
- Push-only; Zevs must wait for the next update unless he asks informally.
- No durable rolling status file.
- Lead-agent selection is underspecified.
- Long-running work can appear stuck between event updates.
### Option B: Multi-surface status with push/pull and intervention metadata
Use multiple operator-facing surfaces:
- Live in-pane message stream.
- Rolling status file at `outputs/sessions/<session_id>/status.md`, keeping the last N events, default N=10.
- Optional aggregate dashboard at `outputs/dashboard.md` when two or more sessions are active.
Cadence triggers:
- Phase start.
- Phase end.
- Mode switch.
- Blocker or escalation.
- Decision gate.
- Before long-running work.
- Heartbeat during long-running work.
Anti-spam rules:
- Suppress updates when nothing changed.
- Rate-limit status messages to one per minute per agent per session.
Intervention fields:
- `intervention_urgency`: `now | soon | when-convenient`
- `intervention_type`: `decision | context | permission | acknowledgment | stop-signal`
- `consequence_if_intervened`
- `consequence_if_not`
- `rollback_cost`
- `sticky_or_transient`
Push and pull:
- Agents push status on trigger events.
- Zevs can request status with a `MODE: status?` request, and an active agent responds with the current dashboard slice.
Lead agent:
- First agent to enter the mode is lead by default.
- Other agents delegate summarization to lead.
- Lead can be reassigned by explicit handoff.
End-of-session summary:
- Running status is event-driven.
- End-of-session summary is a separate comprehensive artifact at `outputs/sessions/<session_id>/summary.md`.
Strengths:
- Supports live monitoring, scannable files, and retrospective summaries.
- Reduces both ghosting and flooding.
- Makes intervention asks actionable.
- Gives Zevs a pull mechanism.
- Prevents duplicate summaries.
Trade-offs:
- Adds file paths and artifact conventions.
- More fields to classify.
- Heartbeat and rate-limit rules require discipline.
- End-of-session summaries add another artifact.
### Option C: Scaled operator interface with live status, rolling summaries, and pull requests
Combine Option A's compact event-driven dashboard with Option B's multi-surface model, heartbeat, anti-spam rules, intervention fields, push/pull status, lead-agent selection, and end-of-session summary. Scale by rigor level.
Rigor levels:
- `quick`: in-pane status only; no separate files unless a blocker or decision gate appears.
- `standard`: in-pane status plus rolling status file for shared work.
- `deep`: standard plus aggregate dashboard for parallel sessions and end-of-session summary.
Default:
- Use `standard` for shared ADRs, skills, tools, and cross-agent workflow.
- Use `quick` for local single-agent work.
- Use `deep` for multi-session, long-running, high-impact, or operator-attention-heavy work.
Operator surfaces:
- Live pane stream: short updates and asks.
- Rolling status file: `outputs/sessions/<session_id>/status.md`, last N events, default N=10.
- Aggregate dashboard: `outputs/dashboard.md`, only when two or more sessions are active or Zevs asks.
- End-of-session summary: `outputs/sessions/<session_id>/summary.md`, written when work pauses or completes in deep or long-running sessions.
Status triggers:
- Phase start or end.
- Mode entry, switch, or exit.
- Blocker or escalation.
- Decision gate.
- Before long-running work.
- Heartbeat during long-running work.
- Operator pull request.
Heartbeat rule:
- During long-running work with no state change, send a heartbeat no more often than every N minutes.
- Default N=5 for standard work and N=2 for deep/high-attention work.
- Heartbeat should state only what is still running, expected next check, and whether Zevs action is needed.
- Heartbeat is not exempt from the one-message-per-minute rate limit; the heartbeat interval should always be greater than the routine rate-limit window.
Anti-spam rules:
- Do not post a status update if nothing changed and no heartbeat interval elapsed.
- Rate-limit routine status to one message per minute per agent per session.
- Prefer one lead-agent status over duplicate per-agent updates.
- Move detail into `ref=<path>` artifacts instead of pane text.
Lead-agent selection:
- First agent to enter the mode is lead by default.
- Lead owns operator summaries for the current session.
- Other agents may send direct operator status only for blockers, safety issues, or handoff failures.
- Lead may be reassigned with a `type=request-action` or `type=status-update` handoff message.
Pull status:
- Zevs may ask for status at any time.
- The active lead responds with the current dashboard slice.
- If no lead is known, the first active agent to see the request answers and records itself as temporary lead.
Minimum status fields:
- `session_id`
- `phase`
- `mode`
- `artifact_ref`
- `lead_agent`
- `status`: `idle | working | blocked | waiting-for-operator | done`
- `completed_since_last_update`
- `in_progress`
- `next_action`
- `blockers`
- `asks_for_Zevs`
- `risk_or_residual_uncertainty`
- `expected_wait`
- `last_update`, as an ISO 8601 timestamp consistent with ADR 002 `session_started`
ADR 022 `status` is operator-facing workflow status, not transport-reported process status. For example, herdr `agent_status=blocked` may mean a permission prompt, while ADR 022 `status=blocked` means the workflow is blocked on a dependency or operator action. Implementations may map between the two, but they are not the same field.
Intervention fields:
- `intervention_urgency`: `now | soon | when-convenient`
- `intervention_type`: `decision | context | permission | acknowledgment | stop-signal`
- `consequence_if_intervened`
- `consequence_if_not`
- `rollback_cost`
- `sticky_or_transient`
End-of-session summary fields:
- `session_id`
- `final_status`
- `completed_artifacts`
- `accepted_decisions`
- `open_decisions`
- `parked_items`
- `residual_risk`
- `follow_up_modes`
- `operator_actions_needed`
Strengths:
- Gives Zevs fast live state and durable scannable state.
- Prevents both silent long work and status spam.
- Clarifies what kind of operator input is needed.
- Gives multi-agent sessions one lead voice.
- Keeps detailed rationale in artifacts instead of pane messages.
Trade-offs:
- Adds status file conventions.
- Requires lead-agent discipline.
- Deep summaries add work at pause or completion time.
- Status files are not an audit trail; ADR 023 still owns transport-level verification.
## Decision
Accepted decision: Option C.
Current positions:
- Codex initial proposal: Option A.
- Claude counterproposal: Option B.
- Convergence candidate: Option C.
- Claude's provisional vote: Option C because multi-session work needs a rolling summary file for at-a-glance state.
- Codex currently prefers Option C because it preserves short live updates while giving Zevs pull status, intervention fields, and durable summaries when the work is larger.
- Claude approved the draft and confirmed its preferred final option is Option C.
- Codex folded in Claude's non-blocking polish on status-layer distinction, heartbeat/rate-limit interaction, and `last_update` timestamp format.
- Zevs's standing approval applies once Codex and Claude agree.
Rationale: Option C keeps live operator updates compact while adding durable rolling status and richer intervention metadata when work becomes multi-step, multi-agent, or high-attention.
## Consequences
- Positive: Zevs can intervene without reading full transcripts.
- Positive: Status becomes event-driven but not silent during long-running work.
- Positive: Lead-agent ownership reduces duplicate updates.
- Positive: Rolling files make state scannable outside pane scrollback.
- Trade-off: Agents must maintain status artifacts for standard/deep work.
- Negative: This is still a file-and-message interface, not a dedicated UI.
## How to apply
For quick work, send compact in-pane status only when state changes or Zevs asks.
For standard shared work:
- Pick a lead agent at mode entry.
- Send status at trigger events.
- Keep pane status short.
- Maintain `outputs/sessions/<session_id>/status.md` when the session spans multiple steps.
For deep or multi-session work:
- Maintain rolling status.
- Add `outputs/dashboard.md` if two or more active sessions exist.
- Write `outputs/sessions/<session_id>/summary.md` when work pauses or completes.
Example status body:
```text
BODY: STATUS session=<id>; phase=3; mode=decide; ref=outputs/decisions/022-operator-interface.md; lead=codex; state=working; done=proposal_sent; next=await_claude_counterproposal; ask=none; risk=message_verbosity; eta=2-5m.
```
Example operator pull:
```text
BODY: MODE: status?; scope=current-session; requested_fields=state,next,asks,risk.
```
## Related
- `outputs/decisions/001-provenance.md`
- `outputs/decisions/002-agent-identity.md`
- `outputs/decisions/003-message-structure.md`
- `outputs/decisions/004-identity-and-message-profile.md`
- `outputs/decisions/010-brainstorm.md`
- `outputs/decisions/011-decide.md`
- `outputs/decisions/012-review.md`
- `outputs/decisions/013-validate.md`
- `outputs/decisions/014-debug.md`
- `outputs/decisions/020-mode-switching.md`
- `outputs/decisions/021-conflict-resolution.md`
- Future ADR 023: Cross-Pane Audit Trail