How to run OpenCode in a cloud sandbox
Install opencode-ai with npm in a Linux microVM, store the provider key as a secret, then run opencode run --auto on a checkout.
On Runtime, OpenCode's permissive defaults are safe to leave on. OpenCode
starts with most permissions set to allow, and --auto approves the rest that
are not explicitly denied. Inside a Runtime sandbox that power stops at the
edge of a Firecracker microVM with its own kernel, running Ubuntu 24.04 and
Node.js 24. The provider key is a Runtime secret: the machine sees a
placeholder and the host's proxy supplies the real value only to the provider's
API. A 2 vCPU, 4 GiB sandbox costs $0.03125 an hour while the agent waits on
the model. OpenCode 1.18.32 was the current npm release on 25 September 2026.
| Setup | OpenCode runs | Runtime appears as |
|---|---|---|
| Agent on a remote checkout | In a sandbox | The machine it works on |
| Agent on your laptop | On your machine | An MCP server with sandbox tools |
The provider key
OpenCode reaches models through the AI SDK and Models.dev. Its GitHub workflow
hands Anthropic's key to the agent as ANTHROPIC_API_KEY, so store the key
under that name:
Terminalprintf %s "$ANTHROPIC_API_KEY" | npx withruntime secrets set ANTHROPIC_API_KEY --host api.anthropic.comThe variable appears in every sandbox of your account holding a placeholder.
Only HTTPS requests to api.anthropic.com leave with the real key in their
headers. No file or process in the sandbox can leak the value, because it
never enters the machine
(secrets sandboxes never see).
Run OpenCode against a repo
TypeScriptimport { writeFile } from "node:fs/promises";import { Sandbox } from "withruntime";const repo = "https://github.com/your-org/your-repo";const task = "The CSV export drops the last row. Find out why, fix it and add a regression test.";await using sbx = await Sandbox.create({ diskMiB: 8192, timeoutSeconds: 3600 });const prep = { check: true, timeoutMs: 600_000 } as const;await sbx.exec("npm install -g --prefix /workspace/.local opencode-ai", prep);await sbx.exec(["git", "clone", "--depth", "1", repo, "/workspace/app"], prep);await sbx.network.set({ internet: true, allow: ["api.anthropic.com", "models.opencode.ai", "registry.npmjs.org"],});const run = await sbx.exec( ["opencode", "run", "--auto", "-m", "anthropic/claude-sonnet-4-5", "--format", "json", task], { cwd: "/workspace/app", env: { OPENCODE_DISABLE_AUTOUPDATE: "1" }, timeoutMs: 1_800_000, onStderr: (text) => process.stderr.write(text), },);const events = run.stdout .split("\n") .filter(Boolean) .map((line) => JSON.parse(line));console.log(run.exitCode, events.length, "events");await sbx.exec("git add -A && git diff --cached > /workspace/opencode.patch", { cwd: "/workspace/app", check: true,});await writeFile("opencode.patch", await sbx.files.readText("/workspace/opencode.patch"));Pythonimport sys, jsonfrom withruntime import Sandboxrepo = "https://github.com/your-org/your-repo"task = "The CSV export drops the last row. Find out why, fix it and add a regression test."with Sandbox.create(disk_mib=8192, timeout_seconds=3600) as sbx: sbx.exec("npm install -g --prefix /workspace/.local opencode-ai", check=True, timeout_ms=600_000) sbx.exec(["git", "clone", "--depth", "1", repo, "/workspace/app"], check=True, timeout_ms=600_000) sbx.network.set(internet=True, allow=["api.anthropic.com", "models.opencode.ai", "registry.npmjs.org"]) run = sbx.exec( ["opencode", "run", "--auto", "-m", "anthropic/claude-sonnet-4-5", "--format", "json", task], cwd="/workspace/app", env={"OPENCODE_DISABLE_AUTOUPDATE": "1"}, timeout_ms=1_800_000, on_stderr=sys.stderr.write, ) events = [json.loads(line) for line in run.stdout.splitlines() if line] print(run.exit_code, len(events), "events") sbx.exec("git add -A && git diff --cached > /workspace/opencode.patch", cwd="/workspace/app", check=True) with open("opencode.patch", "w") as file: file.write(sbx.files.read_text("/workspace/opencode.patch"))What matters in that code:
opencode runis OpenCode's non-interactive mode: it takes the message as arguments, works until the agent finishes and exits, with no TUI.--autoapproves every permission request that no rule denies. Explicit"deny"rules in a repo'sopencode.jsonare still enforced.-m provider/modelpicks the model in OpenCode'sprovider/modelform.--format jsonprints raw JSON events, one per line, instead of the formatted view.- The allow list has a third host. OpenCode's source loads its model
catalogue from
models.opencode.ai(a public list, no key involved), so leaving it reachable keeps model names resolving. OPENCODE_DISABLE_AUTOUPDATEstops update checks during a run that should use exactly the version you installed.
OpenCode's network guide says it respects HTTPS_PROXY and
NODE_EXTRA_CA_CERTS, which the sandbox image already sets, so it trusts the
proxy that adds your key with no extra step.
Useful opencode run flags
From OpenCode's CLI and permissions docs, 25 September 2026:
| Flag | Does |
|---|---|
--auto |
Approves permissions that are not explicitly denied |
-m, --model |
Model as provider/model |
--agent <name> |
Uses a named agent from the config |
-f, --file |
Attaches files to the message |
--format json |
Raw JSON events |
-c, --continue |
Carries on the last session |
-s, --session <id> |
Carries on a given session; add --fork to branch it |
--dir <path> |
Directory to run in |
For repeated tasks on one checkout, opencode serve inside the sandbox and
opencode run --attach avoid a cold start per task; start the server with
sbx.spawn so it outlives the command that launched it
(the network).
Give OpenCode sandboxes as tools
OpenCode on your own machine can hand code execution to Runtime. OpenCode
defines MCP servers under mcp in its config, with type: "local" and the
command as an array. In ~/.config/opencode/opencode.json:
JSON{ "$schema": "https://opencode.ai/config.json", "mcp": { "runtime": { "type": "local", "command": ["npx", "-y", "withruntime", "mcp"], "enabled": true } }}The first Runtime call returns a sign-in link and a code. Approve Connect
agent in the browser and the whole tool set appears, with nothing secret in
the config (MCP). OpenCode also takes
type: "remote" with a url, which fits https://api.withruntime.com/mcp
(remote connection).
| Tool | Lets OpenCode |
|---|---|
runtime_sandbox_create |
Start a clean microVM for untrusted code |
runtime_sandbox_exec |
Run builds and tests there |
runtime_sandbox_files_list |
List and glob the sandbox's files |
runtime_image_build |
Bake dependencies into an image for next time |
runtime_sandbox_manage |
Pause, wake or stop the machine |
Price of a session
Runtime bills the CPU a sandbox uses at $0.025 per vCPU-hour, with a floor of a twentieth of a vCPU, and reserved memory at $0.0075 per GiB-hour. With 2 vCPUs and 4 GiB, a session costs $0.03125 an hour while the model thinks and $0.08 an hour with both cores compiling (pricing). Token charges come from your model provider. The free trial gives 50 sandbox hours without a card:
Terminalnpx withruntime sandbox run --trial -- node --versionOther agents set up the same way: Claude Code and Goose. To run a fleet of them, read a sandbox for coding agents.
Sources
Checked 25 September 2026.
- OpenCode intro:
npm install -g opencode-ai - CLI:
opencode runand its flags,OPENCODE_DISABLE_AUTOUPDATE - Permissions:
--autoand the permissive defaults - MCP servers:
mcp,type: "local",command,type: "remote" - Network:
HTTPS_PROXYandNODE_EXTRA_CA_CERTS - OpenCode source, models-dev.ts:
the model catalogue at
models.opencode.ai - opencode-ai on npm: version 1.18.32
Facts on this page were checked on 25 September 2026.