Skip to main content

Installation

pip install opencomputer-sdk
from opencomputer import Sandbox, Image, Snapshots

Sandbox

Class Methods

await Sandbox.create(...): Sandbox

Create a new sandbox.
ParameterTypeDefaultDescription
templatestr"base"Template name
timeoutint300Idle timeout in seconds
api_keystrenv varAPI key
api_urlstrenv varAPI URL
envsdict[str, str]NoneEnvironment variables
metadatadict[str, str]NoneArbitrary metadata
imageImageNoneDeclarative image definition (see Image)
snapshotstrNoneName of a pre-built snapshot
on_build_logCallable[[str], None]NoneBuild log callback (when using image)
sandbox = await Sandbox.create(template="my-stack", timeout=600)
cpuCount and memoryMB are not available in the Python SDK. Use the HTTP API for custom resources.

await Sandbox.connect(sandbox_id, ...): Sandbox

ParameterTypeDescription
sandbox_idstrSandbox ID (required)
api_keystrAPI key (optional)
api_urlstrAPI URL (optional)
sandbox = await Sandbox.connect("sb-abc123")

await Sandbox.create_from_checkpoint(checkpoint_id, ...): Sandbox

ParameterTypeDefaultDescription
checkpoint_idstrCheckpoint ID (required)
timeoutint300Idle timeout
api_keystrenv varAPI key
api_urlstrenv varAPI URL
forked = await Sandbox.create_from_checkpoint("cp-abc123")

await Sandbox.create_checkpoint_patch(checkpoint_id, script, ...): dict

ParameterTypeRequiredDescription
checkpoint_idstrYesTarget checkpoint
scriptstrYesBash script
descriptionstrNoDescription
result = await Sandbox.create_checkpoint_patch("cp-abc", script="apt install -y curl")

await Sandbox.list_checkpoint_patches(checkpoint_id, ...): list[dict]

patches = await Sandbox.list_checkpoint_patches("cp-abc")

await Sandbox.delete_checkpoint_patch(checkpoint_id, patch_id, ...): None

await Sandbox.delete_checkpoint_patch("cp-abc", "pa-xyz")

Context Manager

Auto-kills the sandbox on exit:
async with await Sandbox.create() as sandbox:
    result = await sandbox.exec.run("echo hello")
    print(result.stdout)
# sandbox.kill() called automatically

Instance Methods

await sandbox.kill(): None

Terminate the sandbox.

await sandbox.is_running(): bool

Check if the sandbox is running.

await sandbox.set_timeout(timeout): None

Update idle timeout.
ParameterTypeDescription
timeoutintNew timeout in seconds

await sandbox.create_checkpoint(name): dict

Create a named checkpoint. Returns checkpoint info as a dictionary.

await sandbox.list_checkpoints(): list[dict]

List all checkpoints for the sandbox.

await sandbox.restore_checkpoint(checkpoint_id): None

Revert in-place to a checkpoint.

await sandbox.delete_checkpoint(checkpoint_id): None

Delete a checkpoint.

await sandbox.create_preview_url(port, domain?, auth_config?): dict

ParameterTypeRequiredDescription
portintYesContainer port (1–65535)
domainstrNoCustom domain
auth_configdictNoAuth configuration

await sandbox.list_preview_urls(): list[dict]

await sandbox.delete_preview_url(port): None

await sandbox.close(): None

Close HTTP clients. Called automatically by the context manager.

Not Available in Python

These features are TypeScript-only. Use the HTTP API directly:
  • hibernate() / wake()
  • cpuCount / memoryMB on create

Properties

PropertyTypeDescription
sandbox_idstrSandbox ID
statusstrCurrent status
agentAgentAgent sessions
execExecCommand execution
filesFilesystemFile operations
ptyPtyTerminal sessions
commandsExecDeprecated — alias for exec

Agent

Accessed via sandbox.agent.

await sandbox.agent.start(...): AgentSession

Start an agent session.
ParameterTypeDescription
promptstrInitial prompt
modelstrClaude model
system_promptstrSystem prompt
allowed_toolslist[str]Restrict tools
permission_modestrPermission mode
max_turnsintMax turns (default: 50)
cwdstrWorking directory
mcp_serversdict[str, Any]MCP server configuration
on_eventCallable[[AgentEvent], None]Event callback
on_errorCallable[[str], None]Stderr callback
session = await sandbox.agent.start(
    prompt="Build a todo app",
    on_event=lambda e: print(e.type),
)
resume, on_exit, and on_scrollback_end are not available in the Python SDK.

await sandbox.agent.attach(session_id, ...): AgentSession

Reconnect to a running agent session. Accepts on_event and on_error.

await sandbox.agent.list(): list[AgentSessionInfo]

List all agent sessions.

AgentSession

MemberTypeDescription
session_idstrSession ID
sandbox_idstrSandbox ID
send_prompt(text)methodSend follow-up prompt
interrupt()methodInterrupt current turn
configure(...)methodUpdate model, tools, cwd
await kill(signal=9)methodKill agent process
await close()methodClose WebSocket

