# Runtime Adapters

Open Orchestra uses one adapter catalog for LLM runtimes, IDEs, and CLI agents.
The catalog keeps target names, default files, managed-block support, structured
payload support, and usage guidance in one place.

## Adapter Catalog

```bash
orchestra runtime adapters --json
```

Current targets:

- `generic`: provider-agnostic Markdown in `ORCHESTRA.md`.
- `claude`: Claude project memory in `CLAUDE.md`.
- `cursor`: Cursor MDC rules in `.cursor/rules/open-orchestra.mdc`.
- `codex`: Codex instructions in `AGENTS.md`.
- `vscode`: extension/chat payloads in `.vscode/open-orchestra.runtime.json`
  and `.vscode/open-orchestra.md`.
- `windsurf`: Windsurf rules in `.windsurf/rules/open-orchestra.md`.

Execution adapters are separate from instruction-file targets. They describe
how an already-authenticated runtime should receive a brief or delegation
packet:

- `codex-cli`: use the current Codex CLI/session. Tool permissions and shell
  approvals stay inside Codex; Orchestra renders briefs and packets only.
- `claude-cli`: use the current Claude Code session. Orchestra renders the
  packet and the Claude parent launches it with the native Agent/Subagent tool
  when available. The tested auto-dispatch eligibility contract recognizes
  `claude-code-agent` as the primary tool; `Task` is documented as a deferred
  legacy/manual alias and is skipped as `tool-mismatch` by auto-dispatch.
- `cursor-cli`: use the current Cursor runtime. Orchestra renders the packet
  and the Cursor parent launches it as a Background Agent so the current chat
  remains usable while the child works.
- `opencode-cli`: use an authenticated OpenCode CLI with its own provider
  config. Orchestra uses the generic instruction target and never copies
  provider keys into workflow artifacts.
- `generic-runtime`: produce portable briefs when the executor has no known
  invocation or permission model.

Provider-backed model adapters are configured separately from execution
adapters. `gemini` and `ollama` can be used for workflow phases without making
them child process runtimes:

```bash
orchestra model connect --provider gemini --model gemini-2.5-pro \
  --roles architect,developer --api-key-file ~/.env_jt/gemini

orchestra model connect --provider ollama --model llama3.1 \
  --roles qa --base-url http://127.0.0.1:11434
```

Secrets stay in environment variables or local secret files referenced from
config. Runtime packets keep `directProviderApiAllowed: false`; provider API
execution only happens in the workflow phase provider layer when policy allows
it.

Provider-backed phases require explicit opt-in. Connecting a provider with
`--allow-direct-provider-api` records both the allowed provider and
`runtimePolicy.delegation.allowDirectProviderApi=true`; without that opt-in,
workflow phases fail before calling the provider. Successful provider-backed
phases are recorded as `executor: provider-backed-phase` with provider, model,
fallbacks, request id, response id, token usage source, cost source, final
provider/model, and `directProviderApiAllowed: true`. Runtime-native subagent
requests remain `directProviderApiAllowed: false`, even when provider routing is
configured for the same role.

Provider-backed phase execution goes through the provider-backed agent wrapper.
The wrapper resolves `openai`, `anthropic`, `gemini`, `ollama`, `fake`, and
future providers through the provider registry/factory boundary around
`ModelProvider`; workflow orchestration should not branch on provider vendors.
OpenAI/Codex provider models are provider-backed execution. `codex-cli` is a
runtime-native parent session and never becomes a provider API fallback unless a
future explicit hybrid policy records that decision as evidence.

Before the wrapper creates a provider adapter or sends a request, it evaluates
provider egress through the security policy boundary. Messages are classified
through the shared classifier/redaction contract and treated as a `provider`
sink. Restricted or unsafe-unredacted content is blocked before any provider
call; only sanitized policy metadata may be recorded as evidence. Provider
failure messages are sanitized before surfacing so backend base URLs,
authorization headers, API keys, and token-shaped values are not exposed.

