# cmux Lead Runtime Adapter

## Scope

This adapter maps the neutral Okstra lead operations to a cmux session, where Okstra owns the worker panes regardless of which model is leading. Read it only when the rendered launch prompt selects it; the run manifest's `terminalBackend` is `cmux-pane` for exactly those runs.

It overrides only the worker-dispatch portion of the selected host relay, not the host or lead contract. Your own runtime still decides how you read files, ask the user, and record your session — this file only decides how workers are started, awaited, and reclaimed.

Keep the selected host relay's dispatch permission guidance when calling `okstra team dispatch`. For a restricted Codex lead, its `Permission at the dispatch boundary` guidance applies to every live dispatch, including reverify and critic jobs; selecting cmux does not grant execution privileges.

## Capability declaration

| Field | Value |
|---|---|
| `runtime` | environment-selected — any lead runtime resolves to this adapter under cmux |
| `leadRoleLabel` | `Okstra lead` |
| `userPromptMode` | `host-text` |
| `workerDispatchBackend` | `cmux-pane` |
| `initialPromptDeliveryMode` | `eager-include` |
| `sessionAccounting` | unchanged — keep your own runtime's accounting |
| `resumeMode` | `artifact-checkpoint` |
| `teardownMode` | `pane-teardown` |
| `leadEventSource` | `lead-events-jsonl` |

## Semantic operation mapping

