---
title: opencode
description: A plugin that gives an opencode session a real desktop, a mouse and a shell.
---

`@raster/opencode` gives an opencode session a real machine: a screen it can look at, a mouse
and keyboard it can drive, and a shell and filesystem on the same box. opencode keeps its own
loop, model and permissions; this only registers tools and hands the machine back when the
session ends.

## Install

```json
{ "plugin": [["@raster/opencode", { "machineId": "mch_..." }]] }
```

Or with nothing but the environment, which is the usual shape:

```bash
RASTER_BASE_URL=... RASTER_API_KEY=... RASTER_MACHINE_ID=mch_... opencode
```

## Options

| Prop | Type | Default | Description |
| - | - | - | - |
| `machineId?` | `string` | - | An existing machine to attach to. Defaults to RASTER_MACHINE_ID. |
| `create?` | `boolean` | `false` | Create a machine when there is no id. Off deliberately: a plugin that quietly bills a new machine because an env var was missing is a surprise nobody asked for. RASTER_MACHINE_CREATE=1 also opts in. |
| `size?` | `"small" \| "standard" \| "large"` | `"standard"` | The size to create, when creating. |
| `name?` | `string` | `"opencode"` | The name to create under. |
| `baseUrl?` | `string` | - | |
| `apiKey?` | `string` | - | |
| `readyTimeoutMs?` | `number` | - | How long to wait for the desktop to come up. |

With neither an id nor `create`, the first tool call fails with a message saying exactly which of
the two to set. That beats silently creating a machine somebody has to notice on a bill.

## The tools

The plugin registers the SDK's canonical toolkit, so opencode gets exactly what every other
harness gets:

`computer_screenshot`, `computer_click`, `computer_type`, `computer_key`, `computer_scroll`,
`terminal_exec`, `file_read`, `file_write`.

Every one runs through the same executor the SDK publishes — including the parts that are easy to
get wrong on your own: a non-zero exit code is a **result** rather than a failure, and a
screenshot travels with the geometry it was captured at. Descriptions are not restated in this
package; they come from the canonical definitions, and a test asserts the argument shapes carry
the same fields.

Screenshots come back as an image part opencode renders inline, named by media type.

## When the machine is resolved

On the **first tool call**, not at load. opencode loads a plugin once per project and keeps it
for the session, so a session that never touches the desktop never creates a lease and never pays
for one — and an unreachable API does not take the project down at startup.

The first caller does the resolution and everyone waiting shares it, including the failure: a
machine that could not be reached is reported to each tool call rather than resolved twice into
two machines.

An attached machine that is stopped is **started** and waited for. A stopped machine has no
screen, and starting it here is what makes the very first tool call work rather than fail with a
state error the model can do nothing about.

## When the session ends

opencode calls the plugin's `dispose`, which releases the input lease and closes the session.
That is what stops an abandoned session from holding the machine's keyboard.

The machine itself keeps running and keeps its disk. Stop or delete it yourself when you are
done with it.

## Building on it

```ts
import { machineSource, computerTools } from "@raster/opencode";

const source = machineSource({ machineId });
const tools = computerTools(source.get);
await source.close();
```

Both are exported for wiring the same machine into a harness of your own.