Internal providers such as `ollama` are private-only. `OLLAMA_BASE_URL` must be
server-configured and point at `localhost`, loopback, link-local, or RFC1918
private-network IP addresses. Public DNS names and public IPs are rejected by
policy. Use loopback for local development, or a private address reachable only
inside the trusted deployment network.

### Ollama Evaluation And Training Boundary

`ollama` is an internal local-provider adapter, not a hidden child runtime and
not a training executor. Provider-backed phases may use it only after explicit
direct-provider opt-in and policy checks. Runtime-native packets remain
`directProviderApiAllowed: false` and must not contain Ollama credentials,
private prompts, dataset contents, or local endpoint details.

Internal agent improvement must start with mock/fake contract evidence,
manifest-governed eval fixtures, and versioned prompt/context packs. Real local
Ollama smoke is optional and loopback/private-only. Training, fine-tuning, LoRA
adapter generation, quantization, model export, and model publication require a
future task with Product, Architect, Security, Compliance/Privacy, QA, and
Release approval. The design is captured in
[Internal Ollama Agent Evaluation And Tuning Design](internal-ollama-agent-design.md).

## Init Modes

Default project init keeps the current compact bootstrap behavior:

```bash
orchestra init
```

Generate only selected runtime files:

```bash
orchestra init --target claude,cursor,windsurf
```

Refresh managed runtime blocks and generated instruction files:

```bash
orchestra refresh --check --json
orchestra refresh --dry-run
orchestra refresh --force --target codex
```

`refresh --check` reports drift without writing. `refresh --dry-run` shows the
planned changes. `refresh --force` rewrites managed blocks only; user-authored
content outside generated blocks is preserved.

Advisory mode creates workflow state without root instruction files unless a
target is explicit:

```bash
orchestra init --advisory
orchestra init --advisory --target claude
```

It also writes portable planning artifacts under
`.agent-workflow/advisory/`: a README, role guides, decision template, and a
project task export that can be moved into a confirmed project workspace.

Unsafe roots are blocked before writes. Unknown non-temp directories require an
explicit confirmation:

```bash
orchestra init --confirm-unknown
```

## Runtime Loop

After init, any runtime should use the same local control-plane loop:

```bash
orchestra health --json
orchestra task list --json
orchestra context --task STORY-001 --json
orchestra delegation decide --task STORY-001 --json
orchestra memory hook --point before_plan --task STORY-001 --json
orchestra skills render --target codex --task STORY-001
orchestra protocol render --target codex --task STORY-001
orchestra workflow render --target codex --task STORY-001
```

Change `--target` to the runtime that is executing the work. The workflow state,
roles, evidence, reviews, and gates remain runtime-agnostic.

## Codex Recurring Preflight

Codex does not provide a project-native recurring hook that Open Orchestra can
install for every context compaction, resumed session, interruption, or role
handoff. The fallback is explicit managed guidance in `AGENTS.md` plus the
existing pre-run validation command.

Before each new Codex work block, and again after any context shift, run:

```bash
orchestra health --json
orchestra task list --json --status pending,blocked,in_progress
orchestra validate --pre-run --task STORY-001 --json
```

The JSON report includes `activeOrchestraContext` and `missingActiveContext`.
When `activeOrchestraContext` is `false`, the current Codex session is missing
one or more required workflow anchors: task registration, effort estimate, or a
workflow run for the task. Reload task context and resume or register the
workflow before editing files. Evidence and review checks still appear in the
same report, but those are completion/handoff signals rather than active-context
anchors.

## Web And VS Code

The local web console exposes workspace classification and supported runtime
targets through:

```bash
orchestra web
```

The API contracts are:

```bash
curl -s http://127.0.0.1:3717/api/workspace/classification
curl -s http://127.0.0.1:3717/api/runtime/adapters
curl -s http://127.0.0.1:3717/api/workflow/progress
```

