Agent Sandbox Registry

python-sdk

A provider is a sandbox backend

docs/en/guide/providers.md

Providers

Note: The abx provider ... commands on this page are provided by the Node.js CLI in the cli repository. Python-only users get the same operations from python -m agent_sandbox.providers .... Both use the same install directory, the same receipts and the same tree digest.

A provider is a sandbox backend. Agent Sandbox ships one built-in provider and can load more from plugins.

Id Name Kind Default
alicloud-express Alibaba Cloud Express Edition (阿里云极速版) built-in yes

If you never touch providers, nothing changes: every command, every output and every environment variable behaves as before. The id alicloud-express is stable. Only the display name may change.


Choosing a provider

Highest priority first:

Where Example
SDK argument await Sandbox.create(provider="my-cloud")
CLI flag abx create --provider my-cloud
Process environment export ABX_PROVIDER=my-cloud
./.env ABX_PROVIDER=my-cloud
~/.abx/.env ABX_PROVIDER=my-cloud
~/.abx/config.toml [core] provider = "my-cloud" (written by abx provider default my-cloud)
Built-in alicloud-express
from agent_sandbox.api.sandbox import Sandbox

sb = await Sandbox.create(template="base")                          # alicloud-express
sb = await Sandbox.create(template="base", provider="local-process")
sb = await Sandbox.create(provider="my-cloud", provider_options={"cluster": "prod"})
print(sb.provider)                                                  # "my-cloud"
await sb.kill()
await sb.close()                                                    # releases the provider process

Sandbox.connect, Sandbox.list and Sandbox.kill_by_id accept the same provider= argument. A sandbox id belongs to the provider that created it. Pass a qualified reference such as my-cloud:sbx-1 to connect and the provider is taken from the prefix. Conflicting provider= and prefix raise ProviderMismatchError (E8030).

Default provider management:

abx provider list
abx provider default my-cloud       # persist in ~/.abx/config.toml
abx provider default                # show the current default
abx provider default alicloud-express

Installing a provider plugin

abx provider install ./my-provider                          # a local directory
abx provider install https://github.com/acme/abx-provider-acme.git --ref 3f2c...   # a full commit
abx provider install git@github.com:acme/abx-provider-acme.git --ref v1.2.0 --allow-unpinned
abx provider list
abx provider info my-cloud
abx provider update my-cloud --check
abx provider uninstall my-cloud

Without the CLI:

python -m agent_sandbox.providers install ./my-provider
python -m agent_sandbox.providers list --json
python -m agent_sandbox.providers update my-cloud --check
python -m agent_sandbox.providers doctor my-cloud
python -m agent_sandbox.providers test my-cloud       # the contract suite (needs pytest)

What install does and does not do

Update and uninstall

