Running Ouroboros with OpenCode

August 10, 2026 · View on GitHub

For installation and first-run onboarding, see Getting Started.

Ouroboros integrates with OpenCode (opencode.ai) — an open-source multi-provider AI coding agent — via two complementary paths:

  1. Subagent Bridge Plugin (primary, recommended): Runs inside an interactive OpenCode session. Ouroboros ouroboros_* MCP tools that emit a _subagent envelope (e.g. ouroboros_qa, ouroboros_lateral_think persona="all") fan out into native OpenCode Task panes — one child session per subagent, rendered inline under the tool call. Zero session-picker pollution, parallel multi-persona dispatch, fresh LLM context per child.
  2. Subprocess Runtime (fallback, headless/CI): Ouroboros launches opencode run --format json as a non-interactive subprocess per task execution. Useful for CLI-driven workflows, batch runs, and environments without an attached OpenCode session.

Both paths share the same specification-first harness (seeds, acceptance criteria, evaluation principles, deterministic exit conditions). Pick the plugin for day-to-day interactive work; pick the subprocess runtime for automation.

No additional Python SDK is required beyond the base ouroboros-ai package.

Model recommendation: OpenCode supports any model available through your configured provider. For best results with Ouroboros workflows, use a frontier-class model (Claude Opus, GPT-5.4, or equivalent) that handles multi-step agentic coding tasks well.

Prerequisites

  • OpenCode installed, configured, and on your PATH (see install steps below)
  • A provider configured in OpenCode (run opencode and complete the first-run setup, or use opencode providers auth <provider>)
  • Python >= 3.12

Note: OpenCode manages its own provider authentication. You do not need to set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variables for Ouroboros — OpenCode handles provider credentials internally via its own configuration at ~/.config/opencode/opencode.jsonc (or opencode.json).

Installing OpenCode

OpenCode is distributed as a standalone binary. Install via the official installer script or npm:

# Recommended: official installer
curl -fsSL https://opencode.ai/install | bash

# Alternative: npm
npm i -g opencode-ai@latest

Verify the installation:

opencode --version

After install, run opencode once to complete first-run provider setup (select a provider and authenticate).

For alternative install methods, see the OpenCode documentation.

Installing Ouroboros

For all installation options (pip, one-liner, from source) and first-run onboarding, see Getting Started. The base ouroboros-ai package includes the OpenCode runtime adapter — no extras are required.

Platform Notes

The OpenCode runtime adapter targets Linux, macOS, and Windows via WSL 2. OpenCode itself supports macOS and native Windows; Ouroboros path handling and subprocess dispatch are portable.

PlatformStatus
Linux (x86_64 / ARM64)Supported
macOS (Apple Silicon / Intel)Supported
Windows (WSL 2)Supported
Windows (native)Best-effort — run inside WSL 2 for the subprocess fallback path

Configuration

ouroboros setup --runtime opencode configures OpenCode integration. At setup time, pick one of two mutually exclusive modes:

ModeWhat it doesUse when
plugin (default)Install bridge plugin + register MCP in opencode.jsoncYou drive work from inside OpenCode — inline Task panes via _subagents dispatch
subprocessWrite subprocess runtime into ~/.ouroboros/config.yamlHeadless ouroboros run, CI, scripted pipelines, no interactive OpenCode session

Why mutually exclusive: if an Ouroboros MCP tool is called inside a opencode run subprocess, the globally registered plugin also fires — duplicate subagent dispatch, wasted tokens. Pick one. To wire both deliberately on the same machine, run ouroboros setup twice with different --opencode-mode values and accept the token cost.

ouroboros setup --runtime opencode                              # interactive picker
ouroboros setup --runtime opencode --opencode-mode plugin       # inside-OpenCode default
ouroboros setup --runtime opencode --opencode-mode subprocess   # headless CI
ouroboros setup --runtime opencode --non-interactive            # accepts default (plugin)

What each mode installs:

plugin

  • Bridge plugin at <opencode_config_dir>/plugins/ouroboros-bridge/ouroboros-bridge.ts (atomic write, content-hashed — no-op if unchanged)
  • Plugin entry in ~/.config/opencode/opencode.jsonc or opencode.json (dedupes stale entries)
  • Ouroboros MCP server in the same file
  • No Claude SDK MCP sidecar mutation; its MCP 1.x profile remains isolated

subprocess

  • orchestrator.runtime_backend: opencode in ~/.ouroboros/config.yaml
  • orchestrator.opencode_cli_path: <auto-detected path> in the same file
  • llm.backend: opencode in the same file

