zynk 0.2.0

Portable protocol and helper CLI for multi-agent collaboration.
# 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