roc runs coding agents in throwaway Docker containers with MCP
A Rust CLI that launches opencode, Claude Code, Codex or goose against LM Studio, Ollama or any OpenAI-compatible model inside a disposable container.
What roc is
roc — "run opencode container" — is a Rust binary that answers one complaint about running coding agents on your laptop: you either approve every ls and go test, or you grant broad permissions and hope the agent never wanders into ~/.ssh or another client's repo.
The README states its position plainly: roc replaces permission lists with hard walls, then takes the leash off. It runs an AI coding agent inside a disposable Docker container that sees only the folders you hand it. When the agent quits, everything it made is gone.
It targets backend work first — agents writing code against real Postgres, Redis or Kafka instances they start themselves — but ships MCP stacks for frontend, Next.js, Wails desktop apps, iOS and D3 data visualization too.
How a session works
The main flow lives in src/session.rs (run). It is deliberate about its order:
- Plan. Resolve the agent binary, image, mounts and environment from flags plus saved state. If nothing is configured, it mounts the current directory read-write.
- Check Docker. Verify the daemon is up and the agent image exists; reap stale sessions left by crashes.
- Lease a worker.
leasepicks an available model worker from your pool — one per loaded copy in LM Studio, or slots for Ollama / any OpenAI-compatible API. With providernone, it uses the agent's own login and skips leasing entirely. If no worker is free, it reports that no worker is available. - Set up. Create a session directory, logs (pruned to the most recent 200 files), and an agent home under
~/.local/roc. - Create a per-session network, labelled so cleanup can find it later.
- Start the MCP gateway with a fresh random token (
random_hex(24)). Secrets for MCP servers stay on your machine; the agent never sees them, only the token. - Write the agent config. roc generates each agent's configuration files into the session directory and seeds shared settings into the agent home.
- Run the container in the foreground with inherited stdin/stdout/stderr — you land in the agent's terminal UI.
When the agent exits, a Guard (a RAII struct) shuts down the gateway and calls docker::cleanup_session, which deletes the containers and networks it recorded, images unless kept (-keep-images), and releases its lease. The cleanup runs on Drop, so it happens even after a crash; if anything is left behind, roc tells you to run roc -cleanup.
The MCP gateway
The gateway (src/mcp/gateway.rs) is a streamable-HTTP front end built on tiny_http. It implements the subset of the MCP Streamable HTTP transport every client supports: POST a JSON-RPC message, get one application/json response; GET answers 405.
Gateway handlers come in three kinds: the built-in Docker server, stdio bridges to external processes, and HTTP proxies. The built-in Docker server is the centerpiece — see below.
A policy-enforced Docker MCP server
The agent never sees your Docker socket. Instead it calls tools on DockerTools (src/mcp/docker_tools.rs) that roc executes on the host with strict guarantees, spelled out in the file's header comment:
- every container, image and network created is labelled
roc.session=<id>and recorded in the state file; - stop/remove/exec/logs/inspect only work on resources of *this* session (the agent container itself excluded);
- bind mounts must resolve inside the session's own read/write directories, with read-only directories forced read-only by the kernel;
- no privileged mode, capabilities, devices or arbitrary flags; published ports bind to
127.0.0.1only.
So an agent can start Postgres and reach it at roc-<session>-db:5432, build its own service image, run it on the session network and curl it by container name — all without touching anything else on your machine.
The state file
Everything roc knows lives in one JSON file, ~/.local/roc/state.json (src/state.rs). It has two halves: a durable, user-editable config (model server, worker pool, agent defaults, MCP servers, Docker policy) and runtime sessions bookkeeping — one entry per live process holding a lease plus every container/image/network it created.
Every read-modify-write happens under an exclusive flock on a sidecar .lock file, with atomic writes (temp file + fsync + rename). API tokens are never written to the file. The state file is documented in docs/configuration.md.
Getting started
You need Docker (Desktop, OrbStack or Engine), Rust 1.99+ to build roc, plus either a model server or an agent you're already logged in to:
git clone https://github.com/andreimerlescu/roc.git && cd roc
make install image # roc into ~/.local/bin, then the agent image (5–10 minutes)
roc -init # guided setup: model server, folders, agent and MCP stacks
roc -doctor # check Docker, image, models and every MCP server
cd ~/work/my-api && roc
-dry-run prints exactly what would run — mounts, the full docker run command and the generated agent config — without touching anything. The Makefile cross-compiles six binaries (Windows/Linux/macOS × amd64/arm64) into dist/ with SHA256SUMS; Linux builds are static musl by default, and non-native targets use cargo-zigbuild.
Everyday commands
| Command | What it does | |---|---| | roc -w ~/proj -r ~/libs | Mount ~/proj read-write and ~/libs read-only | | roc -publish 5173,8080 | Reach the agent's dev servers from your browser | | roc -binary claudecode | Use another agent this time | | roc -ps / roc -kill 2 | List running sessions; stop one by position and clean up | | roc -stack data | Turn on a stack of MCP servers (data, research, github, frontend, nextjs, wails, ios, dataviz) | | roc -mcp add github | Add one server from the 22-server catalog |
Agents and models
The default agent is opencode; Claude Code, Codex and goose are one flag away. roc writes each agent's config with approvals off and your MCP servers wired in — your own settings under ~/.local/roc/agents/ win over its generated ones.
For models you can use LM Studio (one worker per loaded copy), Ollama, any OpenAI-compatible API, or none to lean on the agent's own login. Several sessions run side by side, one per worker; opencode sessions can be driven remotely by tools like Toktail through a published control server whose password is written to a private file that is never mounted into the container.
Testing and license
make test runs the full suite without Docker or a model server. make lint runs rustfmt and clippy. The project is Apache-2.0 with an accompanying NOTICE file; issues and pull requests are welcome.
andreimerlescu/roc: 610 KB in 44 files, indexed Nov 9, 2026 after 0.00 hours of indexing. License: Apache-2.0. Source: https://github.com/andreimerlescu/roc.
Ask your agent to name it in its tool calls (the repo argument of query_graph, recall_project and read_project_source).
Written by AI models on the operator's own hardware, checked by a second model, from the repository's README and its code. Back to the shelf