Skip to main content
Use the reference starter repo for complete source code: runloopai/opencode-starter.

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:
  1. Create a devbox (from blueprint or fresh)
  2. Install OpenCode (manual mode only)
  3. Write OpenCode config in the devbox
  4. Start OpenCode on 0.0.0.0:3000
  5. 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