Complete reference for ~/.ouroboros/config.yaml and all related environment variables.
Source of truth:
src/ouroboros/config/models.pyandsrc/ouroboros/config/loader.pyRun
ouroboros config initto generate defaults. Edit~/.ouroboros/config.yamldirectly to apply changes.
~/.ouroboros/
├── config.yaml # Main configuration (this document)
├── credentials.yaml # API keys (chmod 600, do not put secrets in config.yaml)
├── ouroboros.db # Legacy SQLite event store (preserved when present)
├── seeds/ # Generated seed YAML files
├── data/
│ └── ouroboros.db # Default configured SQLite event store for new installs
├── logs/
│ └── ouroboros.log # Log output
└── .env # Optional; loaded automatically by the CLI
For Codex-backed Ouroboros workflows:
- Put persistent Ouroboros role overrides in
~/.ouroboros/config.yaml. - Use
ouroboros config --web(orouroboros configin a terminal) to select Use Codex default model for Codex's current default model, or choose Enter another model ID… to pin a model for each pipeline stage, including Execute.~/.codex/config.tomlis for the Codex MCP registration and any user-managed native profiles. - The loader does not hardcode a model for Codex. Every model key defaults to
auto, which resolves Codex-backed lookups to Codex'sdefaultsentinel. A model string you set takes effect only withmodels.pin: true. - Use
llm_profilesandllm_role_profileswhen you want portable task profiles that can map to Codex CLI profiles or to ordinary model settings for other providers.
| Role | config.yaml key |
|---|---|
| Clarification / interview | clarification.default_model |
| Agent execution | execution.default_model |
| QA verdict | llm.qa_model |
| Semantic evaluation | evaluation.semantic_model |
| Consensus simple voting | consensus.models |
| Consensus deliberative roles | consensus.advocate_model, consensus.devil_model, consensus.judge_model |
execution.default_model covers the EXECUTE-stage planning roles (atomicity, decomposition, agent_runtime_implementation) alongside Execute-stage runtime calls. With models.pin: true, an explicit model id (or OUROBOROS_EXECUTION_MODEL) pins those roles. When it is unset or set to default/current, CLI backends choose their own default; LiteLLM retains its provider-qualified semantic model because it has no model-free default.
Recommended baseline: use Use Codex default model. Setup assigns each Ouroboros role a per-invocation reasoning effort (fast: low, standard: medium, deep: high, frontier: xhigh) without pinning a Codex model, so Codex's current default remains in control.
llm_profiles are top-level, provider-neutral task profiles. llm_role_profiles maps logical Ouroboros roles to those profiles. For Codex, the built-in mappings use reasoning_effort, which is passed to codex exec for that call and does not change the user's global model. A user-managed provider profile remains supported and is passed as codex exec --profile <name>. Role mappings preserve each call site's tuned sampling and token settings.
llm_profiles:
fast:
max_turns: 1
temperature: 0.2
providers:
codex:
reasoning_effort: low
litellm:
model: openrouter/openai/gpt-5.3-codex-spark
standard:
max_turns: 3
temperature: 0.3
providers:
codex:
reasoning_effort: medium
deep:
max_turns: 5
temperature: 0.4
providers:
codex:
reasoning_effort: high
claude_code:
model: claude-opus-5
gemini:
model: gemini-2.5-pro
opencode:
model: openai/gpt-5.4
litellm:
model: openrouter/anthropic/claude-opus-5
frontier:
max_turns: 8
temperature: 0.4
providers:
codex:
reasoning_effort: xhigh
llm_role_profiles:
ambiguity: deep
assertion_extraction: fast
brownfield: fast
context_compression: deep
mechanical_detection: fast
question_classification: deep
qa: frontier
brownfield_explore: frontier
clarification: frontier
dependency_analysis: standard
pm_interview: deep
seed_generation: deep
consensus_advocate: deep
consensus_perspective: deep
consensus_vote: deep
ontology_analysis: deep
pm_document: deep
reflect: deep
semantic_evaluation: deep
wonder: frontier
consensus_judge: frontier
agent_runtime: standard
agent_runtime_implementation: standard
agent_runtime_interview: deep
agent_runtime_coordinator: standard
agent_runtime_evaluation: deepResolution order is: explicit request-level model pins, role mapping, profile provider mapping for the active backend, existing *_model field, then backend default behavior.
Codex setup applies those effort values with a per-invocation model_reasoning_effort override. It does not create or select an Ouroboros-owned Codex profile, so an App or CLI model change is automatically inherited. Existing user-created Codex profiles remain available when explicitly selected.
If ~/.codex/config.toml already contains a URL-based Ouroboros MCP server, setup preserves it instead of replacing it with a stdio command block:
[mcp_servers.ouroboros]
url = "http://127.0.0.1:12000/mcp"| Section | Class | Purpose |
|---|---|---|
orchestrator |
OrchestratorConfig |
Runtime backend selection and agent permissions |
llm |
LLMConfig |
LLM-only flow defaults (model selection, permission mode) |
models |
ModelsConfig |
Automatic model selection and the explicit pin switch |
economics |
EconomicsConfig |
PAL Router tier definitions and escalation thresholds |
clarification |
ClarificationConfig |
Phase 0 — Interview / Big Bang settings |
execution |
ExecutionConfig |
Phase 2 — Double Diamond execution settings |
resilience |
ResilienceConfig |
Phase 3 — Stagnation detection and lateral thinking |
evaluation |
EvaluationConfig |
Phase 4 — 3-stage evaluation pipeline settings |
consensus |
ConsensusConfig |
Phase 5 — Multi-model consensus settings |
llm_profiles |
dict[str, LLMTaskProfileConfig] |
Provider-neutral LLM task profiles |
llm_role_profiles |
dict[str, str] |
Logical role to LLM task profile mapping |
persistence |
PersistenceConfig |
SQLite event store settings |
drift |
DriftConfig |
Drift monitoring thresholds |
runtime_controls |
RuntimeControlsConfig |
Long-running workflow liveness and progress controls |
logging |
LoggingConfig |
Log level, path, and verbosity |
boundary |
BoundaryConfig |
Check package boundary of ooo run (on by default) |
Controls how Ouroboros launches and communicates with the agent runtime backend.
orchestrator:
runtime_backend: claude # "claude" | "claude_mcp" | "codex" | "opencode" | "hermes" | "gemini" | "kiro" | "copilot" | "pi" | "omp" | "gjc" | "antigravity" | "grok" | "zcode"
permission_mode: acceptEdits # "default" | "acceptEdits" | "bypassPermissions"
opencode_permission_mode: bypassPermissions
max_parallel_workers: 3 # Maximum concurrent AC workers
cli_path: null # Path to Claude CLI binary; null = resolve from PATH/runtime default
codex_cli_path: null # Path to Codex CLI binary; null = resolve from PATH
opencode_cli_path: null # Path to OpenCode CLI binary; null = resolve from PATH
copilot_cli_path: null # Path to Copilot CLI binary; null = resolve from PATH
pi_cli_path: null # Path to Pi CLI binary; null = resolve from PATH
omp_cli_path: null # Path to OMP (Oh My Pi) CLI binary; null = resolve from PATH
zcode_cli_path: null # Path to zcode.cjs or a zcode executable
default_max_turns: 10| Option | Type | Default | Description |
|---|---|---|---|
runtime_backend |
"claude_mcp" | "claude" | "codex" | "opencode" | "hermes" | "gemini" | "kiro" | "copilot" | "pi" | "omp" | "gjc" | "antigravity" | "grok" | "zcode" |
"claude" |
The agent runtime backend used for workflow execution. claude is the default Agent SDK runtime in an MCP 1.x environment. claude_mcp is the explicit out-of-process CLI worker used by the isolated MCP 2 server. Overridable via OUROBOROS_AGENT_RUNTIME. See runtime capability matrix. |
permission_mode |
"default" | "acceptEdits" | "bypassPermissions" |
"acceptEdits" |
Stored permission preference. Runner-driven seed execution forces the native bypassPermissions equivalent for both fresh and resumed dispatches wherever the backend exposes an approval surface; persisted handles cannot downgrade it. Pi and GJC expose no separate approval flag and run headlessly without an approval dialogue. |
opencode_permission_mode |
"default" | "acceptEdits" | "bypassPermissions" |
"bypassPermissions" |
Permission mode when using the OpenCode runtime. Overridable via OUROBOROS_OPENCODE_PERMISSION_MODE. |
max_parallel_workers |
int >= 1 |
3 |
Maximum Acceptance Criteria workers the adaptive dispatch window may reach. Overridable via OUROBOROS_MAX_PARALLEL_WORKERS. Invalid explicit values fail instead of falling back to the default. The native Claude backend starts at this value and is paced by its RPM/TPM bucket. CLI runtimes whose underlying LLM limits are unknown (hermes, codex, gemini, opencode, ...) start at 1, halve the window on 429 pressure, honor Retry-After, and add one worker after sustained success until this ceiling. |
cli_path |
string | null |
null |
Absolute path to the Claude CLI binary (~ is expanded). When null, the active Claude runtime resolves its normal CLI default. Overridable via OUROBOROS_CLI_PATH. |
codex_cli_path |
string | null |
null |
Absolute path to the Codex CLI binary (~ is expanded). When null, resolved from PATH at runtime. Overridable via OUROBOROS_CODEX_CLI_PATH. |
opencode_cli_path |
string | null |
null |
Absolute path to the OpenCode CLI binary (~ is expanded). When null, resolved from PATH at runtime. Overridable via OUROBOROS_OPENCODE_CLI_PATH. |
copilot_cli_path |
string | null |
null |
Absolute path to the GitHub Copilot CLI binary (~ is expanded). When null, resolved from PATH at runtime. Overridable via OUROBOROS_COPILOT_CLI_PATH. |
pi_cli_path |
string | null |
null |
Absolute path to the Pi CLI binary (~ is expanded). When null, resolved from PATH at runtime. Overridable via OUROBOROS_PI_CLI_PATH. |
omp_cli_path |
string | null |
null |
Absolute path to the OMP (Oh My Pi) CLI binary (~ is expanded). When null, resolved from PATH at runtime. Overridable via OUROBOROS_OMP_CLI_PATH. |
zcode_cli_path |
string | null |
null |
Path to the Zcode app-bundle zcode.cjs script, a standalone script, or a directly executable zcode wrapper. Official app bundles use their bundled Electron/Node runtime. Resolution falls back to the macOS app bundle, then PATH. Overridable via OUROBOROS_ZCODE_CLI_PATH. |
ourocode_cli_path |
string | null |
null |
Absolute path to the ourocode CLI binary (~ is expanded). Used by the LLM-only ourocode backend; when null, resolved from PATH at runtime. Overridable via OUROBOROS_OUROCODE_CLI_PATH. |
dsh_cli_path |
string | null |
null |
Absolute path to the DeepSeek Harness ACP server binary dsh-acp-demo (~ is expanded). Used by the LLM-only dsh backend; when null, resolved from PATH at runtime. Overridable via OUROBOROS_DSH_CLI_PATH. |
dsh_config_path |
string | null |
null |
Absolute path to the trusted Cordis composition the dsh backend loads. Required for that backend — it fails closed rather than guessing, and a relative path is rejected because it would resolve against the untrusted project cwd. Overridable via OUROBOROS_DSH_CONFIG_PATH. See the DeepSeek Harness guide. |
default_max_turns |
int >= 1 |
10 |
Default maximum number of turns per agent execution task. |
Defaults for LLM-only flows (interview, seed generation, QA, analysis). The orchestrator section governs agent runtime execution; the llm section governs model-level LLM calls within the orchestration pipeline.
llm:
backend: claude_code
permission_mode: default
opencode_permission_mode: acceptEdits
qa_model: auto
dependency_analysis_model: auto
ontology_analysis_model: auto
context_compression_model: auto| Option | Type | Default | Description |
|---|---|---|---|
backend |
"claude" | "claude_code" | "litellm" | "codex" | "opencode" | "hermes" | "gemini" | "kiro" | "copilot" | "goose" | "pi" | "omp" | "ourocode" | "gjc" | "zcode" | "dsh" |
"claude_code" |
Default backend for LLM-only flows. Overridable via OUROBOROS_LLM_BACKEND. ourocode and dsh are LLM-only and are not valid for orchestrator.runtime_backend. dsh additionally requires orchestrator.dsh_config_path; see the DeepSeek Harness guide. The runtime alias deepseek_harness is not accepted here — this field is validated against the literals above, so persist dsh. |
permission_mode |
"default" | "acceptEdits" | "bypassPermissions" |
"default" |
Permission mode for non-OpenCode LLM flows. Overridable via OUROBOROS_LLM_PERMISSION_MODE. |
opencode_permission_mode |
"default" | "acceptEdits" | "bypassPermissions" |
"acceptEdits" |
Permission mode for OpenCode-backed LLM flows. Overridable via OUROBOROS_OPENCODE_PERMISSION_MODE. |
qa_model |
string |
"auto" |
Model used for post-execution QA verdict generation. Overridable via OUROBOROS_QA_MODEL. |
dependency_analysis_model |
string |
"auto" |
Model used for AC dependency analysis. Overridable via OUROBOROS_DEPENDENCY_ANALYSIS_MODEL. |
ontology_analysis_model |
string |
"auto" |
Model used for ontological analysis. Overridable via OUROBOROS_ONTOLOGY_ANALYSIS_MODEL. |
context_compression_model |
string |
"auto" |
Model used for workflow context compression. Overridable via OUROBOROS_CONTEXT_COMPRESSION_MODEL. |
Every model field in llm, clarification, resilience, evaluation, and
consensus defaults to auto and follows the rules in models.
When llm.backend is ourocode, model fields are OUROCODE_MODEL selectors,
not raw Anthropic model IDs. The supported selectors are claude, claude_api,
codex, and gemini; default and shipped Claude default pins resolve to
claude so journal metadata matches the ACP child process.
Most users need no model setting at all, and one switch when they do.
- Default:
auto. Every role runs the latest model of its tier (frugal, standard, frontier) on the backend you use. A new model release needs no config change. - One switch for every role.
ouroboros config set models.default frontier(orfrugal,standard, a model id, or back toauto). For a single command, pass--modeltoouroboros run,ouroboros interview, orouroboros pm, for exampleouroboros run seed.yaml --model frontier. Tier names work on every backend; Claude aliases such asopusmean something only on Claude backends. - See what runs.
ouroboros config showprints a models table (role, tier, backend, resolved model, source) under amodels: auto (pin off),models: pinned, ormodels: <value> for every role (<source>)header, and lists saved per-role ids that are not applied underignored (pin off)with the hintset models.pin: true to use.ouroboros config show --jsoncarries the same data undermodels. - Pin for research.
ouroboros config set models.pin true(or--pin-modelsfor one command) runs the per-role ids saved in the role fields below.litellmandcopilottake provider-owned ids, so they use saved ids whether or not pin is on.
A fresh config from ouroboros setup or ouroboros config init writes
models.default: auto and no per-role model ids. Copilot setup also writes
the model you pick from Copilot's catalog, because Copilot needs an id from
that catalog.
How every role's model is chosen. The default, auto, runs each role on the
latest model of its tier for the active backend, so a new model release needs
no config change.
models:
default: auto # auto | frugal | standard | frontier | <model id>
pin: false # true = run the model ids persisted in role fields| Option | Type | Default | Description |
|---|---|---|---|
default |
string |
"auto" |
auto picks each role's own tier. A tier name (frugal, standard, frontier) applies that tier to every role, and a model id applies that model to every role. Overridable via OUROBOROS_MODEL. |
pin |
bool |
false |
Run the concrete model ids persisted in role fields (llm.qa_model, clarification.default_model, and the rest) and in the OUROBOROS_*_MODEL variables. While off, those ids are ignored with one warning per process, except on litellm and copilot (see below). Turn on for research or reproducibility. Overridable via OUROBOROS_PIN_MODELS (1/0). |
Each role belongs to one tier: interview, seed, PM, brownfield explore, semantic evaluation, Wonder, Reflect, lateral thinking, and the consensus roles are frontier; Execute, validation, QA, assertion extraction, mechanical detection, dependency analysis, ontology analysis, and context compression are standard; the brownfield repository scan is frugal. How a tier becomes a model depends on the backend:
| Backend | auto resolves to |
|---|---|
claude, claude_mcp |
The Claude CLI alias for the tier (haiku, sonnet, opus), which the CLI maps to its newest model. |
litellm (including OpenRouter) |
The configured model string, used as-is whether or not pin is on. With nothing configured, the shipped Anthropic id for the role. auto is never sent to LiteLLM. |
copilot |
The configured model string (from Copilot's own model catalog), used as-is. With nothing configured, Copilot's default model. |
| Every other backend (Codex, OpenCode, Gemini, Goose, Kiro, Hermes, Pi, OMP, gjc, Antigravity, Grok, Zcode, ourocode, dsh, host) | default: the CLI's own configured model. |
A model passed for one invocation (for example an explicit MCP model argument,
or --model on ouroboros run, interview, and pm) always applies.
llm_profiles define reusable task profiles outside any single provider. llm_role_profiles chooses which profile a logical Ouroboros task role should use.
Common role keys include clarification, seed_generation, assertion_extraction, qa, semantic_evaluation, wonder, reflect, consensus_vote, consensus_advocate, consensus_judge, dependency_analysis, context_compression, ontology_analysis, and mechanical_detection.
Profile fields:
| Field | Type | Description |
|---|---|---|
model |
string | null |
Portable model override used when no provider-specific model is set. |
temperature |
float | null |
Portable temperature override. |
max_tokens |
int | null |
Portable token limit override. |
top_p |
float | null |
Portable nucleus sampling override. |
max_turns |
int | null |
Portable CLI-agent turn budget where supported. |
reasoning_effort |
"low" | "medium" | "high" | null |
Portable effort dial for providers with native reasoning-effort support. A provider-specific mapping may additionally use Codex xhigh. |
providers |
dict |
Backend-specific overrides keyed by codex, claude_code, gemini, opencode, litellm, or provider aliases such as openrouter. |
Provider-specific fields use the same keys plus profile. profile is currently backend-native metadata; Codex maps it to codex exec --profile <name>, while non-Codex adapters ignore it unless they add native profile support later. Role-based resolution uses these profile fields for model/native-profile routing, max_turns, and reasoning_effort; it intentionally preserves request-level temperature, max_tokens, and top_p so existing task-specific tuning does not change just because a role was annotated. Explicit CompletionConfig.profile requests use the profile's full sampling/token envelope. ouroboros setup --runtime codex installs missing default role mappings and preserves existing profile definitions, existing Codex provider model pins, and skips role mappings where explicit legacy model overrides are already configured.
Codex agent-runtime tasks also use these mappings. Runtime handles with session_role: implementation, coordinator, interview, or evaluation resolve through agent_runtime_<session_role>; tasks without a role fall back to agent_runtime. Explicit runtime models still win and are passed with --model instead of --profile.
Configures the PAL Router (Progressive Adaptive LLM): cost tiers, escalation on failure, and downgrade on success.
economics:
default_tier: frugal # "frugal" | "standard" | "frontier"
escalation_threshold: 2 # Retry attempt escalation begins; then +1 tier per retry
downgrade_success_streak: 5 # Consecutive successes before downgrading tier
tiers:
frugal:
cost_factor: 1
intelligence_range: [9, 11]
models:
- provider: openai
model: gpt-5.1-codex-mini
- provider: google
model: gemini-2.0-flash
- provider: anthropic
model: claude-haiku-4-5
use_cases:
- routine_coding
- log_analysis
- stage1_fix
standard:
cost_factor: 10
intelligence_range: [14, 16]
models:
- provider: openai
model: gpt-5-codex
- provider: anthropic
model: claude-sonnet-4-6
- provider: google
model: gemini-2.5-pro
use_cases:
- logic_design
- stage2_evaluation
- refactoring
frontier:
cost_factor: 30
intelligence_range: [18, 20]
models:
- provider: openai
model: gpt-5.2
- provider: anthropic
model: claude-opus-5
use_cases:
- consensus
- lateral_thinking
- big_bang| Option | Type | Default | Description |
|---|---|---|---|
default_tier |
"frugal" | "standard" | "frontier" |
"frugal" |
The starting tier used when no task-specific override applies. |
escalation_threshold |
int >= 1 |
2 |
The retry attempt at which tier escalation begins. From this attempt onward the tier climbs one notch per retry (progressive), capped at the frontier tier. Top-level and untrusted decomposed work start at the base tier. Only a decomposed child with explicit trust authorization starts one tier lower, so that trusted-child ladder may require one additional retry to reach the same frontier ceiling. Current live decomposition supplies no such trust authorization. |
downgrade_success_streak |
int >= 1 |
5 |
Number of consecutive successes at the current tier before downgrading to the previous tier. |
tiers |
dict[str, TierConfig] |
(see above) | Tier definitions keyed by name. Model-tier routing keeps each tier's shape and cost, but the model ids listed here apply only with models.pin: true or on backends that keep configured model ids (litellm, copilot); otherwise each tier runs the latest model of that tier (Claude: haiku/sonnet/opus; runtimes that choose their own model: default). A resumed run replays the models it started on. |
TierConfig fields:
| Field | Type | Description |
|---|---|---|
cost_factor |
int >= 1 |
Relative cost multiplier (1 = frugal, 10 = standard, 30 = frontier). |
intelligence_range |
[int, int] |
Min/max intelligence score for this tier (min must be ≤ max). |
models |
list[ModelConfig] |
Models available in this tier. |
use_cases |
list[str] |
Descriptive tags for which task types this tier is suited for. |
ModelConfig fields:
| Field | Type | Description |
|---|---|---|
provider |
string |
Provider name (openai, anthropic, google, openrouter). |
model |
string |
Model identifier. Provider formats differ: Anthropic uses claude-opus-5, while OpenRouter uses openrouter/anthropic/claude-opus-5. |
Controls Phase 0 — the Socratic Interview and seed generation.
clarification:
ambiguity_threshold: 0.2 # Interview completes when ambiguity score <= this value
max_interview_rounds: 10 # Hard ceiling on clarification rounds
model_tier: standard # "frugal" | "standard" | "frontier"
default_model: auto| Option | Type | Default | Description |
|---|---|---|---|
ambiguity_threshold |
float [0.0, 1.0] |
0.2 |
Maximum ambiguity score to allow seed generation to proceed. Interview loops until the score falls at or below this value. |
max_interview_rounds |
int >= 1 |
10 |
Maximum number of question-answer rounds regardless of ambiguity score. |
model_tier |
"frugal" | "standard" | "frontier" |
"standard" |
PAL tier used for the clarification phase. |
default_model |
string |
"auto" |
Default model for interview and seed generation (see models). Overridable via OUROBOROS_CLARIFICATION_MODEL. |
Controls Phase 2 — the Double Diamond execution loop.
execution:
max_iterations_per_ac: 10 # Maximum execution iterations per acceptance criterion
retrospective_interval: 3 # Iterations between automatic retrospectives
auto_evaluate: true # Evaluate completed runs, including failed runs with artifacts
auto_evolve: true # Continue rejected evaluations through bounded Ralph
auto_evolve_max_generations: 3 # Automatic Ralph budget, clamped to 1..10
default_model: null # null/default/current = let the selected runtime choose
project_guidance: # Explicit project-local execution guidance allowlist
- team| Option | Type | Default | Description |
|---|---|---|---|
max_iterations_per_ac |
int >= 1 |
10 |
Maximum number of execution iterations for a single acceptance criterion before the system escalates or declares failure. |
retrospective_interval |
int >= 1 |
3 |
Number of iterations between automatic retrospective evaluations. |
auto_evaluate |
bool |
true |
Enqueue formal 3-stage evaluation after a completed background run has a session and artifact. This includes unsuccessful AC execution; handler-level failures without an evaluable run are excluded. Applies to MCP ooo run and to the terminal ouroboros run, which waits for the evaluation; ouroboros run --auto-evaluate/--no-auto-evaluate overrides it for one run. |
auto_evolve |
bool |
true |
When formal evaluation returns an explicit rejection, seed a generation-1 lineage snapshot and enqueue a bounded Ralph continuation. Per-call auto_evolve overrides this setting. The terminal ouroboros run follows the same rule and waits for the Ralph job; ouroboros run --auto-evolve/--no-auto-evolve overrides it for one run. |
auto_evolve_max_generations |
int |
3 |
Maximum generations for automatically chained Ralph work. Values are clamped to Ralph's supported 1..10 range. |
run_verify_commands |
bool |
true |
Check an AC's success contract (expected artifacts and verify_command) before accepting it. While on, the evidence verifier may also replay allowlisted commands the worker ran, in a copy of the workspace under the execution sandbox (writes only inside the copy, no network; nothing is replayed where the sandbox is unavailable), to corroborate tests_passed and commands_run claims the transcript alone cannot prove (see Verifier Evidence Policy). Off: nothing is executed by the harness. |
verify_command_timeout_seconds |
int >= 1 |
600 |
Timeout for each verify_command run and each replayed command. |
exec_sandbox |
bool |
true |
Confine the commands the controller runs on its own authority (verifier replay) with the execution sandbox: writes (content, names and metadata) only beneath the workspace copy and a per-run temp directory, no non-loopback network, an allowlisted environment (sandbox-exec on macOS; Landlock plus a seccomp metadata filter on Linux, where metadata inside the copy is read-only too; a per-run AppContainer on Windows, where loopback reaches only the command's own processes, the NUL device is unavailable, batch files (.cmd, .bat) cannot run and are left indeterminate, and reads are limited to what is granted). On Windows the controller's interpreter and the live dependency trees a workspace copy links to are granted read and execute to one Ouroboros capability SID; that grant is persistent, is recorded in ~/.ouroboros/exec-sandbox/read-grants.jsonl, and is removed with python -c "from ouroboros.runtime.exec_sandbox import remove_persistent_read_grants as r; print(r())" (run it while no Ouroboros command is running). Where no backend works, nothing is run and the outcome is indeterminate (sandbox_unavailable). Unsafe when false: those commands run unconfined, able to write anywhere the user can and to use the network. OUROBOROS_EXEC_SANDBOX overrides it; a project .env cannot. The effective value is sealed when a run starts, and resuming it with a different value is refused. |
default_model |
string | null |
null |
Optional Execute-stage model pin, applied with models.pin: true (and always on litellm/copilot). null, an empty value, "auto", "default", or "current" means automatic selection: Claude runs the standard tier alias (sonnet) and other runtimes keep their own current/default model. OUROBOROS_EXECUTION_MODEL has highest precedence, and a present empty env var explicitly clears the saved pin for that process. |
project_guidance |
list[string] |
[] |
Guidance IDs loaded from <project-root>/.ouroboros/guidance/<id>/GUIDANCE.md and appended to execution system prompts. This option is config-only and has no environment-variable override. |
default_policy |
"ask" | "efficient" | "quality_first" |
"ask" |
Persistent default execution policy for fresh runs. ask preserves the host's interactive efficiency prompt exactly. efficient resolves omitted arguments to adaptive/observe and quality_first to quality_first/off without asking. Explicit invocation arguments always win, resumed sessions keep their persisted immutable contract, and strict frugality assurance never derives from this setting. |
project_guidance is an explicit allowlist. Ouroboros does not scan the repository,
user home directory, Codex skills, Claude configuration, or other provider-local
instruction stores. For the example above, the only loaded file is:
<project-root>/.ouroboros/guidance/team/GUIDANCE.md
IDs must be safe single path segments containing letters, numbers, ., _, or
-. Files must be non-empty UTF-8 text, are resolved in deterministic ID order,
and are limited to 16 KiB per file and 32 KiB in total. Missing files, path or
symlink escapes, invalid encoding, and size violations fail before execution.
The Seed and its Acceptance Criteria remain authoritative. Guidance cannot grant tools, change sandbox or approval policy, alter evaluation requirements, bypass evaluation, or redefine acceptance criteria. A run persists guidance paths, hashes, and sizes without storing the raw body; resume reloads those persisted IDs and fails closed if the files changed. A runtime that ignores system prompts also rejects runs with enabled project guidance.
The check package boundary of ooo run (CLI and ouroboros_execute_seed),
on by default for every run it applies to (a fresh run; a resumed session
keeps the boundary it started with): before the worker starts, a read-only
model call writes executable checks for the acceptance criteria, and each
check is admitted only if it behaves as declared on the current tree. After the worker stops, the package decides
the criteria it covers, before the session's terminal status is recorded; the
existing verifier's verdict is kept as advisory for those criteria and decides
the others. Edits the worker makes to test configuration inside the workspace
(for example pytest.ini, conftest.py, or Django's tests/test_sqlite.py)
can make the existing verifier accept; the check package's oracle checks are
unaffected, because they call the implementation through the product harness
and do not read workspace test configuration (a model-written script check
that runs the project's test runner would read it).
MCP results: ouroboros_start_execute_seed reports the closed-value summary
(check_package, check_package_status, package_verdict, legacy_verdict,
reconciliation, verification_coverage) in its job result, with or without
auto_evaluate. The receipts of ouroboros_start_execute_seed and of a
background ouroboros_execute_seed call carry check_package and
check_package_status: pending (off and not_run when the check package is
off; the decision is then the session's terminal status, which the package
reconciled before it was recorded). A resumed session's receipt reports the
mode the run started with, read from its journal before the receipt is
returned; if the journal cannot be read, the resume is refused. An execution
dispatched to the OpenCode plugin (a child session outside this process) is
not governed: its result carries check_package: not_applied with
check_package_reason: plugin_dispatch.
Before the package is frozen, each oracle's stated expected values are
compared with a reference implementation the constructor writes in the same
reply, run in the same isolated target processes: a held-out case that
disagrees is dropped (oracle_inconsistent; an oracle left with no held-out
case is dropped too, since only a held-out case can verify a pass), and a
criterion whose reference
does not reproduce a case the constructor declared as stated in the Seed, or
has no reference that runs, is reported as unverified
(reference_contradicts_stated_case,
reference_unavailable). This catches a slip in a stated value; it does not
catch a misreading of the criterion that the cases and the reference share.
Library entry points. An oracle's target is any importable callable of the
project, including a classmethod. A case input that is an object rather than
a JSON value is written as {"$symbol": "package.module.Name"} (at any depth
in the arguments or a method's init); the harness imports it and passes the
object. An oracle may declare setup, calls of callables defined in the
project with JSON arguments (for Django, django.conf.settings.configure
then django.setup), which the harness makes before it resolves the target.
A setup call that fails, or an input that names nothing, leaves the base run
indeterminate, never a reproduction failure. A returned set compares as the
list of its items sorted by their JSON text. The reference check makes no
setup call and gives the reference each object input as its dotted path.
Command oracles take neither.
What an oracle observation proves. The candidate's code runs inside each
target process, so it can write the process's report itself (the frame
nonce is a parsing convention, not an authority boundary). A report is
therefore evidence of what the candidate's code computed for the inputs it
was sent, never proof that the bound function ran: the identity of the bound
callable is not proven, and a candidate that computes the right outputs
elsewhere in its code passes. That is why every oracle
must carry at least one held-out case (a reply without one is refused,
oracle_without_held_out_case) and why only a passing held-out case of a
reproduction oracle verifies a criterion: its inputs reach the candidate only
in the final verification, so matching its expected value means computing the
rule's output for an input the candidate had never seen. A report can only
make a case pass, never fail one the candidate's code passes, and admission
runs the base checkout's code, so neither admission nor a failure depends on
it.
Admission is per check: a reproduction check that already passes on the
current tree, or a preservation check that already fails on it, is excluded on
its own (repro_passes_on_base, preservation_fails_on_base) and the rest of
the package is admitted. A criterion keeps the package's authority only while
an admitted check covers it (for a bug-fix criterion, an admitted reproduction
check). For the criteria left without an admitted check, one more constructor
call, before the worker starts, asks for replacement checks and says why the
earlier ones were excluded; the replacements go through the same admission.
The constructor is asked for a check for every criterion. Whether an
admitted check covers a criterion is the only thing that decides who judges
it; nothing classifies criteria by kind, and the reason a criterion was left
uncovered is descriptive only.
Every criterion the package cannot verify (no admitted check, or no binding) is decided by the existing verifier: its rejection fails the run (exit 1) and is shown as legacy-decided. Only a criterion neither verifier had evidence for (for example the existing verifier's transcript was unavailable) is accepted as unverified; the run then prints an insufficient-verification warning, as it does when half or more of the criteria were not decided by the package.
boundary:
check_package: off # on | off; unset = on
constructor_timeout_seconds: 600
check_timeout_seconds: 120
max_construction_attempts: 2| Option | Type | Default | Description |
|---|---|---|---|
check_package |
"on" | "off" | unset |
unset (on) | off turns the check package off for every run; unset or on keeps it on. --check-package/--no-check-package and OUROBOROS_CHECK_PACKAGE take precedence, in that order. A bare YAML on/off is accepted. If config.yaml cannot be read, the check package is off for runs that set neither the flag nor the variable, since the unreadable file may hold an off; with no config.yaml at all the default (on) applies. The setting does not depend on telemetry. |
constructor_timeout_seconds |
int (30..3600) |
600 |
Wall-clock budget of one constructor call. |
check_timeout_seconds |
int (5..1800) |
120 |
Per-check timeout during admission and verification. |
max_construction_attempts |
int (1..5) |
2 |
Package versions tried before the worker starts; a version that is not admitted is superseded by the next. The one replacement call for criteria left without an admitted check adds a version outside this budget. |
Checks are model-written Python scripts. They run on throwaway copies of the
project, with the project's virtualenv interpreter when one is found (else
python3), a per-check timeout, and confined by the execution sandbox (see
execution.exec_sandbox): a check can write only beneath its own copy and a
scratch directory that is removed afterwards, has no non-loopback network, and
gets an environment built from an allowlist (PATH, the locale variables,
TZ, a few Python I/O settings, and on Windows the system variables a process
needs; HOME and the temp directory in the scratch directory; VIRTUAL_ENV
when the interpreter is a virtualenv's). The same applies to the processes
that run the implementation under an oracle check and to the constructor's
reference implementation. Where the sandbox cannot confine a check, the check
is undecided and nothing runs. Reads are not restricted: a check can read
files you can read, and on macOS (where sandbox-exec cannot deny
KERN_PROCARGS2) the arguments and environment of your other processes,
Ouroboros included; under Landlock on Linux it cannot. Turn the check package
off where that matters. A project .env cannot set
OUROBOROS_CHECK_PACKAGE.
Constructor runtimes: the constructor's model call must keep no session on
disk (its reply holds the held-out cases), so it runs only on runtimes with a
no-persistence mode: Claude Code (--no-session-persistence, through the Agent
SDK or the claude -p worker of --runtime claude-cli) and Codex CLI
(codex exec --ephemeral). With any other runtime the run has no check
package (constructor_session_not_ephemeral:<backend>, before any model call)
and the existing verifier decides every criterion, deterministically.
A resumed run keeps the mode and the boundary settings it started with
(check_timeout_seconds is recorded on the run's
boundary.check_package.enabled journal record): changing the switch or the
config between the start and the resume changes nothing for that run.
On resume the package decision is recovered from the journal alone. A journal
the run could not have written (a missing, duplicated or conflicting record,
or a gap in the package versions) leaves every criterion undecided
(boundary_record_missing) and runs no check. When the same process still
holds the admitted package, its full decision runs, held-out cases included.
In another process the held-out cases are gone (they are never written to
disk), so no check runs: covered criteria are undecided
(held_out_unavailable) and the existing verifier decides the rest.
Controls Phase 3 — stagnation detection and lateral thinking.
resilience:
stagnation_enabled: true
lateral_thinking_enabled: true
lateral_model_tier: frontier # "frugal" | "standard" | "frontier"
lateral_temperature: 0.8
wonder_model: auto
reflect_model: auto| Option | Type | Default | Description |
|---|---|---|---|
stagnation_enabled |
bool |
true |
Whether stagnation detection is active. When false, the system does not check for SPINNING / OSCILLATION / NO_DRIFT / DIMINISHING_RETURNS patterns. |
lateral_thinking_enabled |
bool |
true |
Whether lateral thinking persona rotation is active when stagnation is detected. |
lateral_model_tier |
"frugal" | "standard" | "frontier" |
"frontier" |
PAL tier used for lateral thinking calls. Frontier is the default because creative re-framing requires high model capability. |
lateral_temperature |
float [0.0, 2.0] |
0.8 |
LLM sampling temperature for lateral thinking prompts. Higher values produce more divergent outputs. |
wonder_model |
string |
"auto" |
Model for the Wonder phase (divergent exploration). Overridable via OUROBOROS_WONDER_MODEL. |
reflect_model |
string |
"auto" |
Model for the Reflect phase (convergent synthesis). Overridable via OUROBOROS_REFLECT_MODEL. |
Controls Phase 4 — the 3-stage evaluation pipeline.
evaluation:
stage1_enabled: true # Currently inert in config.yaml; see below
stage2_enabled: true # Currently inert in config.yaml; see below
stage3_enabled: true # Currently inert in config.yaml; see below
satisfaction_threshold: 0.8 # Currently inert; the pipeline gate is hardcoded to 0.8
uncertainty_threshold: 0.3 # Currently inert in config.yaml; see below
semantic_model: auto
assertion_extraction_model: auto| Option | Type | Default | Description |
|---|---|---|---|
stage1_enabled |
bool |
true |
Currently inert in config.yaml. Runtime builders do not copy this field into PipelineConfig. |
stage2_enabled |
bool |
true |
Currently inert in config.yaml. Runtime builders do not copy this field into PipelineConfig. |
stage3_enabled |
bool |
true |
Currently inert in config.yaml. Runtime builders do not copy this field into PipelineConfig. |
satisfaction_threshold |
float [0.0, 1.0] |
0.8 |
Currently inert. The field is validated but the pipeline compares Stage 2 scores against a hardcoded 0.8; changing this value does not change the gate. See Evaluation Pipeline Guide. |
uncertainty_threshold |
float [0.0, 1.0] |
0.3 |
Currently inert in config.yaml. Runtime builders do not copy it into TriggerConfig. |
semantic_model |
string |
"auto" |
Model used for Stage 2 semantic evaluation. Overridable via OUROBOROS_SEMANTIC_MODEL. |
assertion_extraction_model |
string |
"auto" |
Model used for extracting verification assertions from seed criteria. Overridable via OUROBOROS_ASSERTION_EXTRACTION_MODEL. |
Configuration boundary: the top-level
evaluation.stage1_enabled,stage2_enabled,stage3_enabled, anduncertainty_thresholdkeys are schema-validated placeholders, not runtime controls. The similarly named direct-PythonPipelineConfig.stage*_enabledfields andTriggerConfig.uncertainty_thresholdare separate and active when explicitly supplied toEvaluationPipeline; see Disabling Stages and Trigger Configuration.
Controls Phase 5 — multi-model consensus voting and deliberation.
Inert fields in
evaluationandconsensus. Eight fields in these two sections are schema-only: they validate, persist, and appear inouroboros config show, but no production code reads them. Inevaluation:stage1_enabled,stage2_enabled,stage3_enabled,satisfaction_threshold, anduncertainty_threshold. Inconsensus:min_models,threshold, anddiversity_required. Each is marked in its field table below with what actually controls the behaviour instead. The model fields in both sections are wired.
consensus:
min_models: 3 # Inert — runtime requires 2 successful post-filter votes
threshold: 0.67 # Inert — runtime ratio threshold defaults to 0.66
diversity_required: true # Currently inert — see the field table below
models: [auto]
advocate_model: auto
devil_model: auto
judge_model: auto| Option | Type | Default | Description |
|---|---|---|---|
min_models |
int >= 2 |
3 |
Currently inert. After reviewer-independence filtering, simple consensus separately requires at least two successfully collected votes; this top-level field is not wired to that rule. |
threshold |
float [0.0, 1.0] |
0.67 |
Currently inert. Runtime simple consensus compares approvals divided by successful post-filter votes with direct-Python ConsensusConfig.majority_threshold (default 0.66); this top-level field is not copied into it. |
diversity_required |
bool |
true |
Currently inert. The field exists on ConsensusConfig and in the schema, but nothing reads it. Provider diversity depends on actual adapter routing; neither this flag nor differently named roster entries attest it. See Evaluation Pipeline Guide. |
models |
list[string] |
["auto"] |
Model roster for Stage 3 simple voting. auto repeats the consensus role's model three times; on litellm it keeps the shipped OpenRouter roster (openrouter/openai/gpt-4o, openrouter/anthropic/claude-opus-5, openrouter/google/gemini-2.5-pro). With llm.backend: litellm, use provider/model or openrouter/provider/model. With llm.backend: codex, use Codex/OpenAI model IDs such as gpt-5.4. Overridable via OUROBOROS_CONSENSUS_MODELS (comma-separated). |
advocate_model |
string |
"auto" (litellm: "openrouter/anthropic/claude-opus-5") |
Model that argues in favor of the proposed solution in deliberative consensus. With llm.backend: codex, this can be a Codex/OpenAI model ID such as gpt-5.4. Overridable via OUROBOROS_CONSENSUS_ADVOCATE_MODEL. |
devil_model |
string |
"auto" (litellm: "openrouter/openai/gpt-4o") |
Model that argues against (devil's advocate) in deliberative consensus. With llm.backend: codex, this can be a Codex/OpenAI model ID such as gpt-5.4. Overridable via OUROBOROS_CONSENSUS_DEVIL_MODEL. |
judge_model |
string |
"auto" (litellm: "openrouter/google/gemini-2.5-pro") |
Model that renders a final verdict after deliberation. With llm.backend: codex, this can be a Codex/OpenAI model ID such as gpt-5.4. Overridable via OUROBOROS_CONSENSUS_JUDGE_MODEL. |
Configuration boundary:
consensus.min_modelsandconsensus.thresholdare schema-validated placeholders. Runtime simple consensus hardcodes a minimum of two successful post-filter votes and reads the separate direct-PythonConsensusConfig.majority_threshold. Changing these YAML keys does not change either rule.Backend note: With
llm.backend: litellm, consensus models typically go through OpenRouter/LiteLLM and require the corresponding provider credentials (commonlyOPENROUTER_API_KEY). Withllm.backend: codex, the configured model strings are sent through Codex CLI instead.
Controls the SQLite event store.
persistence:
enabled: true
database_path: data/ouroboros.db # Relative to ~/.ouroboros/| Option | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
true |
Whether event sourcing is active. Setting to false disables all persistence — not recommended for production use. |
database_path |
string |
"data/ouroboros.db" |
Path shared by the MCP runtime, status/resume recovery commands, and TUI. Relative paths resolve from ~/.ouroboros/. Existing installs keep using a legacy ~/.ouroboros/ouroboros.db until the configured target exists, preserving prior history during migration. |
Controls drift monitoring thresholds. Drift measures how far execution has strayed from the original seed (goal + constraint + ontology weighted formula).
drift:
warning_threshold: 0.3 # Drift score that triggers a warning
critical_threshold: 0.5 # Drift score that triggers intervention| Option | Type | Default | Description |
|---|---|---|---|
warning_threshold |
float [0.0, 1.0] |
0.3 |
Drift score above which a warning event is emitted. |
critical_threshold |
float [0.0, 1.0] |
0.5 |
Drift score above which the system triggers a critical intervention (re-alignment step). Must be ≥ warning_threshold. |
Controls long-running MCP/evolution liveness. These defaults are intended for normal local use: complex productive generations can run for hours, silent hangs are bounded, and repeated activity without material progress is eventually stopped.
runtime_controls:
mcp_tool_timeout_seconds: 0 # 0 = no adapter wall-clock cap
generation_idle_timeout_seconds: 7200 # No EventStore activity for 2 hours
generation_no_progress_timeout_seconds: 14400 # Activity but no material progress for 4 hours
generation_safety_timeout_seconds: 0 # Optional final hard cap; 0 = disabled
watchdog_poll_seconds: 15.0Material progress is stricter than liveness. Heartbeats, messages, and tool calls keep the generation from being considered idle; phase changes, workflow status changes, stage/subtask completion, and terminal execution events reset the no-progress timer.
Recommended tuning examples:
# Long-running local work
runtime_controls:
generation_idle_timeout_seconds: 7200
generation_no_progress_timeout_seconds: 43200
# Strict CI / bounded automation
runtime_controls:
generation_idle_timeout_seconds: 900
generation_no_progress_timeout_seconds: 3600
generation_safety_timeout_seconds: 14400| Option | Type | Default | Description |
|---|---|---|---|
mcp_tool_timeout_seconds |
float >= 0 |
0 |
Adapter-level MCP timeout for progress-aware tools such as ouroboros_evolve_step. Keep 0 for normal use so the watchdog, not wall-clock time, decides liveness. |
generation_idle_timeout_seconds |
float >= 0 |
7200 |
Timeout when no lineage/execution activity is observed. 0 disables idle detection. |
generation_no_progress_timeout_seconds |
float >= 0 |
14400 |
Timeout when activity continues but material progress does not. 0 disables no-progress detection. |
generation_safety_timeout_seconds |
float >= 0 |
0 |
Optional final hard cap for a generation. 0 disables the hard cap. |
watchdog_poll_seconds |
float > 0 |
15.0 |
EventStore polling interval for generation watchdog decisions. |
Controls log output.
logging:
level: info # "debug" | "info" | "warning" | "error"
log_path: logs/ouroboros.log # Relative to ~/.ouroboros/
include_reasoning: true| Option | Type | Default | Description |
|---|---|---|---|
level |
"debug" | "info" | "warning" | "error" |
"info" |
Minimum log level. Set to "debug" for verbose output. |
log_path |
string |
"logs/ouroboros.log" |
Path to the log file, relative to ~/.ouroboros/. The resolved absolute path is ~/.ouroboros/logs/ouroboros.log. |
include_reasoning |
bool |
true |
Whether to log LLM reasoning traces. Disable to reduce log volume when reasoning output is not needed. |
API keys are stored separately from the main config. This file is created with chmod 600 permissions by ouroboros config init.
# ~/.ouroboros/credentials.yaml
providers:
openrouter:
api_key: YOUR_OPENROUTER_API_KEY
base_url: https://openrouter.ai/api/v1
openai:
api_key: YOUR_OPENAI_API_KEY
anthropic:
api_key: YOUR_ANTHROPIC_API_KEY
google:
api_key: YOUR_GOOGLE_API_KEYAlternative — environment variables (recommended for CI/CD):
export ANTHROPIC_API_KEY="sk-ant-..."
export OPENAI_API_KEY="sk-..."
export OPENROUTER_API_KEY="sk-or-..."Environment variables take precedence over credentials.yaml.
All environment variables have higher priority than the corresponding config.yaml value.
| Variable | Overrides | Description |
|---|---|---|
OUROBOROS_AGENT_RUNTIME |
orchestrator.runtime_backend |
Active runtime backend (claude_mcp for Claude CLI, claude for the isolated SDK runtime, or another supported runtime). |
OUROBOROS_AGENT_PERMISSION_MODE |
orchestrator.permission_mode |
Stored permission preference; runner-driven seed execution forces the native bypassPermissions equivalent for fresh and resumed dispatches on approval-aware backends. Pi and GJC have no separate approval flag. |
OUROBOROS_OPENCODE_PERMISSION_MODE |
orchestrator.opencode_permission_mode |
Stored OpenCode preference. Seed execution still forces bypassPermissions, translated to --dangerously-skip-permissions. |
OUROBOROS_EXEC_SANDBOX |
execution.exec_sandbox |
Execution sandbox for controller-run commands; on by default. off (or 0, false, no) is unsafe: verifier replay then runs unconfined, able to write outside its workspace copy and to use the network. Honored only from trusted sources (process environment, ~/.ouroboros/.env); a project .env cannot set it. |
OUROBOROS_MODEL_TIER_ROUTING |
(routing kill switch) | Model-tier routing is enabled by default. Set to 0, off, or false (case- and whitespace-insensitive) to disable routing and emit no routing events. |
OUROBOROS_SHADOW_REPLAY |
(experiment arm) | Default OFF. Only 1, true, or on arms the opt-in shadow-baseline harness. Current live decompositions lack deterministic MECE attestation and are skipped before baseline model dispatch; bundled runtimes also lack the complete filesystem/external-effect isolation attestation, so production emits no shadow baseline today. |
OUROBOROS_MAX_PARALLEL_WORKERS |
orchestrator.max_parallel_workers |
Requested maximum concurrent Acceptance Criteria workers for parallel execution. Must be a positive integer. |
OUROBOROS_MAX_CONCURRENCY |
(initial fan-out estimate) | Overrides the backend-aware starting window. The legacy name is retained for compatibility; the value is no longer a permanent cap in runner-owned execution. Live 429/success feedback may shrink or grow the window, never above OUROBOROS_MAX_PARALLEL_WORKERS. Must be a positive integer; blank/invalid values are ignored. |
OUROBOROS_<BACKEND>_RPM |
(rate budget) | Per-backend requests-per-minute ceiling for the shared dispatch rate bucket. <BACKEND> is the runtime name (the same value you set for runtime_backend / OUROBOROS_AGENT_RUNTIME) upper-cased with non-alphanumerics collapsed to _ (e.g. OUROBOROS_HERMES_RPM, OUROBOROS_CODEX_RPM, OUROBOROS_OPENCODE_RPM). Internal *_cli adapter handles (hermes_cli, codex_cli, gemini_cli, copilot_cli) canonicalize to these names, so the user-facing key always applies. Dormant unless set. Must be a positive integer; blank/invalid values are ignored. |
OUROBOROS_<BACKEND>_TPM |
(rate budget) | Per-backend tokens-per-minute ceiling for the shared dispatch rate bucket (same naming as _RPM). Dormant unless set. Must be a positive integer; blank/invalid values are ignored. |
OUROBOROS_BACKEND_LIMITS |
(config path) | Path to the backend-limits YAML file (default ~/.ouroboros/backend_limits.yaml). See Backend concurrency & rate limits. |
OUROBOROS_CLI_PATH |
orchestrator.cli_path |
Path to the Claude CLI binary. |
OUROBOROS_CODEX_CLI_PATH |
orchestrator.codex_cli_path |
Path to the Codex CLI binary. |
OUROBOROS_OPENCODE_CLI_PATH |
orchestrator.opencode_cli_path |
Path to the OpenCode CLI binary. |
OUROBOROS_PI_CLI_PATH |
orchestrator.pi_cli_path |
Path to the Pi CLI binary. |
OUROBOROS_OMP_CLI_PATH |
orchestrator.omp_cli_path |
Path to the OMP (Oh My Pi) CLI binary. |
OUROBOROS_OUROCODE_CLI_PATH |
orchestrator.ourocode_cli_path |
Path to the ourocode CLI binary used by the LLM-only ourocode backend. |
OUROBOROS_DSH_CLI_PATH |
orchestrator.dsh_cli_path |
Path to the dsh-acp-demo binary used by the LLM-only dsh backend. |
OUROBOROS_DSH_CONFIG_PATH |
orchestrator.dsh_config_path |
Absolute path to the trusted Cordis composition the dsh backend loads. Required by that backend. |
OUROBOROS_CHECK_PACKAGE |
boundary.check_package |
on or off for the ooo run check package boundary (on by default); overrides config, and is overridden by --check-package/--no-check-package. Only the exact value on turns it on: any other set value (off, an alias such as 1, true, yes or ON, empty or whitespace) means off. Not accepted from a project .env. |
OUROBOROS_SKIP_VERSION_CHECK |
(none) | Controls the Claude Agent SDK per-call version compatibility check. Defaults to "1" (skip the check, saving ~0.3-0.8 s per LLM call). Set to "0" to re-enable the check for debugging version-mismatch issues. Maps to CLAUDE_AGENT_SDK_SKIP_VERSION_CHECK internally. |
| Variable | Overrides | Description |
|---|---|---|
OUROBOROS_LLM_BACKEND |
llm.backend |
Default LLM backend for non-agent flows. |
OUROBOROS_LLM_PERMISSION_MODE |
llm.permission_mode |
Permission mode for LLM flows. |
OUROBOROS_QA_MODEL |
llm.qa_model |
Model for post-execution QA. |
OUROBOROS_DEPENDENCY_ANALYSIS_MODEL |
llm.dependency_analysis_model |
Model for AC dependency analysis. |
OUROBOROS_ONTOLOGY_ANALYSIS_MODEL |
llm.ontology_analysis_model |
Model for ontological analysis. |
OUROBOROS_CONTEXT_COMPRESSION_MODEL |
llm.context_compression_model |
Model for context compression. |
Every OUROBOROS_*_MODEL variable applies only with OUROBOROS_PIN_MODELS=1
(or models.pin: true), except on litellm and copilot; see models.
A project .env cannot set any of them.
| Variable | Overrides | Description |
|---|---|---|
OUROBOROS_MODEL |
models.default |
auto, a tier name, or a model id for every role. |
OUROBOROS_PIN_MODELS |
models.pin |
1 runs persisted model ids; 0 resolves automatically. |
OUROBOROS_CLARIFICATION_MODEL |
clarification.default_model |
Model for interview and seed generation. |
OUROBOROS_WONDER_MODEL |
resilience.wonder_model |
Model for the Wonder phase. |
OUROBOROS_REFLECT_MODEL |
resilience.reflect_model |
Model for the Reflect phase. |
OUROBOROS_SEMANTIC_MODEL |
evaluation.semantic_model |
Model for Stage 2 semantic evaluation. |
OUROBOROS_ASSERTION_EXTRACTION_MODEL |
evaluation.assertion_extraction_model |
Model for assertion extraction. |
OUROBOROS_CONSENSUS_MODELS |
consensus.models |
Comma-separated model roster for Stage 3 voting. |
OUROBOROS_CONSENSUS_ADVOCATE_MODEL |
consensus.advocate_model |
Advocate model for deliberative consensus. |
OUROBOROS_CONSENSUS_DEVIL_MODEL |
consensus.devil_model |
Devil's advocate model for deliberative consensus. |
OUROBOROS_CONSENSUS_JUDGE_MODEL |
consensus.judge_model |
Judge model for deliberative consensus. |
| Variable | Default | Description |
|---|---|---|
OUROBOROS_EXECUTION_MODEL |
null (runtime default) |
Model used for agent execution inside the MCP evolve loop. Applies to runtimes that expose a per-call model override; unset it to preserve automatic runtime selection. |
OUROBOROS_VALIDATION_MODEL |
null (runtime default) |
Model used for import/validation fix passes during MCP evolution. Applies to runtimes that expose a per-call model override; unset it to preserve automatic runtime selection. |
OUROBOROS_EVOLVE_STAGE1 |
"true" |
Stage 1 mechanical checks (lint/build/test from .ouroboros/mechanical.toml, authored by the detector when missing) for an evolve generation whose output has no ### Task N markers. On by default because these executed checks are the only thing that can approve such a generation; semantic review there is advisory feedback. Set to "false" (or "0") to skip them: every such generation is then unverified, never approved. Accepted values are true/1 and false/0; any other value is logged and ignored. Honored only from trusted sources (process environment, ~/.ouroboros/.env); a project .env cannot set it. |
OUROBOROS_MCP_TOOL_TIMEOUT_SECONDS |
runtime_controls.mcp_tool_timeout_seconds |
Adapter-level MCP timeout for progress-aware tools. 0 disables the wall-clock cap. |
OUROBOROS_GENERATION_IDLE_TIMEOUT_SECONDS |
runtime_controls.generation_idle_timeout_seconds |
Idle timeout when no generation/execution activity is observed. |
OUROBOROS_GENERATION_NO_PROGRESS_TIMEOUT_SECONDS |
runtime_controls.generation_no_progress_timeout_seconds |
Timeout when activity continues without material progress. |
OUROBOROS_GENERATION_SAFETY_TIMEOUT_SECONDS |
runtime_controls.generation_safety_timeout_seconds |
Optional final hard cap for one generation. |
OUROBOROS_WATCHDOG_POLL_SECONDS |
runtime_controls.watchdog_poll_seconds |
EventStore polling interval for watchdog decisions. |
OUROBOROS_GENERATION_TIMEOUT |
legacy alias | Backwards-compatible alias for generation_no_progress_timeout_seconds. It no longer creates a separate hard 2-hour MCP adapter timeout. Prefer runtime_controls in config.yaml for persistent tuning. |
| Variable | Default | Description |
|---|---|---|
OUROBOROS_LOG_MODE |
"dev" |
Logging output format. "dev" = human-readable console output; "prod" = structured JSON (suitable for log aggregation). |
OUROBOROS_AGENTS_DIR |
null |
Path to a directory of custom agent .md prompt files. When set, overrides the bundled agents from the installed package. Useful for developing custom agent personas without reinstalling. |
OUROBOROS_WEB_SEARCH_TOOL |
"" |
MCP tool name to use for web search during the Big Bang interview (e.g., mcp__tavily__search). An empty string disables web-augmented interview. Only applicable when running with an MCP-capable host. |
| Variable | Description |
|---|---|
ANTHROPIC_API_KEY |
Anthropic API key (Claude models). |
OPENAI_API_KEY |
OpenAI API key (Codex CLI, GPT models). |
GOOGLE_API_KEY |
Google API key (Gemini models used in frugal and standard tiers). |
OPENROUTER_API_KEY |
OpenRouter API key (multi-provider model access for consensus). |
Ouroboros plans delivery fan-out — the parallel execution of acceptance criteria — and is responsible for adapting it to the connected LLM backend's concurrency and rate limits rather than relying on the agent runtime to throttle itself. Two independent controls govern this, and every pre-flight value is configurable without source-level changes:
- Adaptive fan-out:
max_concurrencyis the pre-flight starting estimate (the legacy field name is retained for compatibility), whileorchestrator.max_parallel_workersis the hard controller ceiling. Unknown CLI runtimes start at 1. A short/generic 429 or explicit concurrency rejection halves the window;Retry-Afterpauses new provider entrances and is saturated at 24 hours before clock arithmetic; three successful completions add one worker. The complete AIMD policy is part of the durable execution-semantics fingerprint. Explicit usage/quota exhaustion stays on the durable PAUSED → resume path and is never converted into a concurrency retry. - Rate budget (
requests_per_minute/tokens_per_minute): a shared sliding-window bucket that paces dispatch across all concurrent workers. For non-Claude runtimes it is dormant until you declare a budget.
Each dimension is resolved independently, highest precedence first:
- Environment variables —
OUROBOROS_MAX_CONCURRENCY(initial estimate, any backend) and per-backendOUROBOROS_<BACKEND>_RPM/OUROBOROS_<BACKEND>_TPM. - Config file —
~/.ouroboros/backend_limits.yaml(path overridable viaOUROBOROS_BACKEND_LIMITS). - Built-in registry — Claude's ceilings; otherwise the serialize-by-default initial value 1.
The config file is loaded lazily, cached by mtime (edits apply without a restart), and is
fully fault-tolerant: a missing, malformed, or non-regular file is ignored and resolution falls
back to the registry. Backend keys are canonicalized, so aliases (anthropic, claude_code)
map to claude. Only positive integers are honored; 0/negative/blank values are ignored so an
invalid value never silently replaces the serialize-by-default starting estimate.
# Fallback applied to any backend without its own entry below.
default:
max_concurrency: 1
backends:
# Override the native Claude ceilings without touching source.
claude:
requests_per_minute: 40
tokens_per_minute: 32000
# Declare a CLI runtime's starting fan-out estimate and rate budget.
# Live feedback still controls the window within max_parallel_workers.
# Use the runtime name you select with `runtime_backend` (hermes, codex,
# gemini, copilot, opencode, goose, pi, kiro, gjc) — the `*_cli` adapter handles
# canonicalize to these, so either form resolves to the same entry.
hermes:
max_concurrency: 4
requests_per_minute: 20
tokens_per_minute: 60000A flat top-level mapping (backend → fields, without the backends: wrapper) is also accepted.
# ~/.ouroboros/config.yaml
orchestrator:
runtime_backend: claude
logging:
level: infoorchestrator:
runtime_backend: codex
codex_cli_path: /usr/local/bin/codex # omit if codex is already on PATH
llm:
backend: codex
logging:
level: info# ~/.ouroboros/config.yaml
orchestrator:
runtime_backend: codex
codex_cli_path: /usr/local/bin/codex
models:
pin: true # run the ids below instead of Codex's own default
llm:
backend: codex
qa_model: gpt-5.4
clarification:
default_model: gpt-5.4
evaluation:
semantic_model: gpt-5.4
consensus:
advocate_model: gpt-5.4
devil_model: gpt-5.4
judge_model: gpt-5.4This is the recommended Ouroboros-side pattern for Codex users who pin models. Without models.pin: true these ids are ignored and Codex runs its own default. Keep ~/.codex/config.toml limited to the MCP/env block created by setup.
# ~/.ouroboros/config.yaml
orchestrator:
runtime_backend: opencode
opencode_cli_path: /usr/local/bin/opencode # omit if opencode is already on PATH
llm:
backend: opencode
logging:
level: infoOpenCode supports multiple model providers (Anthropic, OpenAI, Google, and others). Model selection is configured in OpenCode itself (~/.config/opencode/opencode.jsonc or opencode.json), not in config.yaml. The orchestrator.opencode_permission_mode defaults to bypassPermissions since OpenCode runs non-interactively via opencode run --format json. The llm.opencode_permission_mode defaults to acceptEdits, but the factory forces bypassPermissions for interview/seed use cases to avoid CLI sandbox blocking.
# ~/.ouroboros/config.yaml
orchestrator:
runtime_backend: copilot
copilot_cli_path: null # omit if `copilot` is already on PATH
llm:
backend: copilot
clarification:
default_model: claude-opus-4.6 # example live-discovered Copilot IDThe Copilot CLI runtime is unique in that ouroboros setup --runtime copilot live-discovers the available models from the GitHub Copilot models API at setup time. There is no llm.default_model contract: setup removes that key and writes the selected dotted Copilot ID into supported per-role fields that are absent or still carry shipped defaults, while preserving explicit user overrides. Re-run setup after GitHub publishes new models. Authentication uses gh auth login; no separate API key is required.
Model-ID normalization is catalog-gated. map_to_copilot_model() first accepts
an exact Copilot ID, then removes the known openrouter/anthropic/ prefix or
applies an explicit alias, and finally converts only the trailing Anthropic
version separator (claude-opus-4-8 → claude-opus-4.8). Every derived value
must exist in the discovered or bundled Copilot catalog before it is returned.
The current direct and OpenRouter Opus defaults therefore resolve to
claude-opus-5; unknown IDs remain unchanged so Copilot emits its normal
unavailable-model error instead of silently choosing another model. See the
Copilot CLI runtime guide for full details.
# ~/.ouroboros/config.yaml
orchestrator:
runtime_backend: pi
pi_cli_path: null # omit if `pi` is already on PATH
llm:
backend: piPi is available as an agent runtime backend and, when the Pi LLM adapter is installed, an LLM-only backend for interview, ambiguity scoring, seed-extraction, and structured JSON flows. ouroboros setup --runtime pi records the Pi executable and installs a managed Pi extension at ~/.pi/agent/extensions/ouroboros-ooo-bridge.ts, so interactive Pi/roach-pi sessions can route exact-prefix ooo ... input back into Ouroboros after Pi restart or /reload. The Pi LLM adapter supports structured response_format requests through prompt-level JSON/schema instructions plus adapter-side extraction and validation; Pi does not expose a Codex-style native --output-schema hard-enforcement flag. The runtime uses documented JSON mode (pi --mode json <prompt>) and preserves Pi native session IDs for targeted resume.
# ~/.ouroboros/config.yaml
orchestrator:
runtime_backend: omp
omp_cli_path: null # omit if `omp` is already on PATH
llm:
backend: ompOMP (Oh My Pi) is available as an agent runtime backend and an LLM-only backend for interview, ambiguity scoring, seed-extraction, and structured JSON flows. ouroboros setup --runtime omp records the OMP executable and installs a managed OMP extension at ~/.omp/agent/extensions/ouroboros-ooo-bridge.ts, so interactive OMP sessions can route exact-prefix ooo ... input back into Ouroboros after an OMP restart (dispatch timeout: OUROBOROS_OMP_BRIDGE_TIMEOUT_MS). The OMP LLM adapter supports structured response_format requests through prompt-level JSON/schema instructions plus adapter-side extraction and validation; OMP does not expose a hard --output-schema flag. The runtime uses documented JSON mode (omp --mode json <prompt>) and resumes prior sessions natively with --resume <id>. OMP selects its own model (roles smol/slow/plan) unless an explicit --model override is passed; the generic default sentinel is never forwarded. See the OMP CLI runtime guide.
orchestrator:
runtime_backend: claude
permission_mode: acceptEdits
opencode_permission_mode: bypassPermissions
max_parallel_workers: 3
cli_path: null
codex_cli_path: null
opencode_cli_path: null
pi_cli_path: null
omp_cli_path: null
ourocode_cli_path: null
default_max_turns: 10
llm:
backend: claude_code
permission_mode: default
opencode_permission_mode: acceptEdits
qa_model: claude-sonnet-4-6
dependency_analysis_model: claude-sonnet-4-6
ontology_analysis_model: claude-sonnet-4-6
context_compression_model: gpt-4
economics:
default_tier: frugal
escalation_threshold: 2
downgrade_success_streak: 5
tiers:
frugal:
cost_factor: 1
intelligence_range: [9, 11]
models:
- provider: openai
model: gpt-5.1-codex-mini
- provider: google
model: gemini-2.0-flash
- provider: anthropic
model: claude-haiku-4-5
use_cases: [routine_coding, log_analysis, stage1_fix]
standard:
cost_factor: 10
intelligence_range: [14, 16]
models:
- provider: openai
model: gpt-5-codex
- provider: anthropic
model: claude-sonnet-4-6
- provider: google
model: gemini-2.5-pro
use_cases: [logic_design, stage2_evaluation, refactoring]
frontier:
cost_factor: 30
intelligence_range: [18, 20]
models:
- provider: openai
model: gpt-5.2
- provider: anthropic
model: claude-opus-5
use_cases: [consensus, lateral_thinking, big_bang]
clarification:
ambiguity_threshold: 0.2
max_interview_rounds: 10
model_tier: standard
default_model: claude-opus-5
execution:
max_iterations_per_ac: 10
retrospective_interval: 3
resilience:
stagnation_enabled: true
lateral_thinking_enabled: true
lateral_model_tier: frontier
lateral_temperature: 0.8
wonder_model: claude-opus-5
reflect_model: claude-opus-5
evaluation:
stage1_enabled: true # Currently inert in config.yaml
stage2_enabled: true # Currently inert in config.yaml
stage3_enabled: true # Currently inert in config.yaml
satisfaction_threshold: 0.8 # Currently inert; score gate is hardcoded to 0.8
uncertainty_threshold: 0.3 # Currently inert in config.yaml
semantic_model: claude-opus-5
assertion_extraction_model: claude-sonnet-4-6
consensus:
min_models: 3 # Inert; runtime needs 2 successful post-filter votes
threshold: 0.67 # Inert; runtime ratio threshold defaults to 0.66
diversity_required: true # Currently inert
models:
- openrouter/openai/gpt-4o
- openrouter/anthropic/claude-opus-5
- openrouter/google/gemini-2.5-pro
advocate_model: openrouter/anthropic/claude-opus-5
devil_model: openrouter/openai/gpt-4o
judge_model: openrouter/google/gemini-2.5-pro
persistence:
enabled: true
database_path: data/ouroboros.db
drift:
warning_threshold: 0.3
critical_threshold: 0.5
runtime_controls:
mcp_tool_timeout_seconds: 0
generation_idle_timeout_seconds: 7200
generation_no_progress_timeout_seconds: 14400
generation_safety_timeout_seconds: 0
watchdog_poll_seconds: 15.0
logging:
level: info
log_path: logs/ouroboros.log
include_reasoning: true