01 / NPM
Node launcher
npm install -g opencode-rust
Requires Node 18+. opr is a dispatching launcher here.
Rust port · MIT licensed
The open source AI coding agent, rebuilt as a native binary. Terminal UI, CLI and HTTP server — no Docker, no runtime, no container to contain.
$ opr
# entry command; binary is `opencode`
> audit the storage layer for schema drift
▸ read crates/opencode-storage/src/schema.rs
▸ grep ALL_MIGRATIONS
▸ tool 22 built-ins + live MCP in one registry
✓ migrations replay on every connect
✓ history spilled to SQLite — sessions, messages, parts
>
01 / Install
Twenty-two built-in tools and every live MCP tool land in one registry, resolved per turn. Permissions are scoped per path, last matching rule wins.
01 / NPM
npm install -g opencode-rust
Requires Node 18+. opr is a dispatching launcher here.
02 / HOMEBREW
brew install vakandi/tap/opencode-rust
Builds from source with cargo install, so the first install compiles.
03 / SOURCE
git clone https://github.com/vakandi/opencode-rust && ./install.sh
Fingerprint-stamped: an unchanged tree skips the rebuild. --force defeats the stamp.
BEFORE FIRST RUN
Set a provider key, for example export ANTHROPIC_API_KEY=...
SURFACE NOTE
opr is not identical across installers. Through npm it is a dispatcher, so opr --some-flag becomes opencode tui --some-flag. Through Homebrew it is a plain symlink, so opencode tui --some-flag is rejected. Both behaviours are intentional.
02 / Capabilities
The original engine kept conversation history in RAM, re-derived the full tool schema on every step, and never evicted per-directory state. Docker existed to contain that leak. Five teams of five agents pinned a MacBook Pro M5 at 99% CPU — the container was the limit, not the workload.
01
Five surfaces over the same engine.
02
Full session lifecycle with lineage preserved.
03
Built-ins and live MCP tools resolve through one registry.
04
Rules scoped per path, evaluated in order.
05
Multi-provider calls with reasoning control.
06
Bring your own processes; they join the tool registry.
07
Conversation state on disk, not in memory.
03 / Engineering
Rust replaces the runtime, not the features. Conversation history spills to SQLite, request bodies stream, tool schemas are cached per model and tool-set, and instance state is pooled with LRU and TTL eviction.
01 / run
run does not abandon its workIt used to make a single provider call and never execute a tool, so a spawned subagent died with the process.
It now drives the real session loop, then holds the process open until four things settle.
session.idle → child sessions quiet → background-task ledger02 / mcp
Three separate defects, each of which silently produced a “successful” boot exposing zero tools.
Content-Length instead of newline-delimited JSON — every server timed out{enabled} toggle variant shadowed the full server variant, discarding every definition03 / stream
The TUI SSE listener dropped early deltas and triggered a full transcript refetch per delta.
04 / Rationale
The container was never the fix. Conversation history spills to SQLite, request bodies stream, tool schemas are cached per model and tool-set, and instance state is pooled with LRU and TTL eviction — so there is nothing left to contain.
| Concern | TypeScript engine | opencode-rust |
|---|---|---|
| Conversation history | Held in RAM | Spilled to SQLite |
| Tool schemas | Re-derived on every LLM step | Cached per (model, tool-set) |
| Request bodies | Buffered whole | Streamed |
| Instance state (MCP / LSP / plugins) | Per-directory, unbounded, never evicted | Pooled by config hash, LRU + TTL eviction |
| Containment | A Docker runtime existed to hold the leak | No container, no cgroup, no leak to contain |
| Heavy run, 5 teams × 5 agents | Pinned a MacBook Pro M5 at 99% CPU — the machine became unusable | That was the limit, not the workload |
Get started
Node 18+, one provider key, no container runtime.