Quickstart
Scaffold, compile, and run a reactor project end to end.
Quickstart
This walks the full path: reactor init to scaffold a project, reactor doctor to check the environment offline, reactor compile to freeze the intelligence, then reactor serve to drive the scaffold's static gateway to a real receipt.
If you are an agent onboarding on behalf of a user, the centralized, ordered setup path -- keyless proof first, then init/doctor/compile, then go live, then where contracts live -- is in OpenProse Setup. This page is the CLI-local version of the same flow.
Install
Prefer a project-local install. No root, no global binary collisions, and the live render peers (@openai/agents, zod) resolve from the project tree. Call the binaries through npx:
npm install --save-dev @openprose/reactor-cli @openprose/reactor @openai/agents zod
# then: `npx reactor …` / `npx reactor-devtools …`@openprose/reactor is the SDK engine the CLI drives, and a real dependency of @openprose/reactor-cli -- the line above just makes it explicit alongside the two live-render peers. None of these pull a model provider or a key. Zero runtime deps live in the SDK core; doctor, init, the whole observability suite, and the @openprose/reactor-devtools replay viewer need neither key nor peers.
To touch the keyless replay with no install at all -- the fastest proof that the receipts are real:
npx -p @openprose/reactor-devtools reactor-devtools --example masked-relay --describeA global install is an alternative, but -g can collide with other tools' binaries and is EACCES-prone on Linux/WSL. If you go that route, install the SDK first and add the peers: npm i -g @openprose/reactor @openprose/reactor-cli @openprose/reactor-devtools @openai/agents zod.
Requires Node >=20 (the SDK's engines floor). reactor --version prints the CLI version (0.2.0), not the SDK version (0.3.0) -- expected, not a mismatch.
Scaffold a project
reactor init writes a minimal, compilable project: a gateway, a responsibility that subscribes to it, a reactor.yml, a .gitignore, and a short README.
npx reactor init my-project
cd my-projectThe scaffold is the smallest end-to-end shape with a real edge. The inbox gateway accepts external arrivals and materializes them as a set. The digest responsibility subscribes to that set, so when the inbox moves the digest re-renders, and only then.
Your contracts live as *.prose.md files under the scaffold's src/. That is where you author the standing truths the reactor maintains -- see Contracts for the authored surface.
init refuses to overwrite existing files by default. Pass --force to clobber a directory that already contains scaffold files.
Check your environment
reactor doctor runs fully offline and reports node version, SDK resolvability and version, live-key presence (it never prints the key), live-dep presence, the SKILL bundle, the sandbox mode, whether the state directory is writable, and the compiled-IR freshness.
npx reactor doctorreactor doctor
node v22.3.0 (ok)
sdk @openprose/reactor@0.3.0 (resolved)
offline mode not forced
live key present (OPENROUTER_API_KEY)
live dep @openai/agents: ok
live dep zod: ok
skill bundle present (/abs/my-project/node_modules/@openprose/...)
sandbox mode none
state dir /abs/my-project/.reactor (writable)
compiled IR not compiled -- run `reactor compile`
status: healthy-for-offline
live: READY -- key + model peers + SKILL present; `reactor compile`/`run` can renderAdd --live to probe one live smoke render against the real provider. The keyless surface (everything but compile/run/serve/trigger) works even when the live key, the peers, and the SKILL bundle are absent.
Compile
compile runs the intelligent compile sessions (Forme topology, per-node canonicalizer, postconditions) and freezes them into the content-addressed IR cache. It needs a live key (OPENROUTER_API_KEY) plus the @openai/agents and zod peers.
export OPENROUTER_API_KEY=... # doctor confirms it's present, never echoes it
npx reactor compileThe cache key is (contract-set fingerprint, SDK version, model id) -- cost is never part of cache identity, so an unchanged contract set recompiles at zero session cost (a cache hit). To check freshness without compiling (handy in CI), use --check, which exits non-zero when the cache is stale.
npx reactor compile --check # exits 1 right after init, before the first compileReading the exit code in CI? Check $? from the bare command -- do not pipe if you need the status. A pipe reports the last command's exit, so a STALE failure silently looks like a pass.
Inspect the compiled DAG
Once compiled, the offline observability commands work with no key. topology prints the resolved DAG.
npx reactor topology # the compiled DAG (inbox -> digest)Drive the static gateway
The scaffold's inbox gateway uses a static connector: its seeded items are ingested by the serve continuity loop, not by a bare boot-and-drain. Use reactor serve here, not reactor run -- serve polls the gateway and stages the seeded arrivals, which moves the inbox fingerprint and wakes digest. (reactor run is the one-shot drain for graphs whose connectors emit on their own; on a static scaffold it would boot, find nothing newly arrived, and exit without rendering.)
serve boots the durable host, runs the continuity loop, and binds the built-in HTTP surface. It stays up until you stop it with Ctrl-C.
npx reactor serve --http 8080serve --http binds 127.0.0.1 by default and ships no auth in v1. POST /trigger/<node> is unauthenticated, so anything that can reach the port can wake a node and cause model spend. Only expose it externally (--host 0.0.0.0) behind a reverse proxy or network policy that adds auth and rate-limiting.
On the first tick the static connector ingests the seeded items, so the gateway and digest both render. In another shell you can read the trail and the standing cost:
npx reactor status # standing compile cost beside the run cost
npx reactor receipts list # the gateway + digest receipts
npx reactor receipts cost # cost rolled up by surprise_causeThen replay your own run's receipt ledger -- keyless, no model call:
npx reactor-devtools .reactor --describeEvery receipt carries a surprise_cause. A node that re-wakes but whose inputs did not move memo-skips at zero render cost, so a cost spike is always a real change propagating. Benchmarks are openly pending -- the proof is the receipts and the keyless replay, not a number in our marketing.
Next steps
OpenProse Setup
The centralized agent-first path: keyless proof, init to doctor to compile, go live, and where contracts live.
Configuration
Every reactor.yml key, the environment variables, and the offline flag.
Compile, run, serve
The three core verbs in depth, the compile cache, and the durable daemon.
Connectors and sandbox
Gateways, connectors with idempotency cursors, and the render sandbox.
Reactor DevTools
The keyless replay viewer: dispositions, cost-by-surprise, and chain-verify.
Reactor CLI
The reference driver for the @openprose/reactor SDK. It compiles a .prose project and serves it as a durable, cost-observable daemon -- twelve commands, four global flags, three exit codes.
Configuration
The reactor.yml schema, environment variables, and the global flags every command honors.