OpenProse
Reactor CLI

Configuration

The reactor.yml schema, environment variables, and the global flags every command honors.

Configuration

reactor init writes a fully-commented reactor.yml at the project root. Every command reads it from <project>/reactor.yml. When the file is absent, the documented defaults apply.

The reactor.yml schema

state:
  dir: ./.reactor              # durable state (receipts, world-models, IR cache)

model:
  provider: openrouter         # openrouter (default) | openai | anthropic | google | <custom>
  render_model: google/gemini-3.5-flash
  compile_model: google/gemini-3.5-flash
  temperature: 0
  max_turns: 200
  # base_url: ...               # optional: override the provider's endpoint
  # api_key_env: ...            # optional: read the key from a different env var

sandbox:
  mode: none                   # none (default) | docker
  shell_timeout_ms: 300000

gateways:                      # external-driven entry points
  - node: inbox
    source_id: inbox
    connector:
      type: static             # static | http | file (or a connectors.{cjs,js} plugin)
      id_field: id
      items: [{ id: item-1, body: "the first item" }]

reactors: []                   # optional: a multi-reactor host (see below)

state

KeyDefaultMeaning
state.dir./.reactorThe durable state directory: receipts, world-models, and the compiled IR cache. Resolved to an absolute path rooted at the project dir, so every command agrees on one location regardless of cwd.

model

KeyDefaultMeaning
model.provideropenrouterThe model provider. A built-in (openrouter, openai, anthropic, google) supplies its own endpoint + key env; any other name requires base_url + api_key_env.
model.render_modelgoogle/gemini-3.5-flashThe model used for renders at run/serve time.
model.compile_modelgoogle/gemini-3.5-flashThe model used for the compile sessions. It is part of the IR cache key.
model.temperature0Sampling temperature.
model.max_turns200The per-session turn ceiling.
model.base_url(provider default)Override the OpenAI-compatible base URL. Optional for a built-in; required (with api_key_env) for a custom vendor.
model.api_key_env(provider default)The env var holding the API key (e.g. ANTHROPIC_API_KEY). Optional for a built-in; set it to read from a non-default variable.

The compile model is a component of the content-addressed cache key (contract-set fingerprint, SDK version, model id). Changing it invalidates the cache and forces a recompile.

Choosing a model provider

By default Reactor talks to models through OpenRouter, but it is not bound to it. The CLI drives one bounded @openai/agents session per render/compile step, and any vendor with an OpenAI-compatible Chat Completions endpoint plugs in by naming it in model:. Point at OpenAI, Anthropic, or Google directly -- no OpenRouter account required:

# Anthropic, directly (set ANTHROPIC_API_KEY in your env or a .env)
model:
  provider: anthropic
  render_model: claude-haiku-4-5
  compile_model: claude-haiku-4-5

Each built-in provider resolves to an endpoint + a key env var:

providerEndpointKey env varExample model id
openrouter (default)https://openrouter.ai/api/v1OPENROUTER_API_KEYgoogle/gemini-3.5-flash
openaihttps://api.openai.com/v1OPENAI_API_KEYgpt-4o-mini
anthropicAnthropic Messages API (native, see below)ANTHROPIC_API_KEYclaude-haiku-4-5
googlehttps://generativelanguage.googleapis.com/v1beta/openai/GEMINI_API_KEYgemini-2.5-flash

openrouter, openai, and google are OpenAI-compatible Chat Completions surfaces. anthropic is special: the CLI routes it through Anthropic's native Messages API (via the bundled @openai/agents AI-SDK adapter over @ai-sdk/anthropic), because Anthropic's OpenAI-compat endpoint ignores response_format and can't drive Reactor's structured compile/render. You don't install or wire anything -- provider: anthropic just works, structured outputs and all. An optional base_url points the adapter at a proxy in front of the Messages API.

For any other OpenAI-compatible vendor (or a self-hosted gateway), name it freely and supply both base_url and api_key_env:

model:
  provider: together
  base_url: https://api.together.xyz/v1
  api_key_env: TOGETHER_API_KEY
  render_model: meta-llama/Llama-3.3-70B-Instruct-Turbo
  compile_model: meta-llama/Llama-3.3-70B-Instruct-Turbo

api_key_env also overrides a built-in's key var -- handy when, say, your OpenRouter key lives under a different name. Run reactor doctor to confirm the configured provider's key is visible (it reports the exact env var, never printing the value), and reactor doctor --live to drive one real round-trip against it.

The key is read from the named env var first, then a .env discovered by walking up from the project directory. A missing key fails compile/run/serve with a non-zero exit and a message naming the exact variable to set -- it never silently misdirects you to OpenRouter, and never exits 0 on an auth dead-end.

Claude, two ways. provider: anthropic drives Claude directly through the native Messages API and fully supports the structured compile/render path -- it is the recommended route for Anthropic models. If you already aggregate models through one gateway, provider: openrouter with a render_model/compile_model like anthropic/claude-haiku-4-5 also works. Avoid pointing a base_url at Anthropic's OpenAI-compatible endpoint (https://api.anthropic.com/v1/): it ignores response_format and rejects Reactor's JSON-schema with 400 response_format.json_schema.strict. See the SDK provider guide for the underlying @openai/agents wiring.

sandbox

The sandbox block is the render threat-model knob.

KeyDefaultMeaning
sandbox.modenonenone runs renders in the SDK's cwd-scoped, bounded shell. docker runs each render command in a throwaway, network-disabled container. (A third value, unix-local, is accepted by the config parser but is not yet realized -- it currently behaves as none.)
sandbox.shell_timeout_ms300000The per-command time bound (300 seconds) for the bounded shell.
sandbox.imagenode:22-bookworm-slimThe container image, when mode: docker. Falls back to node:22-bookworm-slim when unset.
sandbox.network(forced off)Accepted for forward-compatibility but not yet honored: the docker runner currently forces --network=none on every render command regardless of this value (network isolation is the threat-model default).

See connectors and sandbox for the full render-isolation behavior, including the Docker-absent fallback.

gateways

Each gateways entry is an external-driven entry point bound to a connector.

KeyMeaning
nodeThe gateway node id (must match a kind: gateway contract).
source_idThe connector source id (defaults to the node id). Keys the durable idempotency cursor.
pollAn optional poll cadence for the gateway.
connectorThe connector definition: its type plus type-specific fields such as id_field and items.

See connectors and sandbox for the built-in connector types (static, http, file) and the connectors.{cjs,js} plugin shape.

reactors

A reactors list hosts N isolated reactors in one serve process. When the list is empty (the default), the project is single-reactor and the top-level state and gateways are that one reactor.

KeyDefaultMeaning
namereactor-<index>The reactor's name, which becomes its HTTP namespace prefix /<name>/....
projectthe project dirThe contracts directory for this reactor.
state_dir<state.dir>/<name>This reactor's isolated durable state directory.
gateways[]This reactor's gateways.

Each entry is isolated: its own contracts directory, state directory, substrate, schedule, and cursors, so one reactor never corrupts another. See the multi-reactor host for how --concurrency parallelizes across reactors.

Environment variables

VariableMeaning
OPENROUTER_API_KEYThe live key for the default provider. Required by compile, run, serve, and trigger when model.provider is openrouter. Read from the process env first, then a .env file discovered from the working directory upward.
<model.api_key_env>The live key for a non-default provider -- OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, or whatever model.api_key_env names. Resolved the same way (env first, then a discoverable .env). See Choosing a model provider.
REACTOR_OFFLINESet to 1 (or true) to force offline mode. Equivalent to the --offline flag.

Global flags

These flags are honored by every command and override the file:

FlagMeaning
--state-dir <path>Override state.dir.
--project <dir>The project directory containing reactor.yml (default .).
--jsonMachine-readable JSON output.
--offlineForce offline mode (sets REACTOR_OFFLINE=1).

On this page