These endpoints are intended for VS Code, Cursor-like extensions, and other
clients that need to show safe next actions without parsing human CLI output.
`/api/runtime/adapters` and `orchestra runtime adapters --json` expose both
instruction-file targets and nested execution adapters. Execution adapters
include tool permission policy metadata so clients can distinguish
runtime-managed, brief-only, read-only, and opt-in autonomous execution models.

Runtime delegation operations are event-derived:

```bash
orchestra runtime sessions --json
orchestra runtime sessions --task STORY-001 --json
orchestra runtime session --session STORY-001:claude-cli --action suspend --json
orchestra runtime session --session STORY-001:claude-cli --action resume --json
orchestra runtime session --session STORY-001:claude-cli --action cancel --json
orchestra runtime spawn-request --task STORY-001 --role developer --runtime codex-cli --json
orchestra runtime parent-actions --task STORY-001 --json
orchestra runtime parent-actions --task STORY-001 --dispatch --until-idle --runtime codex-cli --timeout 5m --idle-timeout 10s --json
orchestra runtime spawn-lifecycle --session STORY-001:manual:developer:codex-cli --status spawned --agent-id <runtime-agent-id> --json
orchestra runtime watch --task STORY-001 --once --json
```

The matching local APIs are `GET /api/runtime/sessions`,
`POST /api/runtime/spawn-request`, and `POST /api/runtime/spawn-lifecycle`.
Session operations do not kill external provider processes directly; they
record auditable suspend, resume, cancel, close, spawned, active, completed,
failed, or timed-out events so the parent runtime can reconcile claimed work,
spawned agent ids, stale sessions, and handoff state without inventing a second
source of truth.

Spawn request JSON and `runtime parent-actions` include `parentRuntimeAction`, a
structured instruction for the active parent runtime. Codex receives
`kind=codex-spawn-agent` with `tool=spawn_agent`; Claude receives
`kind=claude-agent-request` with `tool=claude-code-agent`; Cursor receives
`kind=cursor-background-agent` with `tool=cursor-background-agent`. The action
points to the prompt artifact, expected result artifact, ownership paths,
allowed commands, and lifecycle commands. It does not include secrets or direct
provider credentials.

## Runtime Spawn Bridge Boundary

Open Orchestra is the runtime delegation control plane, not the owner of hidden
LLM runtime tools. Core commands normalize the spawn intent, evaluate guardrails,
write prompt and handoff artifacts, expose parent actions, record lifecycle, and
resume workflows. The actual native spawn call belongs to a parent-side consumer
running inside the active runtime session.

The bridge contract has two sides:

- **Control-plane wrapper**: Orchestra emits a runtime-neutral request with task
  id, run id, phase, role, context bundle, ownership paths, expected output,
  evidence contract, queue metadata, and lifecycle commands.
- **Parent-side consumer**: the active Codex, Claude, Cursor, local worker, or
  other runtime reads the parent action, invokes any native child-agent tool it
  owns, and records `runtime spawn-lifecycle` with the real child identifier.

A session is only considered actually spawned after a lifecycle event records
`--status spawned` with a real runtime child id. Parent actions, request
artifacts, and dispatch guidance are not equivalent to a running subagent.

Adapter capability terms are strict:

- `parent-tool`: a parent runtime can invoke a native tool such as Codex
  `spawn_agent`, but Orchestra still cannot call that hidden tool from Node.
- `request-only`: Orchestra can produce the request and lifecycle instructions,
  while the parent runtime must execute the native tool manually or by following
  its session prompt.
- `local-process`: a future explicit local executor can be launched as a child
  process under Orchestra policy.
- `unsupported`: no subagent request should be emitted except as an explicit
  unsupported/fallback result.

For Codex, the intended path is parent-tool mediated: Orchestra renders
`codex-spawn-agent`, the parent Codex agent consumes the action and calls
`spawn_agent`, and the returned Codex agent id is recorded through
`runtime spawn-lifecycle --status spawned`. Until that happens, Codex actions
remain requested or skipped with manual guidance.

