> ## Documentation Index
> Fetch the complete documentation index at: https://docs.archil.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenCode

> Run OpenCode headlessly in an Archil sandbox, with its workspace and session history on an Archil disk.

[OpenCode](https://opencode.ai) is an open-source coding agent that works with many model providers. In an Archil [sandbox](/compute/sandboxes/introduction) it gets a Linux VM of its own, so you can let it work without approving each step. Its workspace and session history live on an Archil disk, so the work outlives the sandbox, and a new sandbox can continue the same session.

## Prerequisites

Export your Archil API key, a region where sandboxes are available (`aws-us-east-1`, `aws-us-west-2`, or `aws-eu-west-1`), and an [Anthropic API key](https://console.anthropic.com/settings/keys), then install the SDK:

```bash theme={null}
export ARCHIL_API_KEY=key-...
export ARCHIL_REGION=aws-us-east-1
export ANTHROPIC_API_KEY=sk-ant-...
```

<CodeGroup>
  ```bash TypeScript theme={null}
  npm init -y && npm pkg set type=module
  npm install disk tsx
  ```

  ```bash Python theme={null}
  pip install archil
  ```
</CodeGroup>

## Run OpenCode in a sandbox

This script creates a disk, starts a sandbox with the disk mounted at `/workspace`, installs OpenCode, and gives it a task with `opencode run`, which works until the task is done, prints the result, and exits. Then it deletes the sandbox; everything the agent made is on the disk.

<CodeGroup>
  ```typescript start.ts theme={null}
  import * as archil from "disk";

  const env = {
    ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
    XDG_DATA_HOME: "/workspace/.local/share", // keep sessions on the disk
  };

  const { disk } = await archil.createDisk({ name: "opencode-workspace" });
  const sandbox = await archil.createSandbox({ name: "opencode", mounts: [{ disk, path: "/workspace" }] });
  await sandbox.exec("npm install -g opencode-ai");

  // --auto approves every permission request; < /dev/null: no more prompt text is coming on stdin.
  const result = await sandbox.exec(
    "opencode run --model anthropic/claude-sonnet-5 --auto " +
      '"Create a hello-world Express app with a test, and run the test. Reply in two sentences." < /dev/null',
    { cwd: "/workspace", env },
  );
  console.log(result.stdout);

  await sandbox.stop();
  await sandbox.delete();
  ```

  ```python start.py theme={null}
  import os

  import archil

  env = {
      "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
      "XDG_DATA_HOME": "/workspace/.local/share",  # keep sessions on the disk
  }

  disk = archil.create_disk(name="opencode-workspace").disk
  sandbox = archil.create_sandbox(
      name="opencode", mounts=[archil.SandboxMountSpec(disk=disk, path="/workspace")]
  )
  sandbox.exec("npm install -g opencode-ai")

  # --auto approves every permission request; < /dev/null: no more prompt text is coming on stdin.
  result = sandbox.exec(
      "opencode run --model anthropic/claude-sonnet-5 --auto "
      '"Create a hello-world Express app with a test, and run the test. Reply in two sentences." < /dev/null',
      cwd="/workspace",
      env=env,
  )
  print(result.stdout)

  sandbox.stop()
  sandbox.delete()
  ```
</CodeGroup>

Run it with `npx tsx start.ts` or `python start.py`. The agent's wording varies from run to run. One run printed:

```text theme={null}
I created a hello-world Express app at `/workspace/hello-world-express` (app.js, server.js, app.test.js) with a Jest/Supertest test verifying `GET /` returns "Hello, World!". The test ran successfully: 1 passed, 1 total.
```

## Pick up where you left off

OpenCode's project and session history are on the disk, so any sandbox that mounts it can continue the session. This script starts a new sandbox on the same disk and runs `opencode run --continue`, which continues the most recent session.

<CodeGroup>
  ```typescript continue.ts theme={null}
  import * as archil from "disk";

  const env = {
    ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
    XDG_DATA_HOME: "/workspace/.local/share",
  };

  const [disk] = await archil.listDisks({ name: "opencode-workspace" });
  const sandbox = await archil.createSandbox({ name: "opencode", mounts: [{ disk, path: "/workspace" }] });
  await sandbox.exec("npm install -g opencode-ai");

  const result = await sandbox.exec(
    "opencode run --continue --model anthropic/claude-sonnet-5 --auto " +
      '"Add a /health route with a test and run all the tests. Reply in two sentences." < /dev/null',
    { cwd: "/workspace", env },
  );
  console.log(result.stdout);

  await sandbox.stop();
  await sandbox.delete();
  ```

  ```python continue.py theme={null}
  import os

  import archil

  env = {
      "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
      "XDG_DATA_HOME": "/workspace/.local/share",
  }

  [disk] = archil.list_disks(name="opencode-workspace")
  sandbox = archil.create_sandbox(
      name="opencode", mounts=[archil.SandboxMountSpec(disk=disk, path="/workspace")]
  )
  sandbox.exec("npm install -g opencode-ai")

  result = sandbox.exec(
      "opencode run --continue --model anthropic/claude-sonnet-5 --auto "
      '"Add a /health route with a test and run all the tests. Reply in two sentences." < /dev/null',
      cwd="/workspace",
      env=env,
  )
  print(result.stdout)

  sandbox.stop()
  sandbox.delete()
  ```
</CodeGroup>

```text theme={null}
I added a `/health` route to app.js:9-11 that returns `{ status: 'ok' }` with a 200 status, along with a corresponding Jest test in app.test.js. All tests pass: 2 passed, 2 total.
```

## Going further

* **Stream output.** Pass `onOutput: ({ data }) => process.stdout.write(data)` to `exec` (in Python, `on_output=lambda out: sys.stdout.buffer.write(out.data)`) to watch the agent as it works. Add `--format json` to `opencode run` to get one JSON event per line.
* **Work interactively.** Start `opencode` in a pseudo-terminal with `sandbox.run`; see [Opening interactive shells](/compute/sandboxes/introduction#opening-interactive-shells).
* **Run the OpenCode server.** `opencode serve` runs OpenCode as an HTTP server that the OpenCode terminal UI (`opencode attach`) and the [OpenCode SDK](https://opencode.ai/docs/sdk/) connect to. Run it as a sandbox [service](/compute/sandboxes/introduction#hosting-network-services) so it keeps running and restarts with the sandbox. Set `OPENCODE_SERVER_PASSWORD` on the server, and reach it with a port token, or with a public port if you use `opencode attach`, which can't send the token header.

<Accordion title="Use Vercel AI Gateway instead of an Anthropic key">
  OpenCode has a built-in [Vercel AI Gateway](https://vercel.com/docs/ai-gateway/coding-agents/opencode) provider, `vercel`, that reads `AI_GATEWAY_API_KEY`. Export `AI_GATEWAY_API_KEY` instead of `ANTHROPIC_API_KEY`, replace the `ANTHROPIC_API_KEY` line in `env` with this one, and change `--model anthropic/claude-sonnet-5` to `--model vercel/anthropic/claude-sonnet-5` in both scripts. On the Developer plan, sandboxes can't reach the gateway, because it isn't on the [managed allowlist](/compute/sandboxes/firewall#developer-plan-allowlist); use your provider key instead.

  <CodeGroup>
    ```typescript TypeScript theme={null}
    AI_GATEWAY_API_KEY: process.env.AI_GATEWAY_API_KEY!,
    ```

    ```python Python theme={null}
    "AI_GATEWAY_API_KEY": os.environ["AI_GATEWAY_API_KEY"],
    ```
  </CodeGroup>
</Accordion>

## Clean up

Each script deletes its sandbox when it finishes, so only the disk is left. Delete it:

<CodeGroup>
  ```typescript cleanup.ts theme={null}
  import * as archil from "disk";

  const [disk] = await archil.listDisks({ name: "opencode-workspace" });
  await disk.delete();
  ```

  ```python cleanup.py theme={null}
  import archil

  [disk] = archil.list_disks(name="opencode-workspace")
  disk.delete()
  ```
</CodeGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Claude Code" icon="terminal" href="/guides/agents/claude-code">
    Run Claude Code headlessly in a sandbox.
  </Card>

  <Card title="OpenAI Codex" icon="terminal" href="/guides/agents/codex">
    Run the Codex CLI headlessly in a sandbox.
  </Card>

  <Card title="Coding agent in a sandbox" icon="code" href="/guides/agents/coding-agent">
    Build your own coding agent with the AI SDK instead.
  </Card>

  <Card title="Persistent sandboxes" icon="box" href="/compute/sandboxes/introduction">
    Lifecycle, services, network access, and forking in detail.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.