OpenSandbox CLI
osb is the command-line interface for OpenSandbox. It is built for the common day-to-day flows:
- create and manage sandboxes
- run commands inside a sandbox
- read and modify sandbox files
- inspect runtime egress policy
- manage sandbox-local Credential Vault state
- collect low-level diagnostics
- install OpenSandbox-specific skills for coding agents
It uses the OpenSandbox Python SDK under the hood and is intended to be the shortest path from a terminal to a working sandbox workflow.
Install
pip install opensandbox-cliuv tool install opensandbox-clipipx install opensandbox-cliConfirm the install:
osb --help
osb --versionBefore You Start
Make sure an OpenSandbox server is reachable. If you are running locally, start the server first and then point the CLI at it.
opensandbox-serverQuick Start
1. Initialize config
osb config init
osb config set connection.domain localhost:8080
osb config set connection.protocol http
osb config set connection.api_key <your-api-key>
osb config show -o jsonIf you want a non-default config file, choose it at the root command level for the whole invocation:
osb --config /tmp/dev.toml config init
osb --config /tmp/dev.toml config set connection.domain localhost:8080
osb --config /tmp/dev.toml config show -o json2. Create a sandbox
osb sandbox create --image python:3.12 --timeout 30m -o jsonIf you set defaults first, later create commands can be shorter:
osb config set defaults.image python:3.12
osb config set defaults.timeout 30m
osb sandbox create -o json3. Verify it is usable
osb sandbox get <sandbox-id> -o json
osb sandbox health <sandbox-id> -o json4. Run a command inside the sandbox
Use -- before the sandbox command payload.
osb command run <sandbox-id> -o raw --argv -- python -c "print(1 + 1)"5. Read or write a file
osb file write <sandbox-id> /tmp/hello.txt -c "hello" -o json
osb file cat <sandbox-id> /tmp/hello.txt -o raw6. Clean up
osb sandbox kill <sandbox-id> -o jsonCommon Tasks
Create sandboxes
Basic:
osb sandbox create --image python:3.12Private image:
osb sandbox create \
--image my-registry.example.com/team/app:latest \
--image-auth-username alice \
--image-auth-password <token>Manual cleanup mode:
osb sandbox create --image python:3.12 --timeout noneExplicit entrypoint argv:
osb sandbox create \
--image python:3.12 \
--entrypoint python \
--entrypoint -m \
--entrypoint http.serverCreate with network policy and volumes:
osb sandbox create \
--image python:3.12 \
--network-policy-file network-policy.json \
--volumes-file volumes.jsonCreate with Credential Vault proxy enabled:
osb sandbox create --image python:3.12 --network-policy-file network-policy.json --credential-proxy -o jsonList and inspect sandboxes
osb sandbox list
osb sandbox list -o json
osb sandbox list --state running --state paused
osb sandbox get <sandbox-id> -o json
osb sandbox metrics <sandbox-id>
osb sandbox metrics <sandbox-id> --watch -o rawPause, resume, and renew
osb sandbox pause <sandbox-id> -o json
osb sandbox get <sandbox-id> -o json
# Repeat get with a deadline until status.state is Paused; stop on Failed.
# Only then resume:
osb sandbox resume <sandbox-id> --resume-timeout 60s -o json
osb sandbox renew <sandbox-id> --timeout 30m -o jsonPause is asynchronous. A successful pause response means the request was accepted. See Pause and Resume for runtime-specific behavior.
Expose a service
osb sandbox endpoint <sandbox-id> --port 8080 -o jsonUse the returned endpoint and headers together. The command resolves a route; it does not start a service or prove that the application is healthy.
Run commands
Foreground streaming:
osb command run <sandbox-id> -o raw -- sh -lc 'echo ready'Tracked background execution:
osb command run <sandbox-id> --background -o json -- sh -c "sleep 10; echo done"
osb command status <sandbox-id> <execution-id> -o json
osb command logs <sandbox-id> <execution-id> -o jsonBy default the CLI shell-quotes each argument and joins them into a command string. To use pipelines, redirection, or sandbox-side variable expansion, pass an explicit shell and script:
osb command run <sandbox-id> -o raw -- sh -c 'echo "$HOME"; printf "ready\n" | cat'Use --argv for native execution without a shell. It requires execd support for the argv request field:
osb command run <sandbox-id> -o raw --argv -- python3 -c "import sys; print(sys.argv[1:])" "a b" '$HOME' "x'y" ""
osb command interrupt <sandbox-id> <execution-id> -o jsonForeground command run accepts -o raw; background execution accepts table, json, or yaml.
Persistent shell session:
osb command session create <sandbox-id> --workdir /workspace -o json
osb command session run <sandbox-id> <session-id> -o raw -- pwd
osb command session run <sandbox-id> <session-id> -o raw -- export FOO=bar
osb command session run <sandbox-id> <session-id> -o raw -- sh -c 'echo $FOO'
osb command session delete <sandbox-id> <session-id> -o jsonWork with files
osb file upload <sandbox-id> ./local.txt /workspace/local.txt -o json
osb file download <sandbox-id> /workspace/result.json ./result.json -o json
osb file search <sandbox-id> /workspace --pattern "*.py" -o json
osb file info <sandbox-id> /workspace/main.py -o json
osb file replace <sandbox-id> /workspace/app.py --old old --new new -o json
osb file chmod <sandbox-id> /workspace/script.sh --mode 755 -o jsonFor regular files, file download replaces the local destination only after the entire download succeeds. If the download fails or you interrupt it, an existing file stays unchanged and temporary download files are removed. The destination directory must be writable so the CLI can stage the download before replacing the file.
Existing devices (such as /dev/null) and named pipes receive the download directly. They are not replaced, and bytes already written cannot be rolled back if the download fails or is interrupted.
Destinations that refer to standard output, such as /dev/stdout and /dev/fd/1, stream directly even when stdout is redirected to a regular file. These downloads omit the success message in all output formats so stdout contains only file bytes; errors still go to stderr. A failed or interrupted stream can contain partial data.
Manage runtime egress policy
Inspect current policy:
osb egress get <sandbox-id> -o jsonPatch specific rules:
osb egress patch <sandbox-id> --rule allow=pypi.org --rule deny=internal.example.com -o jsonIf you are debugging connectivity, verify behavior with an actual command:
osb command run <sandbox-id> -o raw -- curl -I https://pypi.orgManage Credential Vault
Credential Vault operations call the sandbox egress sidecar through the Python SDK. Create the sandbox with --credential-proxy and an explicit network policy before writing vault state. Template-backed sandboxes do not support Credential Vault. See Credential Vault for payload examples and revision checks.
osb credential-vault create <sandbox-id> --file vault.yaml -o json
osb credential-vault get <sandbox-id> -o json
osb credential-vault patch <sandbox-id> --file mutation.yaml -o json
osb credential-vault credential list <sandbox-id> -o json
osb credential-vault binding list <sandbox-id> -o json
osb credential-vault delete <sandbox-id> -o jsonWARNING
Use --file - to read a JSON/YAML payload from stdin. Do not pass plaintext credential values as command-line flags; keep them in the payload stream or file.
Collect diagnostics
Use the stable diagnostics commands for API-backed log and event descriptors.
osb diagnostics events <sandbox-id> --scope runtime -o raw
osb diagnostics events <sandbox-id> --scope all -o raw
osb diagnostics logs <sandbox-id> --scope container -o raw
osb diagnostics logs <sandbox-id> --scope all -o json
osb diagnostics events <sandbox-id> --scope runtime -o json
osb diagnostics logs <sandbox-id> --scope container -o yaml--scope is required for stable diagnostics. The built-in server supports container and all for logs, and runtime and all for events. Docker/Kubernetes return DIAGNOSTICS_SCOPE_UNSUPPORTED for unavailable scopes, including lifecycle events. Best-effort scopes may include a warnings field when the backend can only provide a subset. Raw output prints inline diagnostic text, or the content URL when diagnostics are delivered as a temporary URL; raw output does not download that URL. JSON/YAML use Python model names such as content_url, content_type, and expires_at (the HTTP API uses camelCase). See Diagnostics for runtime differences. Older server builds may still return DIAGNOSTICS_NOT_IMPLEMENTED for scoped diagnostics.
INFO
Legacy DevOps diagnostics remain experimental. Prefer osb diagnostics logs/events for stable API-backed log and event collection.
osb devops inspect <sandbox-id> -o raw
osb devops summary <sandbox-id> -o rawOutput Formats
Output selection is command-scoped, not global.
table: human-readable tables and panelsjson: machine-readable JSONyaml: machine-readable YAMLraw: unformatted text or streaming output
Examples:
osb sandbox list -o json
osb sandbox list -o yaml
osb file cat <sandbox-id> /workspace/hello.txt -o rawNot every command supports every format. Use --help on the specific command when in doubt.
Command Groups
The main command groups are:
osb sandbox: lifecycle managementosb command: command execution and persistent sessionsosb file: file and directory operationsosb egress: runtime egress policyosb credential-vault: sandbox-local credentials and bindingsosb diagnostics: stable diagnostics logs and eventsosb devops: experimental legacy diagnosticsosb config: local CLI configurationosb skills: bundled skills for AI tools
The CLI currently exposes image-backed creation. It does not provide snapshot or template management, Client Pool, or pool tracing commands; use the SDK/API for those workflows. A feature in the Python SDK is not automatically a CLI command.
Explore them directly:
osb sandbox --help
osb command --help
osb file --help
osb skills --helpAgent Skills
The CLI ships with built-in OpenSandbox skills for coding agents and agent-oriented tools.
Bundled skills:
sandbox-lifecyclecommand-executionfile-operationsnetwork-egresssandbox-troubleshooting
Supported targets:
| Target | Install location |
|---|---|
claude | ./.claude/skills/ or ~/.claude/skills/ |
cursor | ./.cursor/rules/ or ~/.cursor/rules/ |
codex | ./.codex/skills/<name>/SKILL.md or ~/.codex/skills/<name>/SKILL.md |
copilot | ./.github/copilot-instructions.md or ~/.github/copilot-instructions.md |
windsurf | ./.windsurfrules or ~/.windsurfrules |
cline | ./.clinerules or ~/.clinerules |
opencode | ./.agents/skills/<name>/SKILL.md or ~/.agents/skills/<name>/SKILL.md |
Common flows:
osb skills list
osb skills show sandbox-lifecycle
osb skills install sandbox-lifecycle --target codex --scope project
osb skills install --all-builtins --target codex --scope global
osb skills uninstall sandbox-troubleshooting --target claude --scope globalFor scripts or agents, use structured output:
osb skills install sandbox-lifecycle --target codex --scope project -o jsonConfiguration Model
The CLI resolves configuration in this order:
- root CLI flags such as
--api-key,--domain,--protocol,--request-timeout,--config - environment variables such as
OPEN_SANDBOX_API_KEYandOPEN_SANDBOX_DOMAIN - config file, defaulting to
~/.opensandbox/config.toml - SDK defaults
Config commands:
osb config init
osb config show
osb config set connection.domain localhost:8080
osb config set connection.protocol http
osb config set defaults.image python:3.12
osb config set defaults.timeout 30mExample config file:
[connection]
api_key = "your-api-key"
domain = "localhost:8080"
protocol = "http"
request_timeout = 30
use_server_proxy = false
[output]
color = true
[defaults]
image = "python:3.12"
timeout = "30m"Development
For local development in this monorepo:
cd cli
uv sync
uv run osb --help
uv run pytestThis repository uses a local uv source override for the OpenSandbox Python SDK, so running from cli/ will resolve against the checked-out SDK in the monorepo.