What you need
- A Runloop API key (
RUNLOOP_API_KEY)
- One of:
- Python 3.11+ and
uv
- Node.js 18+ and
npm
- Optional model provider keys:
ANTHROPIC_API_KEY
OPENAI_API_KEY
Environment variables
Set your Runloop API key before running any command:
export RUNLOOP_API_KEY="your-runloop-api-key"
You can also set provider keys if your OpenCode workflow needs them:
export ANTHROPIC_API_KEY="..."
export OPENAI_API_KEY="..."
Instead of exporting provider keys directly, you can store them as Runloop
account secrets and map them into your devbox at runtime. See Account
Secrets.
Our starter image is what starts when you start a devbox. You get the following packages available to your devbox:Core tools: curl, ca-certificates, jq, sudo, git
Extras: dnsutils, iputils-ping, less, vim, wget, rsync, gh
Python stack: Python 3.12, pip, uv
Node stack: Node 22.15.0, npm, Yarn 1.22.22 via corepack
Setup
Clone the reference implementation:
git clone https://github.com/runloopai/opencode-starter.git
cd opencode-starter
Create a blueprint with OpenCode
cd python
uv sync
uv run opencode-runloop create-blueprint
This creates a reusable opencode blueprint with OpenCode preinstalled.
Create a devbox with OpenCode
cd python
uv run opencode-runloop run
Each command creates a devbox, starts opencode web, enables a tunnel, and prints the OpenCode URL.
Optional: create devbox without blueprint (manual install)
Use this when you want zero upfront setup:
cd python
uv sync
uv run opencode-runloop run --manual
Manual mode is slower because OpenCode is installed in a fresh devbox each
run.
How the integration works internally
Each run follows this flow:
- Create a devbox (from blueprint or fresh)
- Install OpenCode (manual mode only)
- Write OpenCode config in the devbox
- Start OpenCode on
0.0.0.0:3000
- Create a Runloop tunnel and print the URL
This makes local setup simple while keeping execution remote and sandboxed.
OpenCode Dockerfile
Use this Dockerfile when creating the blueprint:
# Runloop starter image containing Node.js and npm
FROM runloop:runloop/starter-x86_64
# Install OpenCode globally
RUN npm install -g opencode-ai
# Create config directory
RUN mkdir -p /home/user/.config/opencode
WORKDIR /home/user
OpenCode config
Use this OpenCode config payload:
{
"$schema": "https://opencode.ai/config.json",
"default_agent": "runloop",
"server": {
"hostname": "0.0.0.0",
"port": 3000
},
"agent": {
"runloop": {
"description": "Runloop sandbox-aware coding agent",
"mode": "primary",
"prompt": "You are running in a Runloop devbox. Use /home/user as your working directory. When running services, bind to 0.0.0.0 so they are accessible via Runloop tunnels. File paths should be absolute or relative to /home/user."
}
}
}
Write config into the devbox filesystem
The starter writes config to /home/user/.config/opencode/opencode.json before starting OpenCode:
import json
opencode_config = {
"$schema": "https://opencode.ai/config.json",
"default_agent": "runloop",
"server": {
"hostname": "0.0.0.0",
"port": 3000,
},
"agent": {
"runloop": {
"description": "Runloop sandbox-aware coding agent",
"mode": "primary",
"prompt": "You are running in a Runloop devbox. Use /home/user as your working directory. When running services, bind to 0.0.0.0 so they are accessible via Runloop tunnels. File paths should be absolute or relative to /home/user.",
},
},
}
devbox.cmd.exec("mkdir -p ~/.config/opencode")
devbox.file.write(
file_path="/home/user/.config/opencode/opencode.json",
contents=json.dumps(opencode_config, indent=2),
)
Snippets
Creating a blueprint with OpenCode
from runloop_api_client import RunloopSDK
from runloop_api_client.types.shared_params.launch_parameters import (
LaunchParameters,
UserParameters,
)
runloop = RunloopSDK()
opencode_dockerfile = '''
# Runloop starter image containing Node.js and npm
FROM runloop:runloop/starter-x86_64
# Install OpenCode globally
RUN npm install -g opencode-ai
# Create config directory
RUN mkdir -p /home/user/.config/opencode
WORKDIR /home/user
'''
blueprint = runloop.blueprint.create(
name="my_opencode_blueprint",
dockerfile=opencode_dockerfile,
launch_parameters=LaunchParameters(
user_parameters=UserParameters(username="root", uid=0)
),
)
Creating a devbox with OpenCode
from runloop_api_client import RunloopSDK
from runloop_api_client.types.devbox_create_params import Tunnel
from runloop_api_client.types.shared_params.launch_parameters import (
LaunchParameters,
UserParameters,
)
runloop = RunloopSDK()
devbox = runloop.devbox.create_from_blueprint_name(
name="opencode",
blueprint_name="my_opencode_blueprint",
launch_parameters=LaunchParameters(
user_parameters=UserParameters(username="user", uid=1000),
),
tunnel=Tunnel(auth_mode="open"),
)
Common issues
- Missing API key errors
- Confirm
RUNLOOP_API_KEY is set in your shell before running commands.
- Provider/model errors
- Set
ANTHROPIC_API_KEY or OPENAI_API_KEY based on the model you are using.
- Slow startup
- Use blueprint mode (
create-blueprint once, then run) instead of --manual.
Next steps