For Claude, the current supported path is request-only or parent-agent mediated.
Claude Code's parent session can launch Agent/Subagent work, but Orchestra
cannot invoke that tool directly from its CLI process. Real automation requires
the parent Claude agent to follow the session instruction to inspect
`runtime parent-actions` and call the Agent tool, or a future Claude hook/API
that can trigger the same action. Until such a hook or callback is available and
verified, automated Claude native execution remains deferred/manual and must not
claim spawned lifecycle.

Pending parent actions also include structured `eligibility` metadata. The
metadata records the checked runtime, action kind, tool name, session status,
runtime filter when supplied, and safety state. Dispatchable actions report
`status=dispatchable`; skipped actions include machine-readable reason codes
and operator-readable messages. Current skip codes are `already-dispatched`,
`queued`, `suspended`, `terminal`, `stale-or-unsafe`, `runtime-mismatch`,
`tool-mismatch`, `unsupported-runtime`, `unavailable-native-tool`, and
`manual-request`.

When `workflow run` pauses with a pending parent runtime action, parent agents
have two supported paths:

- Manual inspection: run `runtime parent-actions --task <id> --json`, inspect
  each requested action, call the active runtime's native tool, then record
  `runtime spawn-lifecycle` with the returned child id.
- Verified dispatch: run
  `runtime parent-actions --task <id> --dispatch --until-idle --runtime <runtime-id>`.
  The dispatcher repeatedly inspects pending parent actions, dispatches only
  safe actions for the active runtime, records spawned and active lifecycle
  events only when the adapter has a real runtime child id or verified callback
  correlation id, applies `runtime watch` completions when expected handoff
  artifacts appear, resumes paused workflow runs, and continues across later
  phases until idle or timeout.

The auto-dispatch loop is bounded by `--timeout`, `--idle-timeout`, and
`--interval`, so it never polls forever. It skips queued actions, suspended
sessions, terminal sessions, stale or unsafe actions, runtime mismatches,
already-dispatched sessions, unsupported runtimes, unavailable native tools,
manual requests, and tool mismatches. Skipped actions include fallback guidance
with the prompt artifact, expected result artifact, and manual lifecycle
commands so a human parent runtime can safely continue without provider API
access. This keeps the boundary explicit: Orchestra emits auditable actions and
lifecycle commands; the active parent runtime or a verified local bridge
executes native tools. Codex dispatch cannot invoke `spawn_agent` from the CLI
process, so `codex-spawn-agent` dispatch returns manual guidance and must not
record `spawned` until the Codex parent runtime has called `spawn_agent` and
then runs `runtime spawn-lifecycle --status spawned` with the real returned
agent id. For Claude, the tested dispatch contract accepts
`claude-agent-request` with `tool=claude-code-agent`, but it records `spawned`
and `active` only when the active parent runtime is Claude and the native
callback capability is explicitly verified. Unsupported Codex, CI, non-Claude,
or callback-unavailable contexts return fallback guidance and do not claim
native execution. Orchestra does not call Claude Code, Anthropic APIs, or
another provider API.

Runtime-native dispatch also enforces delegation capacity before calling parent
runtime tools. The dispatcher evaluates actions sequentially, reserves only the
oldest eligible requested sessions within `maxConcurrentDelegates` and
`maxSpawnsPerTask`, keeps suspended sessions from opening extra capacity, and
leaves over-capacity actions queued with structured `checked.capacity` metadata.
`runtime parent-actions --json` applies the same capacity evaluation, so parent
runtimes see backpressure before invoking a native spawn tool.
When lifecycle events complete, fail, time out, cancel, or close an active
session, the next queued action can be promoted to a requested parent action and
dispatched on the next bounded auto-dispatch pass. This prevents several squads
or gates from flooding the parent runtime at once while still allowing
background work to continue as capacity becomes available.