provider update re-fetches from the recorded source. If the command, the security block, or the feature list changed, you must consent again. Installs that are pinned (a 40-hex commit or --sha256) do not move: update reports pinned and does nothing unless you pass a new --ref. update takes the same transport and verification flags as install: --ref, --check, --yes, --allow-unpinned, --allow-insecure-transport (the receipt does not remember that you used it; a file://, http:// or git:// source needs it on every update) and --no-verify (skip the post-update handshake). The previous version stays in a trash directory until the new one starts successfully, then it is dropped. If the new version fails (for example its handshake), the previous files and its data/ directory are restored exactly. provider uninstall removes the directory; stored settings ([providers.<id>], ABX_<ID>_*) stay unless you pass --purge. Uninstalling the default provider resets the default to alicloud-express.

Where things live

~/.abx/providers/
  <id>/
    abx-provider.toml     # manifest
    ...                   # plugin files
    .abx-install.json     # receipt: source, commit, digest, consent
    data/                 # the plugin's working and state directory (not hashed)

Everything outside data/ is hashed into the digest, including a tests/ directory: tests you ship are installed and change the digest, so keep large test suites out of the repository path you install (use --subdir) or accept the extra files.


Provider kinds

Kind What it is Installable Works from
builtin alicloud-express n/a SDK and CLI
rest A manifest only: an E2B-protocol endpoint with its own base URL and key yes SDK and CLI
exec A program that speaks EPP/1 (JSON-RPC 2.0, one JSON object per line, over stdin/stdout) yes SDK and CLI
python A Provider subclass registered in-process no (pip entry point or register_provider) SDK only

The exec kind is the primary extension point: one plugin works for both the Python SDK and the Node CLI, in any language. A backend that already speaks the E2B envd data-plane protocol only needs to implement the control plane (create, connect, list, kill) and return the envd URL; commands, files and terminals then use the fast native transports. A backend without envd implements the data-plane methods (exec.run, files.*) as well.

Capability matrix

A provider declares the features it implements. Calling something it lacks raises ProviderFeatureNotSupportedError (E8004, also a CapabilityNotSupportedError), never an AttributeError or HTTP 404.

Feature What it covers
sandbox.lifecycle create, connect, list, info, kill
sandbox.timeout, sandbox.pause change TTL; pause and resume
exec.run, exec.stream, process.manage buffered commands; streamed output; list, kill and signal processes
pty interactive terminal
files.rw, files.watch, files.transfer read, write, list, move, remove; watching; signed upload and download URLs
code.interpret stateful code contexts
templates.read, templates.build list and inspect templates; build, deploy and delete them
ports.url, ports.domain public URL for a port; custom domains
storage.mount, network.vpc object-storage mounts; VPC attachment
sessions the sandbox survives the process and can be re-attached by id

alicloud-express implements all 18 features. abx provider list shows the declared features of every provider on one line (sandbox(lifecycle,pause) exec(run,stream) files(rw) ...; python -m agent_sandbox.providers list prints the same), and abx provider info <id> shows the full list.

The manifest flag is enforced at run time, for every provider kind:

Kind Where an undeclared feature is stopped Result
exec the EPP adapters, before the request is written to the plugin E8004
rest feature_gate around the built-in protocol classes, before any HTTP request E8004
python Provider.require(feature) in the provider's own code E8004

A feature that is declared but fails inside the backend is not E8004; the backend's error is mapped (see Errors below). Two different "not found" outcomes are kept apart on purpose: an unknown sandbox id is SandboxNotFoundError (E2009) on every provider and every sandbox.* call (connect, info, set_timeout, pause, resume; kill stays idempotent), and a missing template, file or process is E4001/E2001 or, with no sdk_code, ProviderResourceNotFoundError (E8005).

What you can call after installing

Installing a provider does not enable every SDK method or every abx command. The SDK and the CLI call the same installed plugin. Each method and command needs one feature from the table above. If the plugin does not declare it, the call raises ProviderFeatureNotSupportedError (E8004) before any request is sent. exec and rest plugins work from both hosts. A python provider registered in-process works from the SDK only.

Feature Python SDK CLI
sandbox.lifecycle Sandbox.create, connect, list, kill, info create, list, info, kill, connect
sandbox.timeout set_timeout sandbox timeout
sandbox.pause pause, resume sandbox pause, sandbox resume
exec.run commands.run, sandbox.run exec, run
exec.stream commands.stream sandbox shell-stream
process.manage commands.list, kill, send_stdin sandbox process ...
pty get_terminal PTY session
files.rw files.* upload, download, sandbox files ...
files.watch files.watch —
files.transfer signed upload and download URLs —
code.interpret run_code sandbox code
templates.read template read APIs template list, template info
templates.build image build and template registration template build/push/create/deploy/install/delete, deploy, install
ports.url network.get_url sandbox url
ports.domain custom domain configuration —
storage.mount OSS mount —
network.vpc VPC configuration --vpc-id family
sessions Sandbox.connect on an existing id connect <provider:id>

OpenSandbox

abx provider install alibaba-agent-sandbox/awesome-providers//opensandbox

//opensandbox is the directory inside the catalog, the same spelling as abx template install alibaba-agent-sandbox/awesome-templates//python-hello. Then:

sb = await Sandbox.create(template="base", provider="opensandbox")
proc = await sb.commands.run("echo hello")
await sb.files.write("/tmp/note.txt", "hello")
print(await sb.files.read("/tmp/note.txt"))
await sb.kill()

Verified status (2026-10-13), against a real opensandbox-server 1.1.1 with the Docker runtime, from the Node CLI and from Sandbox.create(provider="opensandbox") (evidence: 2026-10-13-opensandbox-provider-e2e):

Works (run for real) Does not work
install pinned from git, doctor, the 18-case contract kit (18/18 on both hosts); create with an image URI, info, list, connect by id, kill (idempotent), E2009 for a killed sandbox; commands.run exit code, stderr, env; 300 KB binary and unicode file round trip, directory listing, typed E4001 for a missing file; process list (3 processes); set_timeout, pause (status paused), resume (command runs again); network.resolve(9000) (server proxy URL); tampering with an installed file stops every command with E8011 run_code, PTY, files.watch, template build/deploy, signed transfer URLs, domains, OSS, VPC: all answer E8004 naming the feature. Not verified: the egress sidecar network policy (network_policy option), private registries, the secure_access token flow, exec with process.manage send_stdin

One gap that was found and is not a provider problem: the awesome-providers catalog still ships the pre-rename ebx-provider.toml, so installing it straight from GitHub fails with E8014 (no abx-provider.toml at the plugin root).

OpenSandbox declares nine features: sandbox.lifecycle, sandbox.timeout, sandbox.pause, exec.run, exec.stream, process.manage, files.rw, ports.url, sessions. Those SDK methods and the matching CLI commands work. These do not, and raise E8004: run_code, PTY, template list/build/deploy, file watch, signed transfer URLs, custom domains, OSS, VPC. Process list, kill, and signal work; send_stdin raises E8004, and killing an execd command id is SIGKILL only.

The plugin is Node.js with no npm packages, so the SDK needs node on PATH. The default server is http://127.0.0.1:8080 (providers.opensandbox.base_url). A template name is a container image; base means python:3.12-slim unless default_image is set. Field-by-field notes: opensandbox/README.md.


Writing a provider

A plugin is a directory with abx-provider.toml and the program it runs.

manifest_version = 1

[provider]
id      = "local-process"
name    = "Local Process"
name_zh = "本地进程"
version = "0.1.0"

[compat]
protocol = "epp/1"

[runtime]
kind    = "exec"
command = ["python3", "./provider.py"]   # argv list, never a shell string; "./" is relative to the plugin directory

[features]
supported = ["sandbox.lifecycle", "exec.run", "files.rw"]

[security]                               # shown at install and recorded; advisory, not enforced
filesystem       = ["data_dir"]
spawns_processes = true

[core]
inherit = []                             # generic keys the plugin wants; needs user consent

[config.fields.workdir_root]             # the plugin's own settings: ABX_LOCAL_PROCESS_WORKDIR_ROOT
type    = "path"
required = false
description = "Directory that holds sandbox working directories"

Two working examples are in this repository:

The OpenSandbox plugin is a separate installable provider, not part of this repository: opensandbox in alibaba-agent-sandbox/awesome-providers. It is a dependency-free Node exec provider for an OpenSandbox server (streaming exec, files, process control, pause/resume, port URLs, mock-server and live tests). Install it with abx provider install alibaba-agent-sandbox/awesome-providers//opensandbox.

Authoring checklist

  1. Manifest: manifest_version = 1, a valid id, [compat] protocol = "epp/1" and requires, [runtime] kind = "exec" (or a rest endpoint), [config.fields.*] for every option with secret = true on secrets and env = [...] for the vendor's own variable names. Errors are E8014 with the broken field named.
  2. Required methods: initialize (return the features you implement), shutdown, and for sandbox.lifecycle sandbox.create|get|list|kill. Everything else is per feature (see "Methods a plugin answers").
  3. Feature flags: declare exactly what works and nothing else. The host answers E8004 for the rest without calling you.
  4. Errors: -32003 for a feature you lack, -32002 for a missing sandbox (sdk_code E2009 if you want to be explicit), sdk_code on everything that has an SDK class, never a credential in a message.
  5. Conformance: python -m agent_sandbox.providers test <id> (or abx provider test <id>) must pass; skipped cases are the features you did not declare.
  6. Publish: pinned install line with a 40-hex commit, an honest [security] block, the consent-screen contents in the README.

Development loop: python -m agent_sandbox.providers install ./my-provider --link --yes installs a symlink with no digest check, so edits take effect immediately. Run doctor, then test (below), then install a pinned copy for real use.

Methods a plugin answers

The wire methods, their parameter names and types, and which are required are listed in the EPP method table and, machine-readably, in tests/fixtures/epp-methods.json of the SDK repository (the CLI keeps an identical copy). In short:

What reaches sandbox.create

Sandbox.create(..., provider="my-cloud", provider_options={...}, secure=...) sends:

Param When
template, timeout, metadata, envs, cpu, memory, disk, gpu, request_timeout always
secure only when the caller passed secure=True/False; absent otherwise, so the plugin's own default applies (the built-in provider behaves as secure=True)
options the provider_options the caller passed (declared config fields only), without secret fields; use them for per-create settings such as a network policy, platform or image pull settings

sandbox.network.get_url(port) stays a local, synchronous computation. await sandbox.network.resolve(port) returns (url, headers) and await sandbox.network.resolve_url(port) the URL; both ask the plugin's ports.url when the provider declares it and fall back to the local computation otherwise.

sandbox.commands.start() (and run(..., background=True)) returns a lazy stream for every provider: nothing is sent until the stream is iterated. To start work and not wait, run nohup ... & through commands.run(..., shell=True), or use the sessions feature.

Configuration and credentials

Each provider has its own scoped keys: ABX_<PROVIDER>_<KEY> in the environment or .env, [providers.<id>] in config.toml, provider_options={...} in the SDK. The provider receives only the keys its manifest declares, in the initialize request. Secrets are never put in the plugin's argv or environment.

The generic keys sandbox_api_key, sandbox_base_url and sandbox_domain (ABX_SANDBOX_API_KEY and ABX_SANDBOX_BASE_URL) belong to the built-in provider. A plugin gets them only if its manifest lists them in [core] inherit and you consented at install or update time. The consent screen names the keys. Your LLM, GitHub and MCP keys are never delivered to a provider.

What the host does to the plugin process

No isolation. A plugin is third-party code that runs with your user privileges and your credentials for that provider. Install only code you trust. Pinning, digest verification and consent narrow the risk; they do not sandbox the process. The [security] block is a declaration shown to you, not a restriction.

Errors

The host maps plugin errors onto the existing exception hierarchy, so scripts see the same exception types and CLI exit codes for every provider.

EPP code Raised as CLI exit
-32001 unauthenticated AuthenticationError family (E1xxx) 3
-32002 not found SandboxNotFoundError (E2009) for a sandbox.* call on an existing id; otherwise ProviderResourceNotFoundError (E8005), or the class named by data.sdk_code 4
-32003 feature not supported ProviderFeatureNotSupportedError (E8004) 1
-32004 quota exceeded QuotaExceededError 6
-32005 timeout ProviderTimeoutError (E8022) or CommandTimeoutError 5
-32006 invalid params or config ProviderConfigError (E8002) 2
-32000 other failure class by data.sdk_code, else ProviderError (E8000) 1
JSON-RPC standard codes ProviderProtocolError (E8020) 1

The full E8xxx list is in the error code reference.

Testing a plugin

Three ways to run the contract suite, from least to most work. The suite only exercises the features the plugin declares and skips the rest (a skipped test is not a failure).

# 1. One command, no test file. Fails when nothing was collected.
python -m agent_sandbox.providers test my-cloud --option base_url=http://127.0.0.1:8080
python -m agent_sandbox.providers test my-cloud -- -k exec -x      # extra pytest arguments after --

# 2. Plain pytest, no test file
pytest -p agent_sandbox.providers.testing --pyargs agent_sandbox.providers.contract \
       --provider-under-test my-cloud --provider-option base_url=http://127.0.0.1:8080
# 3. A subclass in your plugin's own tests
from agent_sandbox.providers.testing import ProviderContractTests

class TestMyProvider(ProviderContractTests):
    provider_id = "my-cloud"          # an installed provider
    provider_options = {}

(--provider-under-test and --provider-option KEY=VALUE, repeatable, are registered when agent_sandbox.providers.testing is loaded as a pytest plugin with -p. ABX_PROVIDER_UNDER_TEST sets the default. With no provider selected the suite fails instead of skipping.)

What it checks: declared features are known; secret fields have no default; lifecycle (create, connect, list, kill, unknown id is E2009); kill is idempotent; set_timeout; pause and resume; exec.run exit codes, stderr and env; streamed output order with exactly one final exit; that a command timeout is enforced; process listing; files (text, binary, unicode, directories, move, remove, missing file is a typed not-found); ports.url; that features you did not declare fail with E8004 (a CapabilityNotSupportedError); and that secret option values never appear in error text.

Offline testing: the kit needs a working backend. For a plugin that talks to HTTP, write a small mock server and drive the plugin over stdio with a tiny JSON-RPC client. The opensandbox plugin has both (tests/mock/, tests/epp-client.mjs).

Check an installed provider's wiring without running a sandbox:

python -m agent_sandbox.providers doctor my-cloud          # manifest, digest, handshake, credentials
python -m agent_sandbox.providers doctor my-cloud --no-handshake

Running pytest from a directory that has an unrelated conftest.py? Add --noconftest (or --confcutdir). python -m agent_sandbox.providers test already isolates itself from the current directory's pytest configuration.


Python plugins (SDK only)

from agent_sandbox.providers import Provider, register_provider

class MyProvider(Provider):
    id = "my-cloud"
    ...

register_provider(MyProvider())

A package can also publish an entry point in the group agent_sandbox.providers that points to a Provider instance or a zero-argument factory; it is loaded the first time providers are listed. These providers run in your process with full trust, so they cannot be installed by abx provider install.


See also