The .jsonc file is rewritten as plain JSON (comments stripped) for compatibility.

Where things live

ConcernFile
Ouroboros runtime settings (backend, CLI path)~/.ouroboros/config.yaml
OpenCode provider / model / MCP / plugins~/.config/opencode/opencode.jsonc (or .json)
Bridge plugin source<opencode_config_dir>/plugins/ouroboros-bridge/ouroboros-bridge.ts

Model selection for OpenCode-backed workflows is configured in OpenCode itself, not in config.yaml.

The plugin hooks OpenCode's tool.execute.after event. When an Ouroboros MCP tool returns a _subagent / _subagents envelope, the plugin:

  1. Spawns one independent child session per subagent (client.session.create + client.session.prompt)
  2. Patches a subtask part into the parent message so the child renders as a native Task pane inline under the original tool call
  3. Fans out up to MAX_FANOUT = 10 children concurrently — each with fresh LLM context (no cross-persona anchoring bias)

Multi-persona example:

ouroboros_lateral_think persona="all"
  → hacker     (child session, Task pane)
  → researcher (child session, Task pane)
  → simplifier (child session, Task pane)
  → architect  (child session, Task pane)
  → contrarian (child session, Task pane)

Environment tunables

VariableDefaultPurpose
OUROBOROS_CHILD_TIMEOUT_MS1200000 (20 min)Per-child wall clock

OUROBOROS_CHILD_TIMEOUT_MS is the only environment knob the bridge reads (opencode/plugin/ouroboros-bridge.ts:38). Retry counts are compile-time constants there — PATCH_RETRIES = 3 and RESOLVE_RETRIES = 5 (:40-41) — and neither is overridable.

See the full plugin guide: OpenCode Subagent Bridge.

Path 2 — Subprocess Runtime (fallback)

For headless, CI, or scripted workflows where no interactive OpenCode session is running, select the subprocess runtime explicitly:

# ~/.ouroboros/config.yaml
orchestrator:
  runtime_backend: opencode
  opencode_cli_path: /usr/local/bin/opencode   # omit if on PATH

llm:
  backend: opencode

Or per-invocation:

uv run ouroboros run workflow --runtime opencode ~/.ouroboros/seeds/seed_abcd1234ef56.yaml

The OpenCodeRuntime adapter launches opencode run --format json --dangerously-skip-permissions as a subprocess, pipes the prompt via stdin, and parses the structured JSON event stream from stdout. orchestrator.opencode_permission_mode defaults to bypassPermissions; seed execution forces that mode for fresh and resumed dispatches.

When to use subprocess over plugin

ScenarioPath
Interactive OpenCode session, want Task panesPlugin
Parallel multi-persona dispatch (lateral_think, qa)Plugin
CI / headless automation, no attached sessionSubprocess
Scripted ouroboros run workflow invocationSubprocess
Debug / reproduce one-shot from terminalSubprocess

Could subprocess do parallel subagent dispatch without the plugin?

Yes, in theory. The orchestrator could spawn N parallel opencode run --format json subprocesses, one per subagent envelope entry, pipe each persona prompt via stdin, collect the stdout JSON event streams, and union-merge the results back into a single envelope.

Sketch:

parent = subprocess(opencode run --format json) ← seed prompt
         └─ hits MCP tool returning _subagents=[hacker, researcher, ...]
orchestrator
  ├─ subprocess(opencode run --format json) ← hacker prompt
  ├─ subprocess(opencode run --format json) ← researcher prompt
  └─ subprocess(opencode run --format json) ← simplifier prompt
         ↓ stdout JSON per child
      merge → parent envelope

Why we do not ship this path:

ConcernPluginSubprocess fan-out
Inline Task pane rendering under parent messageYes (PATCH subtask part into parent)No — each child is a top-level session
Session picker pollution1 parent session, N hidden childrenN+1 visible sessions on every dispatch
Reparenting of child under parent message idYes (direct PATCH against session._client)Not possible without plugin hook
Cold-start latency per childOne in-process client.session.createFull CLI boot + TUI init per spawn
Live progress visible during runYes (native OpenCode rendering)No — child output only surfaces after merge
Shared MCP/provider config inheritanceAutomatic (same process)Re-resolved per subprocess
Works headless / no attached sessionNo (needs running session)Yes

The subprocess runtime stays scoped to its strength — single-shot headless execution. Parallel subagent fan-out is a plugin-only feature by design; emulating it via subprocesses is feasible but strictly worse UX in every attached scenario.

ooo Skill Availability on OpenCode