| Operation | Mapping |
|---|---|
| `read_artifacts` | Read the manifest-provided paths through the current host's file or shell interface. |
| `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
| `prompt_user` | Ask through the host text/question interface and require an explicit approval or clarification response. |
| `dispatch_worker` | Run `okstra team dispatch --project-root <root> --run-manifest <path>`; use `--dry-run` first when the core requires a dispatch preview. |
| `await_workers` | Run `okstra team await --project-root <root> --run-manifest <path>` through the host's asynchronous shell facility. |
| `redispatch_worker` | Create the core-specified fresh jobs file and dispatch it with a new `dispatchKind`; never reuse a live worker conversation. |
| `shutdown_workers` | Run `okstra team teardown --project-root <root> --run-manifest <path>` only after the user-approved cleanup gate. |
| `record_lead_event` | Append progress and activity records to the manifest-provided `leadEventsPath`. Use `okstra lead-progress append --phase <phase-id>` for a checkpoint and `okstra agent-activity append --kind <kind>` for an activity record; both resolve the ledger path from the run manifest. Emit the matching `PROGRESS:` line — the command prints it as `progressLine` — and, when an activity record is required, the immediately following `ACTIVITY:` line from the same structured fields. |
| `collect_usage` | Collect artifact/CLI-log-backed usage through the existing Okstra token-usage path; never substitute another runtime's session log. |

An `implementation` run calls `dispatch_worker` twice: once for the Executor, then — after `await_workers` settles it — once for the verifiers. That second call's `--workers` list must omit the Executor's worker ID: it is materialized as the Executor on every dispatch, so a batch still carrying it is refused again. A verifier started beside the Executor observes base HEAD instead of the stage diff, so a single batch holding both is refused by `scripts/okstra_ctl/dispatch_core.py` `_validate_implementation_phase_order`, `--dry-run` included.

## Pane placement is not yours to compute

Okstra creates, sizes, labels, and closes every worker pane. Do not issue terminal-multiplexer commands of any kind — not to place a worker, not to resize the lead, not to reclaim a finished round. Pane geometry depends on the display, and a lead that recomputes it per run gets it wrong differently on every host.

Concretely: you never choose a split direction, a pane width, a surface id, or a title. `okstra team dispatch` does all of it and records what it created.

## Watching a worker is not the same as judging it

Workers run beside you, so you can read their screens. That is a diagnostic channel and nothing more.

- A worker is finished when its dispatch record reaches a terminal status and its required Result Paths exist. Nothing you see on a screen changes that verdict.
- Never parse a pane's contents into a result. Terminal output is a rendered grid — wrapped to the pane's width, with history truncated — so a path or a number read off it may be silently incomplete.
- Never send input to a running worker. Workers are one-shot sessions whose prompt is already delivered; retries and re-verification always create a fresh session, and interrupting a live worker contaminates exactly the context that rule protects.

Use the screen to tell "still working" from "stuck", and to see at a glance which worker failed. Use the artifacts for everything else.

## cmux dispatch details

- For convergence reverify, consume the persisted round plan exactly. This adapter may map and transport each returned batch, but it cannot change batch membership and does not classify findings or branch on task type, provider, or model identity.
- Do not invoke Claude Code team tools or `okstra codex-dispatch`. Under cmux every lead dispatches through `okstra team`, including a Claude Code lead.
- Worker completion is valid only from `workerDispatches[]`, terminal status sidecars, and required Result Paths. Pane creation alone is not completion.
- Reverify uses a fresh jobs file at `runs/<task-type>/state/reverify-jobs-r<N>-<task-type>-<seq>.json`, sets `dispatchKind: "reverify-r<N>"`, and dispatches with `okstra team dispatch --project-root <root> --run-manifest <path> --dispatch-kind reverify-r<N> --jobs-file <jobs-file>`.
- Report-writer uses a fresh one-job jobs file with `dispatchKind: "report-writer"` and the same schema, then dispatches through `okstra team dispatch --project-root <root> --run-manifest <path> --jobs-file <jobs-file>`.
- Generate v2 jobs files with `okstra agent-prompt jobs --project-root <root> --run-manifest <path> --dispatch-kind <kind> --metadata <prompt-meta.json> [--metadata <prompt-meta.json>] --out <jobs-file>`. Pass only the metadata paths for the core-planned batch. The command derives the `workers` array, canonical role execution, result headers, and five digests, and verifies them through the same consumer used at dispatch. Do not transcribe those fields. Identical output is reused; differing output is preserved and requires a new `--out` path. Existing v1 files remain readable by dispatch.
- `workerResultPath` is the path the prompt tells the worker to write: the prompt's `**Result Path:**`, or `**Worker Result Path:**` for the report writer. `okstra team dispatch` refuses an entry whose value differs from that anchor, because the collector waits on `workerResultPath` while the worker writes where the anchor says. A reverify result is named `<worker-id>-worker-reverify-r<N>-<task-type>-<seq>.md`: the `-worker-` token is what the audit sidecar name inserts `-audit-` after (a name without it is refused with `worker result path has no canonical -worker- token`), and the round label is what keeps one round's file apart from the next. The report writer's `workerResultPath` is the roster's `resultPath` for `report-writer` and its `**Result Path:**` is the run manifest's `reportNarrativePath` — the report-writer materialization ([report-writer](../report-writer.md)) refuses any other pair. **Enforced:** `_validate_jobs_file_prompt_anchors` in `scripts/okstra_ctl/dispatch_state.py`, `_validate_report_writer_paths` in `scripts/okstra_ctl/agent/prompt_cli/materialize.py`.
- `role` names the role execution's own role — `verifier` for reverify, `report-writer` for the report writer. It is not a per-round label: `dispatch_state.py` requires the entry's `role` to equal both the role execution's `role` and the duty's role, so a value like `worker-reverify-r<N>` is refused as `jobs file v2 identity does not match role execution authority`. The round lives in `dispatchKind` and in `invocationRef`. The report-writer completion paths include its narrative Markdown, worker-result pointer, and audit sidecar; they do not include the Phase 7 report record.
- After either dispatch, run `okstra team await --project-root <root> --run-manifest <path>` before evaluating terminal status or completion paths.

## Completion, cleanup, and resume

- Await through `okstra team await`; raw Result Path polling is forbidden for this backend.
- Reclaim terminal panes after each batch through `okstra team reclaim --project-root <root> --run-manifest <path>` before dispatching the next batch. Reserve `teardown` for run completion.
- Resume from run artifacts and lead-events checkpoints. After usage collection, persistence, and the core user-approval gate, run `okstra team teardown --project-root <root> --run-manifest <path>` and tear down only Okstra-owned panes recorded for the run.