Runtime lifecycle watching is adapter-driven. Each inspected session reports a
`watcher` object with adapter id, detection mode, support level, supported
completion signals, fallback behavior, and the reason a native callback is
unavailable. `codex-cli`, `claude-cli`, and `cursor-cli` reconcile completion
through observable runtime notifications, explicit lifecycle events, child
self-report commands, and bounded expected-artifact inspection. `generic-runtime`,
unknown runtime ids, and runtimes without declared callbacks use the same safe
artifact fallback directly. Event-driven callbacks should only be used when the
selected watcher adapter declares native support; otherwise `runtime watch`
requires a safe handoff artifact or a recorded runtime notification before it
marks a session terminal.

Runtime notifications are provider-neutral. A parent runtime, local integration,
web callback, or child agent that cannot directly run `runtime spawn-lifecycle`
can record an observable signal with:

```bash
orchestra runtime notification --session <session-id> --status completed --artifact <expected-handoff.md> --agent-id <runtime-child-id>
```

The watcher still validates task id, phase, role, runtime, session id, and the
expected handoff artifact before applying completion. A notification without the
expected artifact stays waiting; a mismatched or unsafe artifact is skipped with
an explicit reason. Failed notifications record failed lifecycle state and do not
auto-resume the workflow.
For spawned or active sessions, expected handoff validation runs before timeout
evaluation. A stale session that already produced the valid expected handoff is
completed, while stale sessions without a valid completion artifact can still be
marked timed out.
Requested sessions are also reconciled from a valid expected handoff artifact.
This covers parent runtimes that produce the handoff but cannot self-report the
intermediate spawned lifecycle event.

## Claude Adapter Support Level

Claude support is currently a parent-runtime dispatch and lifecycle contract,
not proof that Orchestra can invoke Claude Code or Anthropic APIs by itself.
The tested local behavior covers:

- Dispatch support: eligible `claude-agent-request` actions for `claude-cli`
  with `tool=claude-code-agent` can be inspected by
  `runtime parent-actions --dispatch --runtime claude-cli`. The dispatch path
  records `spawned` and `active` lifecycle state only when the bridge verifies a
  Claude parent runtime and callback capability. In local contract tests this is
  simulated with explicit environment markers; in unsupported environments the
  action is skipped with manual fallback guidance.
- Alias policy: `claude-code-agent` is the only auto-dispatchable Claude tool
  name in the tested contract. `Task` is a legacy/manual alias and is skipped
  as `tool-mismatch`; accepting it in auto-dispatch requires new tests and
  documentation.
- Fallback behavior: skipped, unsupported, unsafe, stale, queued, suspended,
  terminal, mismatched, or unavailable actions return structured eligibility
  metadata, fallback guidance, prompt artifact, expected result artifact, and
  manual lifecycle commands. Fallback never runs the phase in the parent agent
  silently, never records native Claude lifecycle events, and never switches to
  direct provider APIs.
- Guardrails: dispatch is bounded by runtime guardrails, runtime filters,
  session status, safety state, action kind, tool name, and stale-session
  checks. It preserves `directProviderApiAllowed=false` for runtime-native
  delegation artifacts.
- Completion reconciliation: `runtime watch` validates the expected completion
  metadata before marking a Claude session complete. The validation checks task
  id, phase, role, runtime, session id, and the safe expected handoff path, and
  it also requires the final handoff artifact to repeat those metadata fields.
  It skips mismatches, missing artifact metadata, unsafe paths, and duplicate
  completions with explicit reasons instead of treating any handoff file as
  completion proof. Native immediate `completionResult` payloads use the same
  validation path when present.
- Gate preservation: auto-dispatch must not approve or skip human gates.
  `workflow run --resume` now holds unapproved gates until
  `workflow gate-approve` records explicit approval, and runtime lifecycle
  auto-resume records no gate approval events. The regression suite covers safe
  non-gated resume, unapproved gate hold behavior, opt-out, queued/pending
  messaging, and multi-pass parent action dispatch.

Manual recovery for a skipped or unavailable Claude action:

