Sandbox templates
Portable sandbox templates from the CLI — capture a provider/runtime/tools config once, bind agents to it, and move it between workspaces as a manifest that never carries secret values.
When an agent runs code it does so inside a sandbox — a provisioned, isolated environment with a provider (Modal, Vercel, or Docker), a runtime image, resource caps, a network posture, some non-secret config, a set of preloaded tools, and the workspace secrets it is allowed to see. A sandbox template captures that whole recipe once, under an environment, so every agent bound to it provisions the same way. Templates are portable: you can export one as a manifest and import it into another workspace or organization.
A manifest never carries secret values. Export writes the required secret key names only (e.g. EVAL_API_KEY), so a shared template shows the recipient exactly which credentials to fill in — without ever leaking yours. Import upserts those empty key rows into the destination vault.
Everything here requires platform auth (oxagen login), and template writes are Owner/Admin only. The same capabilities back the API, MCP tools, and the app — the CLI is just the flag-driven surface.
Environments
A template always lives under an environment (env_…). Manage those with oxagen env; most template commands take --env <slug> to pick or disambiguate one. Secrets are managed per-environment with oxagen secret — a template's secretSelection decides which of those keys resolve into the sandbox at run time.
List and inspect
oxagen sandbox template list # every template in the workspace
oxagen sandbox template list --env staging # just one environment
oxagen sandbox template list --json # machine-readable, for scripting
oxagen sandbox template get swe-bench-prewarmed
oxagen sandbox template get sbx_abc123 --jsonget accepts a slug or a sbx_… public id. When a slug is ambiguous across environments, add --env <slug> to pin it. In pretty mode it prints the resources, network mode, secret selection, literal env, and preloaded tools; --json emits the full template object on one line.
Create a template
oxagen sandbox template create \
--env staging \
--name "SWE-bench prewarmed" \
--slug swe-bench-prewarmed \
--provider modal \
--runtime "ghcr.io/acme/swe-bench-prewarmed@sha256:…" \
--vcpu 2 --memory-mb 4096 --timeout-ms 300000 \
--network-mode public \
--env-var SWEBENCH_SPLIT=verified \
--set-defaultOnly --env, --name, and --slug are required; every other field falls back to a driver default. Notes:
--providerismodal,vercel, ordocker. The provisioner fails fast if that driver has no credentials configured.- Resource caps are bounded:
--vcpu≤ 4,--memory-mb≤ 8192,--timeout-ms≤ 300000,--disk-mb≤ 20480. Each must be a positive integer. --network-modeis one ofpublic,static_egress,aws_privatelink,gcp_psc,reverse_tunnel,ssh_bastion. Onlypublicandstatic_egressare implemented today; the others fail fast at provision time.--env-var KEY=valueis repeatable and is for non-secret literal config only — injected at lowest precedence. Real credentials belong in the vault (oxagen secret set), never here.--set-defaultpromotes the new template to its environment's default. Runs that don't name a template resolve to it.
Exactly one template per (workspace, environment) is the default. --set-default atomically swaps it.
Promote a default, remove a template
oxagen sandbox template set-default python-worker --env staging
oxagen sandbox template rm old-worker --env staging --yesrm soft-deletes and requires --yes. A default template can't be deleted — promote another one in the same environment first.
Export and import (portability)
Export a template to a portable manifest — to stdout by default, or to a file:
oxagen sandbox template export swe-bench-prewarmed # prints JSON
oxagen sandbox template export swe-bench-prewarmed -o swe.json # writes a fileImport is preview-then-commit, like oxagen secret import. Without --yes you get a summary and warnings and nothing is written:
# Preview only — no changes:
oxagen sandbox template import --env staging -f swe.json
# Apply it, overriding the slug to avoid a collision, as the new default:
oxagen sandbox template import --env staging -f swe.json --slug swe-2 --set-default --yesThe preview flags required secret keys (created empty in the destination — fill them before provisioning) and any structural problems. On commit the server is the authoritative validator and returns warnings for a slug collision or for tool refs not installed in the destination workspace — those tools are simply skipped at provision time, so a template stays portable even if the target hasn't installed every plugin it references.
Bind an agent to an environment
A template only takes effect once an agent is pointed at its environment. Bind a platform agent (a agt_… id, slug, or agent-key) with oxagen agent env:
oxagen agent env bind coder --env staging --template swe-bench-prewarmed --primary
oxagen agent env list coder
oxagen agent env unbind coder --env stagingOmit --template to bind to the environment and let it resolve to that environment's default template at run time. The agent's first binding becomes its primary automatically; --primary promotes another and atomically demotes the previous. Unbinding the primary falls back to the workspace default environment and its default template.
Scripting
Every read supports --json (one JSON value on stdout; progress and warnings stay on stderr), so templates compose cleanly with jq:
# The default template's runtime image in staging:
oxagen sandbox template list --env staging --json \
| jq -r '.[] | select(.isDefault) | .runtime'
# Copy a template from one workspace to another:
oxagen sandbox template export swe-bench-prewarmed -o /tmp/t.json
OXAGEN_WORKSPACE_ID=ws_other oxagen sandbox template import --env default -f /tmp/t.json --yes