await session.collect_events(): list[AgentEvent]

Collect all events until the agent process exits. Python-unique alternative to callbacks.
session = await sandbox.agent.start(prompt="Fix the tests")
events = await session.collect_events()
for event in events:
    if event.type == "result":
        print(event.data)

await session.wait(): int

Wait for the agent to finish. Returns the exit code.
exit_code = await session.wait()

AgentEvent

Dataclass with dict-like access:
@dataclass
class AgentEvent:
    type: str
    data: dict[str, Any]

# Usage:
event["message"]      # dict-like access
event.get("message")  # safe access with default
event.type            # attribute access

AgentSessionInfo

@dataclass
class AgentSessionInfo:
    session_id: str
    sandbox_id: str
    running: bool
    started_at: str

Exec

Accessed via sandbox.exec.

await sandbox.exec.run(command, ...): ProcessResult

Run a command synchronously via sh -c.
ParameterTypeDefaultDescription
commandstrShell command (required)
timeoutint60Timeout in seconds
envdict[str, str]NoneEnvironment variables
cwdstrNoneWorking directory
result = await sandbox.exec.run("npm test", cwd="/app")

await sandbox.exec.start(command, ...): str

Start a long-running command. Returns the session ID (not a session object).
ParameterTypeDefaultDescription
commandstrCommand (required)
argslist[str]NoneArguments
envdict[str, str]NoneEnvironment variables
cwdstrNoneWorking directory
timeoutintNoneTimeout in seconds
session_id = await sandbox.exec.start("node server.js", cwd="/app")
Python exec.start() returns a session ID string. There are no streaming callbacks, ExecSession object, or maxRunAfterDisconnect. For streaming, use the WebSocket binary protocol.

await sandbox.exec.list(): list[ExecSessionInfo]

List all exec sessions.

await sandbox.exec.kill(session_id, signal=9): None

Kill an exec session.

Not Available in Python

  • exec.attach() — reconnect to running session
  • Streaming callbacks (on_stdout, on_stderr, on_exit)
  • ExecSession object with send_stdin() and done
  • max_run_after_disconnect

ProcessResult

@dataclass
class ProcessResult:
    exit_code: int
    stdout: str
    stderr: str

ExecSessionInfo

@dataclass
class ExecSessionInfo:
    session_id: str
    sandbox_id: str
    command: str
    args: list[str]
    running: bool
    exit_code: int | None
    started_at: str
    attached_clients: int

Filesystem

Accessed via sandbox.files.

await sandbox.files.read(path): str

Read a file as a UTF-8 string.

await sandbox.files.read_bytes(path): bytes

Read a file as raw bytes.

await sandbox.files.write(path, content): None

Write content to a file. Accepts str or bytes.

await sandbox.files.list(path="/"): list[EntryInfo]

List directory contents.

await sandbox.files.make_dir(path): None

Create a directory.

await sandbox.files.remove(path): None

Delete a file or directory.

await sandbox.files.exists(path): bool

Check if a path exists. Client-side wrapper — attempts a read and returns False on error.

EntryInfo

@dataclass
class EntryInfo:
    name: str
    is_dir: bool
    path: str
    size: int = 0

Pty

Accessed via sandbox.pty.

await sandbox.pty.create(cols=80, rows=24, on_output=None): PtySession

Create an interactive terminal session.
ParameterTypeDefaultDescription
colsint80Terminal columns
rowsint24Terminal rows
on_outputCallable[[bytes], None]NoneOutput callback

PtySession

MemberTypeDescription
session_idstrSession ID
sandbox_idstrSandbox ID
send(data)methodSend input (str or bytes)
await recv()methodReceive output bytes (Python-unique)
await close()methodClose the PTY
recv() is Python-unique — a pull-based alternative to the on_output callback. Returns raw bytes.

Image

Fluent, immutable builder for declarative sandbox images. Each method returns a new Image instance.

Image.base(): Image

Start from the default OpenSandbox environment (Ubuntu 22.04, Python, Node.js, build tools).
from opencomputer import Image

image = (
    Image.base()
    .apt_install(["curl", "jq"])
    .pip_install(["requests", "pandas"])
    .env({"PROJECT_ROOT": "/workspace"})
    .workdir("/workspace")
)

Builder Methods

MethodParametersDescription
apt_install(packages)list[str]Install system packages via apt-get
pip_install(packages)list[str]Install Python packages via pip
run_commands(*cmds)str (variadic)Run shell commands during build
env(vars)dict[str, str]Set environment variables
workdir(path)strSet default working directory
add_file(remote_path, content)str, strEmbed a file with inline content
add_local_file(local_path, remote_path)str, strRead a local file into the image
add_local_dir(local_path, remote_path)str, strRead a local directory into the image

image.to_dict(): dict

Returns the image manifest as a plain dict.

image.cache_key(): str

