# ADR: Conductor-First Typed Dispatch Authority

Status: Accepted on 2026-07-11; bridge counts and dispatch admission are superseded by ADR 0003.

## Context

OMS already has a TypeScript, file-backed queue/control/evidence foundation, bounded provider hooks, reconciliation, worktrees, role policy, a local tracer, and a negative-only release assessment. It does not yet run the desired live product flow.

The required operator experience is one human-started persistent Claude Opus conductor in tmux. The human types the goal once; the read-only conductor then routes work across configured Claude and Codex lanes. OMS must observe provider and GitHub changes, survive restarts and quota pauses, and prepare verified pull requests without becoming a daemon or granting models merge/release authority.

The previous operator-first design required a human start ceremony for every worker and emitted product instructions for an external team runtime. That does not satisfy the desired OMS-owned conductor loop.

## Decision

V1 uses a conductor-first, typed-dispatch architecture:

1. A human runs interactive bare `oms` to create or resume an interactive read-only Claude Opus conductor in the OMS tmux session. On the first live run, the CLI obtains one exact repository-scoped human confirmation before state initialization or provider contact. The explicit `oms conductor start` form remains only for advanced recovery or a selected state root; non-interactive bare invocation prints help and contacts no provider.
2. The human enters a freeform goal. CD-01 begins with exactly two proposal tools on the session-scoped local stdio `oms conductor bridge`: `mcp__oms__propose_goal` and `mcp__oms__propose_dispatch`. The goal tool validates and atomically commits durable objective, scope, stopping condition, horizon, and budget/policy state. The dispatch tool is initially advertised and schema-valid but deterministically returns `dispatch-not-enabled` with no mutation.
3. CD-02 activates that same dispatch handler without adding tools or permissions. Every worker assignment then becomes a validated, persisted OMS envelope bound to exact goal, ticket, lease, attempt, role/model, provider eligibility, worktree, capabilities, budget, acceptance/evidence requirements, and nonce before delivery. Freeform content never enters argv, a shell, or file Write.
4. CD-03 adds exactly two narrow control tools: `mcp__oms__manage_worker` for observe/park/resume/stop and `mcp__oms__start_team` for grouping already accepted dispatch IDs. The complete conductor bridge therefore has four tools: two proposal tools and two fixed-action controls. It exposes no generic shell, filesystem, tmux, provider, GitHub, verification, merge, or release authority.
5. OMS provider adapters start and observe interactive Claude workers, resumable Codex Goal workers, and eligible fresh read-only exec roles. Worker sessions require an explicitly reviewed `operator_originated_oms_managed_interactive` policy; legacy per-worker human-start flags are not silently reinterpreted. Direct tmux operations are encapsulated; the conductor cannot invoke them.
6. Provider hooks drive immediate session/activity/health/completion-observed/quota observations. Completion hooks cannot set `agent=done` or `ticket=verifying`; only one dispatch-bound typed result receipt can. A one-shot GitHub sync runs every 60 seconds by default. Projected events form opaque notification batches, and a version-pinned `asyncRewake` waiter wakes an idle conductor to re-read canonical state. Waiter generations are durable CAS records bound to conductor session/process identity. The 15-minute watchdog is the sole dead-waiter recovery owner: it may resume/respawn only a proven idle/dead conductor so `SessionStart` re-arms, never interrupt active work, and otherwise record visible stalled/blocked state.
7. Deterministic verification is the final vote. Exactly one fresh opposite-engine grade is mandatory and supplemental. An unavailable/ineligible opposite engine parks or blocks visibly; bounded reflection/retry cannot bypass attempts or verification.
8. OMS may push isolated branches, open/update draft pull requests, attach evidence, and report `READY_FOR_HUMAN`. Only a human may merge, tag, publish, or release.

## Simplicity boundary

- Native primitives provide provider sessions, local stdio MCP tools, `asyncRewake` hooks, tmux, worktrees, GitHub access, and scheduling.
- Skills define conductor, worker, advisor, grader, reflection, quota, schedule, and team behavior.
- Small Node.js/TypeScript commands provide the four-tool session bridge, state, dispatch, adapters, event synchronization, generation-safe notification waiting, watchdog recovery, verification, and evidence.
- V1 adds no daemon, database, framework, webhook listener, custom mux library, tracked shell automation, or general workflow engine.
- A team is only a group of executor dispatches. V1 uses one deterministic review gate followed by one fresh structured cross-engine grade; teams add no second verifier/model-review lane.

