Skip to content

Overview

The Computer API drives the same sessions as Slack threads, over WebSocket (JSON-RPC 2.0) and HTTP

The schema is computer/schema/computer-api.v1.json; API schema lists its operations, objects, events and errors. The relay, a process on the computer (SP_WIRE_LISTEN, default 127.0.0.1:7071), serves the WebSocket and the workspace file routes. The client is the opc CLI.

Transport

TransportOperations
WebSocket and HTTPEverything not listed below, with the same parameters, result and errors
WebSocket onlysessions.attach (live events), terminals
HTTP onlyCreating and listing sessions, workspace files

WebSocket

Open /connect with the subprotocol opc.v1 (without it: close 4400). Messages are JSON-RPC 2.0 text frames; binary frames carry terminal data.

The server’s first frame:

{"jsonrpc":"2.0","method":"ready","params":{"connectionId":"...","server":{"version":"...","region":null},"protocol":{"features":[]},"limits":{"maxAttached":20,"maxMessageBytes":1048576,"maxRequestsPerSecond":100},"expiresAt":null,"expiresInMs":null}}

A request and its response:

{"jsonrpc":"2.0","id":1,"method":"sessions.get","params":{"sessionId":"cs_0123456789abcdef"}}
{"jsonrpc":"2.0","id":1,"result":{"session":{"id":"cs_0123456789abcdef","status":"idle","...":"..."}}}

Batches are not supported. Close codes and relay limits: API schema.

HTTP

Routes are in the schema’s x-methods map, for example POST /sessions/{id}/turns for turns.send. Path parameters replace the id fields of the method’s params. opc sends them under /api/managed-agents/computer of its API URL.

Authentication

LayerCredential
Hosted serviceAn API key in the x-api-key header, on HTTP requests and the WebSocket upgrade. opc login obtains it
RelayX-Wire-* headers signed with a key from the host, each signature valid 30 seconds. The relay does not check API keys: whatever fronts it verifies the key and signs the headers

Scopes

A credential without a scope list has every scope.

ScopeOperations
sessions:readsessions.attach, sessions.get, turns.get, events.list, asks.list, asks.get, subagents.list, subagents.get, subagents.stop, file listing and download
sessions:writeturns.send, turns.cancel, sessions.update, sessions.interrupt, sessions.compact, sessions.suspend, sessions.resume, file upload
asks:answerasks.answer, asks.dismiss
terminalsterminals.open, terminals.resize, terminals.eof, terminals.close

A scope may also name sessions (sessionIds), be read-only (readOnly) and expire (until).

CaseResult
Scope missingforbidden, reason: "missing_scope"
Credential expired or revokedIts connections close with 4001
Caller is not the session’s owner and not on its member listsession_not_found on every operation. A null member list means the whole organization
Terminal opened by someone other than the owner or an adminforbidden, reason: "terminal_owner_only"

Session journal

Every state change in a session is an event with a seq, an integer from 1 that increases by one. Session, Turn, Ask and Subagent objects are computed from the events. Reads and most writes work on a suspended session.

NeedHow
Read your own writeA write returns the seq of its event. A read with minSeq waits up to 2 seconds for the journal to reach it, then fails with unavailable
ResumeAsk for events after the last seq processed. See Events
New epoch (logEpoch, epochStartSeq: the journal was rebuilt)Discard held events from epochStartSeq on and read again from epochStartSeq - 1

Idempotency keys

Every write takes an idempotencyKey of 1 to 255 characters; over HTTP opc sends it as the Idempotency-Key header. A key is scoped to one member and one operation, shared by the operation’s WebSocket method and HTTP route, and kept 24 hours.

RepeatResult
Same key, same parametersThe first result, with its objects re-read at their current state, and duplicate: true where the result has that field
Same key, different parameters409 idempotency_conflict
Same key while the first is in flightWaits for the first
After the first failedRuns again

Errors

Over WebSocket an API error is JSON-RPC error -32000 whose data is the error body; over HTTP it is {"error": {...}} with the matching status.

{"jsonrpc":"2.0","id":7,"error":{"code":-32000,"message":"at most 20 turns may wait","data":{"code":"queue_full","message":"at most 20 turns may wait","status":409,"retryable":true,"retryAfterMs":5000,"requestId":"req_..."}}}
FieldMeaning
retryableTrue for rate_limited, unavailable, computer_unavailable, internal and queue_full
retryAfterMsHow long to wait, when the server knows
fieldThe parameter at fault. An unknown parameter is invalid_request

All codes: API schema.