Computes a deterministic SHA-256 hash of the manifest for cache lookups.

Snapshots

Standalone class — not a property on Sandbox.

Snapshots(api_key=..., api_url=...)

from opencomputer import Snapshots

snapshots = Snapshots()
# or with explicit config:
snapshots = Snapshots(api_key="...", api_url="...")
ParameterTypeDescription
api_keystrAPI key (falls back to OPENCOMPUTER_API_KEY env var)
api_urlstrAPI URL (falls back to OPENCOMPUTER_API_URL env var)

await snapshots.create(name, image, on_build_logs=None): dict

Create a pre-built snapshot from a declarative image.
ParameterTypeRequiredDescription
namestrYesUnique snapshot name
imageImageYesDeclarative image definition
on_build_logsCallable[[str], None]NoBuild log streaming callback

await snapshots.list(): list[dict]

List all snapshots for the current organization.

await snapshots.get(name): dict

Get a snapshot by name.

await snapshots.delete(name): None

Delete a snapshot. Existing sandboxes created from it are not affected.

SnapshotInfo

Snapshot methods return dicts with these fields:
{
    "id": str,           # Unique snapshot identifier
    "name": str,         # Snapshot name
    "status": str,       # "building" | "ready" | "failed"
    "contentHash": str,  # SHA-256 hash of the image manifest
    "checkpointId": str, # Linked checkpoint ID
    "manifest": dict,    # The declarative image manifest
    "createdAt": str,    # ISO 8601 creation timestamp
    "lastUsedAt": str,   # ISO 8601 last usage timestamp
}

Secret Stores

await SecretStore.create(**kwargs)

Create a new secret store.
from opencomputer import SecretStore

store = await SecretStore.create(
    name='my-agent-secrets',
    egress_allowlist=['api.anthropic.com'],
)
name
str
required
Store name (unique per organization).
egress_allowlist
list[str] | None
default:"None"
Allowed egress hosts (e.g. ["api.anthropic.com"]).
Returns: dict — Secret store info with id, name, egressAllowlist, etc.

await SecretStore.list(**kwargs)

List all secret stores.
stores = await SecretStore.list()
Returns: list[dict]

await SecretStore.get(store_id, **kwargs)

Get a secret store by ID.
store = await SecretStore.get('store-uuid')
store_id
str
required
UUID of the secret store.
Returns: dict

await SecretStore.update(store_id, **kwargs)

Partial updates — only the fields you pass are changed.
updated = await SecretStore.update(
    'store-uuid',
    name='new-name',
    egress_allowlist=['api.anthropic.com', '*.openai.com'],
)
store_id
str
required
UUID of the store to update.
name
str
default:""
New store name (empty = no change).
egress_allowlist
list[str] | None
default:"None"
New allowed egress hosts (None = no change).
Returns: dict

await SecretStore.delete(store_id, **kwargs)

Deletes the store and all its secrets. Running sandboxes are not affected.
await SecretStore.delete('store-uuid')
Returns: None

await SecretStore.set_secret(store_id, name, value, **kwargs)

Set a secret in a store. Secrets are encrypted at rest. The value is never returned by the API.
await SecretStore.set_secret('store-uuid', 'ANTHROPIC_API_KEY', 'sk-ant-...')
Optionally restrict which hosts can receive this secret:
await SecretStore.set_secret(
    'store-uuid',
    'ANTHROPIC_API_KEY',
    'sk-ant-...',
    allowed_hosts=['api.anthropic.com'],
)
store_id
str
required
UUID of the secret store.
name
str
required
Secret name (used as the env var name in sandboxes).
value
str
required
Secret value (encrypted at rest, never returned by API).
allowed_hosts
list[str] | None
default:"None"
Restrict this secret to specific hosts only.
Returns: None

await SecretStore.list_secrets(store_id, **kwargs)

Returns secret metadata only. Values are never exposed.
entries = await SecretStore.list_secrets('store-uuid')
# [{'name': 'ANTHROPIC_API_KEY', 'allowedHosts': ['api.anthropic.com'], ...}, ...]
Returns: list[dict]

await SecretStore.delete_secret(store_id, name, **kwargs)

await SecretStore.delete_secret('store-uuid', 'DATABASE_URL')
Returns: None

Creating a Sandbox with a Secret Store

Pass the secret_store parameter to Sandbox.create() to inject the store’s secrets:
from opencomputer import Sandbox

sandbox = await Sandbox.create(
    secret_store='my-agent-secrets',
    timeout=600,
)

# Secrets are available as sealed env vars
result = await sandbox.commands.run('echo $ANTHROPIC_API_KEY')
# stdout: "osb_sealed_abc123..." (sealed, not the real key)

# But outbound HTTPS requests get the real value substituted by the proxy
api_result = await sandbox.commands.run(
    'curl -s https://api.anthropic.com/v1/messages -H "x-api-key: $ANTHROPIC_API_KEY" ...'
)
# The proxy replaces the sealed token with the real key before it hits Anthropic