## Authority boundary

The conductor may prioritize eligible tickets, select configured roles/lanes, ask for advice or grading, launch/observe/park/resume/stop workers through OMS, and select a legal retry or escalation.

The conductor may not edit product code or canonical state, modify durable policy, widen goal scope silently, introduce providers/models/credentials/spend classes, issue raw tmux commands, override verification or stale authority, exceed attempts/budget, merge, publish, release, or claim stability. It has no Edit/Write permission. Freeform goal and task proposals use only the two proposal tools; worker lifecycle and team grouping use the two narrow control tools with opaque canonical IDs. All other access is read-only diagnostics.

Workers may mutate only their isolated ticket worktrees and may acknowledge/return results only for their dispatch. They cannot write goal, verification, trust, queue, merge, or release authority.

OMS owns durable goal, ticket, lease, dispatch, worker/session, event, quota, verification, evidence, attempt, audit, and human-hold state.

## State semantics

- Agent activity: `idle | working | blocked | done`
- Agent health: `healthy | parked | stalled | stopped`
- Ticket lifecycle: `pending | leased | running | verifying | completed | retryable | parked | blocked`

`agent=done` means one schema-valid result receipt bound to the current goal, dispatch, attempt, lease, session, worktree, and commit arrived. It moves the ticket to `verifying`; only protected deterministic evidence plus the mandatory opposite-engine grade may complete it.

## Security boundary

- Raw issue, comment, review, provider, hook, pane, and model text is untrusted content and never becomes a command or authority.
- Freeform goal/task text crosses only the two proposal tools. CD-01 can mutate only goal authority while dispatch remains `dispatch-not-enabled`; CD-02 activates dispatch; CD-03 adds two schema-bound lifecycle/team controls that accept canonical IDs and bounded control fields. The bridge rejects oversize/non-schema input, stale authority, capability expansion, changed identity, and replay before canonical mutation and exposes no ambient filesystem/shell/provider/GitHub/verification/merge/release capability.
- Dispatch, hook, event, result, and evidence identities are replay-safe and exact-version bound.
- One expected-version/nonce waiter generation is active per conductor session/process. Dead-waiter recovery is watchdog-owned; duplicate recovery, PID reuse, unsafe resume, or lost notification fails visible rather than widening authority.
- Hook completion is observational only. Missing/stale/cross-dispatch result receipts cannot create `done` or `verifying` state regardless of event order.
- Pane text and sentinels are diagnostic only.
- Candidate code cannot replace the installed verifier, frozen plan, policy snapshot, or evidence writer.
- Unknown provider/auth/billing/version eligibility, credential widening, stale authority, or deterministic failure stops the path.
- Hook/receipt evidence proves the documented local OMS continuity boundary, not cryptographic provider attestation.

## Alternatives

### Human starts every worker

Rejected. It preserves a narrow operator boundary but fails the intended experience that the human starts only the conductor.

### Raw conductor-driven tmux commands

Rejected. It exposes brittle TUI transport and injection risk as public authority. OMS adapters may use tmux internally with typed validated inputs.

### Path-scoped proposal files

Rejected. A session-scoped stdio bridge keeps Edit/Write entirely disabled and passes freeform proposal fields through native JSON tool input instead of relying on dynamic filesystem permissions.

### Custom orchestration service

Rejected. Native CLIs, skills, one-shot commands, tmux, hooks, and user schedulers cover v1.

### Webhook server

Deferred. Sixty-second polling with durable watermarks is sufficient for v1 and avoids a listener/secret/deployment boundary.

### Automatic merge or release

Rejected for v1. It requires endurance evidence, explicit trust policy, and a separate reviewed ADR.

## Consequences

- The first human action remains explicit and visible.
- The conductor can behave agentically without owning deterministic authority.
- OMS must keep the four-tool session bridge narrow, implement one generation-safe event waiter with watchdog-owned recovery, and retain small provider/pane and schedule boundaries.
- The operator-originated OMS-managed interactive worker policy must be checked against current official provider policy and CLI behavior; it remains distinct from headless/unattended eligibility and fails closed when uncertain.
- Long runs depend on durable state, hooks, polling, and recovery rather than model context.
- A successful run ends at a verified review-ready PR and negative-only release assessment.

## Follow-ups

- Promote this ADR and add a regression test in CD-01.
- Consider webhooks, additional schedulers, automatic merge, package release, or unattended credential lanes only through separate reviewed changes after the 12-hour and fresh 24-hour proofs.