After running ouroboros setup --runtime opencode, the Ouroboros MCP server is registered in OpenCode's config. The ooo skills are available via MCP tool dispatch within OpenCode sessions.

ooo SkillOpenCode sessionCLI equivalent (Terminal)
ooo interviewYesouroboros init start --llm-backend opencode "your idea"
ooo seedYes(bundled in ouroboros init start)
ooo runYesouroboros run workflow --runtime opencode seed.yaml
ooo statusYesouroboros status execution <execution_id>
ooo evaluateYes(MCP only)
ooo evolveYes(MCP only)
ooo ralphYesMCP-owned ouroboros_ralph; subprocess mode returns a job, plugin mode delegates a child Task
ooo cancelYesouroboros cancel execution <execution_id>
ooo unstuckYes(MCP only)
ooo tutorialYes(MCP only)
ooo welcomeYes(MCP only)
ooo updateYespip install --upgrade ouroboros-ai
ooo helpYesouroboros --help
ooo qaYesouroboros qa
ooo setupYesouroboros setup --runtime opencode
ooo publishYes(no direct ouroboros publish subcommand; skill/runtime flow uses gh CLI)

Ralph note (#528): ooo ralph now calls the MCP-owned ouroboros_ralph surface instead of reimplementing the multi-generation loop with client-side evolve_step polling. In OpenCode subprocess/non-plugin mode it returns a standard background job_id, which is monitored with job tools and cancelled with ouroboros_cancel_job(job_id). In OpenCode plugin mode it returns status=delegated_to_plugin with job_id=None; the bridge dispatches a child Task session instead of creating any local JobManager job, so local Ralph job polling/cancellation tools do not apply to that plugin-delegated run. ouroboros cancel execution <execution_id> remains only for execution sessions and does not cancel Ralph job IDs.

Note on ooo seed vs ooo interview: These are two distinct skills with separate roles. ooo interview runs a Socratic Q&A session and returns a session_id. ooo seed accepts that session_id and generates a structured Seed YAML (with ambiguity scoring). From the terminal, both steps are performed in a single ouroboros init start invocation.

OpenCode uses the shared stateless ouroboros.router resolver for exact ooo and /ouroboros: skill dispatch. Adding or changing a command only requires updating the relevant SKILL.md frontmatter; the runtime keeps logging, message assembly, and MCP invocation local. See Shared ooo Skill Dispatch Router.

Quick Start

For the full first-run onboarding flow (interview -> seed -> execute), see Getting Started.

Verify Installation

opencode --version
ouroboros --help

OpenCode-Specific Strengths

  • Multi-provider support -- use Anthropic, OpenAI, Google, or other providers through a single runtime
  • Built-in provider management -- OpenCode handles its own authentication and provider configuration, no env var setup required
  • Rich tool access -- full suite of file, shell, and search tools (same surface as Claude Code)
  • Native MCP integration -- OpenCode has built-in MCP server support
  • Open-source -- fully open-source, allowing inspection and contribution
  • Session-aware runtime -- Ouroboros preserves OpenCode session handles and resume state across workflow steps

For a side-by-side comparison of all runtime backends, see the runtime capability matrix.

Runtime Differences

OpenCode, Claude Code, and Codex CLI are independent runtime backends with different tool sets, permission models, and provider ecosystems. The same Seed file works with all three, but execution paths may differ.

AspectOpenCodeClaude CodeCodex CLI
What it isOuroboros session runtime backed by OpenCode subprocessAnthropic's agentic coding toolOuroboros session runtime backed by Codex CLI transport
AuthenticationManaged by OpenCode (opencode providers auth)Max Plan subscriptionOpenAI API key
ModelAny model supported by configured providerClaude (via claude-agent-sdk)GPT-5.4 with medium reasoning effort (recommended)
Tool surfaceRead, Write, Edit, Bash, Glob, GrepRead, Write, Edit, Bash, Glob, GrepCodex-native tools (file I/O, shell)
Session modelSession-aware via --session flag and runtime handlesNative Claude session contextSession-aware via runtime handles, resume IDs, and skill dispatch
TransportSubprocess (opencode run --format json), prompt via stdinClaude Agent SDK (direct API)Subprocess (codex executable)
Cost modelProvider API usage chargesIncluded in Max Plan subscriptionOpenAI API usage charges
Tested platformsLinuxLinux, macOSLinux, macOS

Note: The Ouroboros workflow model (Seed files, acceptance criteria, evaluation principles) is identical across runtimes. However, because OpenCode, Claude Code, and Codex CLI have different underlying agent capabilities, tool access, and provider ecosystems, they may produce different execution paths and results for the same Seed file.

CLI Options

Workflow Commands

# Execute workflow (OpenCode runtime)
# Seeds generated by ouroboros init are saved to ~/.ouroboros/seeds/seed_{id}.yaml
uv run ouroboros run workflow --runtime opencode ~/.ouroboros/seeds/seed_abcd1234ef56.yaml

# Debug output (show logs and agent output)
uv run ouroboros run workflow --runtime opencode --debug ~/.ouroboros/seeds/seed_abcd1234ef56.yaml

# Resume a previous session
uv run ouroboros run workflow --runtime opencode --resume <session_id> ~/.ouroboros/seeds/seed_abcd1234ef56.yaml

Seed File Reference

FieldRequiredDescription
goalYesPrimary objective
task_typeNoExecution strategy: code (default), research, or analysis
constraintsNoHard constraints to satisfy
acceptance_criteriaNoSpecific success criteria
ontology_schemaYesOutput structure definition
evaluation_principlesNoPrinciples for evaluation
exit_conditionsNoTermination conditions
metadata.ambiguity_scoreYesMust be <= 0.2

Known Limitations

Session pollution (subprocess runtime only)

Each task execution via opencode run creates a visible session in OpenCode's session history. Long-running workflows with many orchestrator steps will accumulate sessions. This does not affect the plugin path — child sessions created by the bridge are reparented inline as Task panes and do not pollute the picker. See #331 for subprocess reparenting.

Background-job tools are fire-and-forget in plugin mode

ouroboros_start_execute_seed and ouroboros_start_evolve_step are background-job APIs in subprocess mode: they return a job_id that callers poll via ouroboros_job_status / ouroboros_job_result.

In plugin mode, these tools delegate execution to the bridge plugin, which spawns a child session inside the host. The MCP server has no visibility into that child's lifecycle, so:

  • job_id is None (no JobManager record is created)
  • status is "delegated_to_plugin" — not "running" or "queued"
  • ouroboros_job_status(None) / ouroboros_job_result(None) are not useful handles

The bridge manages its own lifecycle: child creation, progress rendering (Task panes), and completion signaling. Callers should check status == "delegated_to_plugin" and rely on the bridge's inline rendering rather than polling.

No interactive mode

The adapter uses opencode run --format json (non-interactive). Features that require interactive OpenCode sessions (e.g., manual approval prompts) are not available during Ouroboros execution.

Permission mode

OpenCode has no multi-value --permission-mode option, but current releases expose --dangerously-skip-permissions. Ouroboros translates bypassPermissions to that native flag on both fresh and --session resume commands. Narrower stored modes do not add the full-bypass flag.

In plugin mode, the bridge creates every delegated child session with an explicit OpenCode permission ruleset of permission="*", pattern="*", action="allow". This is the session-API equivalent of the subprocess bypass flag; plugin resume remains unsupported because the host bridge cannot durably reattach an already-dispatched child.

Troubleshooting

OpenCode not found

Ensure opencode is installed and available on your PATH:

which opencode

If not installed:

curl -fsSL https://opencode.ai/install | bash

Provider not configured

If OpenCode reports a provider error, ensure you have completed first-run setup:

opencode                        # interactive first-run setup
# or
opencode providers auth anthropic   # configure a specific provider

OpenCode manages its own provider credentials — you do not need to set ANTHROPIC_API_KEY or similar environment variables for the Ouroboros integration.

"Providers: warning" in health check

This is normal when using the orchestrator runtime backends. The warning refers to LiteLLM providers, which are not used in orchestrator mode.

"EventStore not initialized"

The database will be created automatically at the active path shown by ouroboros config show.

Cost

Using OpenCode as the runtime backend incurs API charges from your configured provider. Costs depend on:

  • Provider and model selected in OpenCode's configuration
  • Task complexity and token usage
  • Number of tool calls and iterations

Refer to your provider's pricing page for current rates.

Active Conductor and Synapse

OpenCode CLI subprocess sessions are proven Synapse inform/after_turn transports using the same OpenCode session ID. This does not claim live checkpoint redirect or hard replace. OpenCode plugin Task dispatch remains a separate host-owned lifecycle and is not reinterpreted as runtime interruption.

For pollable runs, one read-only observer relays current model/harness, efficiency assurance, bounded Discover targets, dependency/parallel levels, first scheduled ACs, attention, and terminal assurance while the main session remains available. The main host selects the affected AC by meaning, never by a user-supplied internal ID, and speaks naturally in the user's conversation language from canonical English guidance.