Skip to content
Raster
Esc
navigateopen⌘Jpreview
On this page

opencode

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

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

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

RASTER_BASE_URL=... RASTER_API_KEY=... RASTER_MACHINE_ID=mch_... opencode

Options

PropType
machineId?string

An existing machine to attach to. Defaults to RASTER_MACHINE_ID.

Typestring
create?boolean

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.

Typeboolean
Defaultfalse
size?"small" | "standard" | "large"

The size to create, when creating.

Type"small" | "standard" | "large"
Default"standard"
name?string

The name to create under.

Typestring
Default"opencode"
baseUrl?string
Typestring
apiKey?string
Typestring
readyTimeoutMs?number

How long to wait for the desktop to come up.

Typenumber

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

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.

Was this page helpful?