```bash
orchestra runtime parent-actions --task <id> --json
orchestra runtime spawn-request --task <id> --role <role> --runtime claude-cli --json
orchestra runtime spawn-lifecycle --session <session-id> --status spawned --agent-id <claude-child-id-or-label> --json
orchestra runtime spawn-lifecycle --session <session-id> --status active --agent-id <claude-child-id-or-label> --json
orchestra runtime watch --task <id> --once --json
orchestra workflow run --task <id> --resume <run-id>
```

Only run the lifecycle commands after the parent Claude Code session has
actually launched or taken ownership of the rendered prompt artifact. If no
child id is returned by the runtime, use a stable operator label and keep the
expected handoff artifact path from the spawn request.

## Native Background Agent Notes

Claude Code and Cursor do not need Orchestra to call vendor APIs directly.
They need a precise packet and lifecycle hooks:

- Claude Code: render `runtime spawn-request`, then manually launch the packet
  from the parent Claude session with the native Agent/Subagent tool. The
  primary tested tool name is `claude-code-agent`. `Task` is deferred as a
  legacy/manual alias and is not auto-dispatchable in GH-432; auto-dispatch
  reports it as `tool-mismatch`. Record the returned child id or role label
  through `runtime spawn-lifecycle`.
- Codex: render `runtime spawn-request`, read `parentRuntimeAction`, and call
  the parent `spawn_agent` tool with the prompt artifact as the role-scoped
  assignment. In workflow auto-consumer mode, use
  `runtime parent-actions --dispatch --until-idle --runtime codex-cli` to
  discover and consume safe actions after the run pauses. Keep the child
  detached unless the parent is blocked. The child prompt must write the
  expected handoff and self-report completion with `runtime spawn-lifecycle`; if
  the runtime cannot execute commands, it must emit a runtime notification that
  can be reconciled by `runtime watch`.
- Cursor: render `runtime spawn-request`, then launch it as a Cursor Background
  Agent. Background work should stay detached from the current chat and report
  lifecycle state back to Orchestra before the workflow is resumed.
- All runtimes: keep `directProviderApiAllowed=false`, keep child prompts
  scoped to the request artifact, avoid full transcript transfer, and record a
  terminal lifecycle event before marking the phase complete.

The current vendor behavior this maps to is:

- Claude Code supports custom subagents with separate context and allows direct
  subagent invocation from the parent session.
- Cursor Background Agents run isolated remote agents in parallel and can be
  launched while the user continues working.

## Workflow Phase Executors

`workflow run` can plan how each phase should be executed without confusing the
role/profile with the runtime executor:

- **Role/profile**: PM, PO, Architect, Developer, QA, Release, or another phase
  owner. This controls responsibilities, playbooks, expected evidence, and gate
  authority.
- **Runtime executor**: `codex-cli`, `claude-cli`, `cursor-cli`,
  `opencode-cli`, `vscode-agent`, `windsurf-agent`, or `generic-runtime`.
  This controls where the brief or delegation packet is intended to run.
- **Subagent**: a runtime-native role-scoped execution unit, only available
  when the selected runtime adapter declares `subagents.runtimeNative: true`
  and a supported `subagents.spawn.mode`.
- **Spawn bridge**: the runtime-specific mechanism for requesting that child
  execution. Modes are `unsupported`, `request-only`, `parent-tool`, and
  `local-process`. `codex-cli` renders a `spawn_agent` request for the active
  Codex parent session, but the parent Codex agent must call the tool and record
  the returned id. `claude-cli` is request-only or parent-agent mediated until a
  reliable hook/API/callback is available. Other runtimes can consume the same
  request artifact without allowing Orchestra to call vendor APIs directly.
- **Provider**: a direct model/provider route used by provider-backed phase
  prompts. Provider APIs are separate from runtime-native subagents and are
  never used as a silent fallback for runtime delegation.

The workflow phase execution mode can be selected per run:

```bash
orchestra workflow run --task STORY-001 --phase-execution auto
orchestra workflow run --task STORY-001 --phase-execution subagents
orchestra workflow run --task STORY-001 --phase-execution single-agent
```

`auto` uses runtime spawn request artifacts when the selected runtime supports
them and delegation guardrails allow the spawn; otherwise it records a
parent-agent fallback reason. `subagents` requires runtime-native support and
fails fast if the runtime cannot satisfy it. `single-agent` forces the parent
agent path and records that choice in phase provenance.

Gate mode is independent from execution mode: `--gates none` suppresses human
gate pauses, while `--phase-execution single-agent` is what prevents detached
runtime parent actions and subagent lifecycle requirements.

When no task or role executor is configured and the default executor is
`generic-runtime`, `auto` and strict `subagents` mode infer the active runtime
from `OPEN_ORCHESTRA_ACTIVE_RUNTIME`, then from
`.agent-workflow/active-runtime.json`. The environment value accepts either the
runtime target (`claude`, `codex`, `cursor`) or the executor id
(`claude-cli`, `codex-cli`, `cursor-cli`) and wins over a stale or mismatched
persisted record so a parent runtime can correct cross-project/session drift.

`.agent-workflow/active-runtime.json` is the truthful signal of which AI runtime
is currently driving the conversation. It is written by the active runtime's
UserPromptSubmit hook on every session start. `orchestra init --target claude`
configures Claude's `.claude/settings.json` hook to call
`orchestra health --runtime claude-cli --json`; `--target cursor` configures the
equivalent in `.cursor/rules/orchestra-health.mdc`. Manual-setup guidance for
Codex/VS Code/Windsurf documents the same `orchestra health --runtime <id>`
pattern that must run at session start. Each hook overwrites the file with its
own runtime id, so "last writer wins" matches "current parent runtime".

The persisted record has a 24h TTL. Records older than that are ignored and
inference falls through to the default when no environment override is present.
Codex maps to `codex-cli`, Claude maps to `claude-cli`, Cursor maps to
`cursor-cli`, Windsurf maps to
`windsurf-agent`, and VS Code maps to `vscode-agent`.

Explicit selections always take precedence in this order: `--runtime` flag,
task override, role override, then `runtimePolicy.defaults.executor`. Automatic
inference never rewrites `.agent-workflow/config.json`; it only affects the
current planning decision. Set `workflow.phaseExecutionMode` to `single-agent`
or configure `runtimePolicy.defaults.executor` to override inference for
deterministic local or CI runs. If `OPEN_ORCHESTRA_ACTIVE_RUNTIME` names an
unknown runtime, workflow planning fails with supported values and the same
override options instead of requiring hidden config edits.

File-based inference (reading `target=` from `AGENTS.md`/`CLAUDE.md`/etc.) and
per-tool environment detection (`CLAUDECODE`, `CODEX_THREAD_ID`,
`CURSOR_TRACE_ID`, etc.) are intentionally **not** used: instruction files
describe which runtimes the project supports, not which one is active right
now, and per-tool env vars can coexist in nested or inherited sessions.

Subagent spawning is fully asynchronous by default. A spawn request returns the
`sessionId`, request artifact, prompt artifact, expected result artifact, status,
next lifecycle commands, and quality warnings, then the parent agent should
return control to the user. The parent should not wait for the child unless the
next parent action is explicitly blocked on that result. Completion is
reconciled later through `runtime spawn-lifecycle`, runtime notifications, or an
explicit `runtime sessions` poll.

Subagent spawning is bounded by `runtimePolicy.delegation.guardrails`.
`maxConcurrentDelegates` is the threshold for simultaneously running delegated
sessions, `maxSpawnsPerTask` limits fan-out for one task, and `limitAction`
controls whether pressure should `queue` or `reject`. With the default `queue`
policy, a phase that cannot acquire capacity is paused as a queued runtime
subagent instead of silently falling back to the parent agent. Resume the
workflow after capacity is released. Manual `runtime spawn-request` calls follow
the same guardrails: `queue` materializes a queued request artifact and session,
while `reject` fails before creating a delegation artifact.

Default local runtime-native guardrails allow 3 concurrent delegated sessions
and 3 spawns per task. The separate SaaS-capacity scheduler defaults to 3 active
runtime leases, 25 queued requests, 2 active requests per provider, and 3 active
requests per runtime within the evaluated platform, tenant, and workspace
policies. Hosted deployments should override those thresholds per tenant and
workspace before enabling runtime-native dispatch.

For multi-squad work, the parent renders one spawn request per independent
squad/role/phase. Each detached session is tracked independently by `sessionId`;
completion order is intentionally non-deterministic. Release aggregation,
handoff review, and QA reconciliation happen at explicit gates or status checks,
not by sequential waits in the parent conversation.

Each phase stores executor provenance in the workflow run and handoff:
execution mode, executor type, phase, role, runtime id, delegation packet path
or spawn request path when one was rendered, session id when available,
fallback reason, and `directProviderApiAllowed=false`. Spawn request artifacts
include the phase, role, session id, parent tool name when applicable, prompt
artifact, expected result artifact, ownership paths, queue status, and the
guardrail evaluation so the parent runtime can prove what was delegated.

Cursor canvas sync is intentionally runtime-specific:

```bash
orchestra cursor canvas status --json
orchestra cursor canvas sync --dry-run --json
orchestra cursor canvas clean --json
```

Use it only when Cursor canvas artifacts should be copied into the workspace for
review. Other runtimes should use `runtime brief`, `runtime delegate-plan`, and
managed bootstrap files instead.

## Invocation Planning

Direct CLI execution is intentionally disabled. Orchestra can render a typed
invocation plan so callers can inspect the command shape before any future
executor is enabled:

- `claude-cli` with `gates=phase` or `gates=all` plans
  `claude --print <prompt> --allowedTools Read Glob Grep`.
- `claude-cli` with `gates=none` plans
  `claude --print <prompt> --allow-dangerously-skip-permissions`.
- `codex-cli`, `opencode-cli`, IDE runtimes, and generic runtimes remain
  runtime-managed or brief-only, so the plan has no command to execute.

Every invocation plan reports `directExecutionEnabled: false` and
`canExecute: false`; the contract is for policy review, UI display, and future
executor hardening, not for spawning tools today.

## Dependency Remediation

Missing tools should be handled as runtime setup problems, not hidden fallback
behavior:

- Missing Codex CLI: install or authenticate Codex, then rerender the brief with
  `orchestra runtime brief --task <id> --runtime codex-cli`.
- Missing OpenCode CLI: install OpenCode and configure its provider credentials
  in OpenCode, then use `--runtime opencode-cli`.
- Missing Gemini credentials: set `GEMINI_API_KEY` or configure
  `--api-key-file` through `orchestra model connect`.
- Missing Ollama server: start Ollama locally or set the configured base URL to
  the reachable OpenAI-compatible endpoint.

The stable inspection commands are:

```bash
orchestra runtime adapters --json
orchestra runtime brief --task <id> --runtime codex-cli --json
orchestra runtime delegate-plan --task <id> --runtime opencode-cli --roles qa --json
orchestra runtime spawn-request --task <id> --role developer --runtime codex-cli --json
orchestra runtime sessions --task <id> --json
orchestra runtime spawn-lifecycle --session <id> --status completed --agent-id <id> --json
orchestra model providers --json
```

## Ollama E2E

The Ollama adapter has an opt-in E2E battery that runs in a temporary workspace
and uses a local OpenAI-compatible endpoint controlled by the test:

```bash
npm run test:e2e:runtime:ollama
```

The test configures `model connect --provider ollama`, runs a developer phase
through provider-backed execution, validates the request body sent to
`/v1/chat/completions`, and checks model provenance events. It intentionally
does not require a real Ollama daemon, so default CI and local development do
not degrade when Ollama is unavailable. Use `ORCHESTRA_OLLAMA_SMOKE=1` for a
separate real-model smoke check.
