Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog.

Status: superseded for catalog providers. The "Local provider engine" entry below, the one that describes gRPC on ~/.abx/engine.sock, is the earlier Python slice. The current design is the Node engine: HTTP, SSE and WebSocket, protocol abx-engine/1. See cli/docs/en/reference/engine-api.md. That entry is kept as history.

[Unreleased]

Added

  • Python MCP bounded binary upload_file/download_file (1 MiB, strict Base64, SHA256) over both transports; SDK files.read_bytes(max_bytes=...) optionally limits streamed downloads and raises FileSizeLimitError (E4003), while its existing default remains unchanged.

  • Python MCP start_task, get_task, and cancel_task provide sandbox-lifetime background handles, bounded saved log pages, explicit disconnect retention and owned process-group cancellation. Normal synchronous cleanup remains unchanged; Python-only, Linux/python3 runtime.

  • Python MCP lifecycle tools list_sandboxes, get_sandbox, and set_sandbox_timeout; creation accepts provider, region, CPU and memory options. Metadata uses a fixed allowlist, external inspection/renewal does not adopt resources, and lifecycle failures omit credential-bearing exception details.

  • Add the Chinese counterpart of the historical OpenSandbox provider research archive, preserving its versioned evidence and current-adapter boundary.

Fixed

  • Real-cloud E2E acceptance. The server fixture keeps envd credentials separate from the unconfigured template server; provider reports reject missing checks and the CLI scenario resolves ABX_BIN or an installed abx instead of assuming a sibling checkout.

  • MCP timeout typing. Keep the explicit managed-instance guard valid under the CI type checker while preserving shutdown ownership and renewal cleanup.

  • Stacked pull request validation. The complete CI matrix now runs for pull requests targeting feature branches as well as main; push validation remains limited to main.

  • MCP external metadata/timeout operations dispatch directly through Sandbox.get_info_by_id / set_timeout_by_id, closing temporary infrastructure in finally; they never call provider connect/resume and cannot wake paused instances through that connect path. Late managed TTL completion after shutdown cannot restore renewal state.

  • agent-sandbox-server serve --commands FILE registers the module before execution, fixing startup failures for dataclasses with postponed annotations. File imports reuse canonical paths, keep different files isolated, and remove incomplete module/import-path state after a failed load.

  • Source-checkout installs with uv now resolve agent-sandbox-server to the local workspace member instead of failing with a missing tool.uv.sources entry. Published dependency pins are unchanged.

[0.3.0] - 2026-10-15

Both distributions are 0.3.0. The client on PyPI is agent-sandbox-client (import agent_sandbox). agent-sandbox is an unrelated project, so do not pip install agent-sandbox. The server distribution is agent-sandbox-server. Directories, the repository, and the CLI are unchanged.

This release makes the SDK work on Alibaba Cloud Express generation 2: streaming RPCs use the Connect envelope when envd is 0.6 or newer, and Sandbox.info.envd_version is kept. Port 9000 does not send the sandbox access token to an unconfigured agent-sandbox-server. Named commands return the command value; unknown names, bad arguments, and command exceptions are typed errors. Sandbox.create_sync and connect_sync keep the class, including a subclass. The template-author quick path is in the SDK usage guide.

Changed

  • The client PyPI distribution is agent-sandbox-client. agent-sandbox on PyPI is an unrelated project (Agent Infra Team). Import agent_sandbox, the repository, the CLI, and agent-sandbox-server are unchanged. Do not run pip install agent-sandbox.
  • Catalog providers run on the Node.js host. opensandbox, e2b, cubesandbox and alicloud-container are all node plugins (OpenSandbox runs its EPP/1 methods in the host process, and node provider.mjs still serves EPP/1 on stdio); the python plugin kind is gone (a Provider subclass in code still works). The SDK reaches node plugins through the local engine (abx provider engine serve, started on demand; abx must be on PATH or in ABX_BIN). EngineProvider and EngineClient are new in agent_sandbox.providers; e2b_shape is removed. An exec plugin (third-party, any language) can now host a terminal (pty.open/write/resize/close, pty.output, pty.exit).
  • The Python project is split into two lock-step PyPI distributions in one repository (python-sdk). client-sdk/ is the agent-sandbox-client distribution (import agent_sandbox: transport, protocol, models, API, declarative @sandbox, MCP server, E2B migration helper). server-sdk/ is the new agent-sandbox-server distribution (import agent_sandbox.server): the container-side runtime that used to ship inside agent-sandbox. Both share the agent_sandbox namespace (the server distribution ships only agent_sandbox/server/ and has no agent_sandbox/__init__.py), each has its own pyproject.toml, tests, README, py.typed marker and _version.py, and both are released with the same version number (publish.yml publishes agent-sandbox-server first, then agent-sandbox-client). Migration: install the in-container runtime with pip install agent-sandbox-server (template Dockerfiles, e.g. examples/templates/python-hello). agent-sandbox-client hard-depends on agent-sandbox-server==<same version>, so pip install agent-sandbox-client still provides agent_sandbox.server; the [server] extra remains as an empty alias. from agent_sandbox.server import ... is unchanged. A server-only install has no agent_sandbox.__version__; use agent_sandbox.server.__version__.
  • Missing or broken agent-sandbox-server now raises an actionable ImportError from the @sandbox decorator's sandbox.server proxy, naming pip install agent-sandbox-server and the --force-reinstall --no-deps repair.
  • Project URLs point at the renamed repositories (agent-sandbox/python-sdk, agent-sandbox/agent-sandbox).
  • Repository plumbing follows the split. Makefile targets (install, dev, test, lint, format, format-check, typecheck, build, dist-check, ci, clean, hooks) operate on both packages; CI runs ruff, ruff format --check, mypy and pytest per package on Python 3.10/3.11/3.12, builds both distributions, runs twine check, verifies py.typed in both wheels and that client + server install into one virtualenv and import; Dependabot watches /client-sdk and /server-sdk. The packaging test (test_packaging.py) is ported to both packages (client wheel has no agent_sandbox/server, server wheel has no agent_sandbox/__init__.py).

  • Open-source hygiene. Scripts, examples and docs no longer contain developer-machine paths, a personal ACR namespace or fixed e2e tags: the e2e scripts require ACR_NAMESPACE (no personal default), the abx executable used by scripts/cloud_e2e_test.py and examples/compat-demos/e2e_capability_validation.py is resolved from PATH (override with ABX_BIN), and .env.example uses the <your-namespace> placeholder. New regression guard make hygiene (scripts/check-no-local-paths.sh, allowlist in scripts/local-paths.allowlist) runs in CI and fails on user-home paths, Windows user paths, .venv/bin assumptions, personal identifiers and key-like strings.

  • Dotenv resolution is layer first. ./.env and ~/.abx/.env used to be merged per exact variable name before name priority was applied, so ./.env: SANDBOX_API_KEY=a with ~/.abx/.env: E2B_API_KEY=b resolved to b although the documentation says the project file wins. The project file now wins (a). This is the only observable change of the new naming scheme; every other combination, including all existing tests, resolves as before.

Added

  • Official site and registry website. READMEs and the docs index name https://www.agent-sandbox.com and https://registry.agent-sandbox.com. The installer still fetches https://registry.agent-sandbox.cn/providers/index.json.
  • SDK skill. agent-sandbox-sdk/SKILL.md tells a coding agent how to write a client and a template (@command / start() under if __name__ == "__main__", FC base image for alicloud-express, generic image otherwise, the built-in provider alicloud-express). The folder name matches name. The repository-root SKILL.md is removed so a copied skill is not a second guide. Guide: sdk-skill.
  • Local provider engine (historical; superseded for catalog providers — see the status note at the top). SDKs dial gRPC on a Unix socket (~/.abx/engine.sock). The engine holds backend HTTP, SSE and WebSocket connections. Sandbox.create for the built-in Alibaba Cloud provider sends Create through the engine, which performs POST /sandboxes. Commands, files and the PTY for that sandbox also go through the engine (ExecStart, FileRead, FileWrite, FileOp, WatchDir, Pty); the SDK does not open those sockets itself. Engine.exec_sse and Engine.terminal remain loopback-only compatibility calls. The socket is mode 0600. A live socket is reused, not replaced. Health reports protocol abx.engine.v1. Start a shared process with python -m agent_sandbox.engine.
  • Provider authoring skill (agent-sandbox-provider/SKILL.md). Tells a coding agent how to add a rest, exec, or python provider: the 18 feature ids, extensions, and a credential name that is not ABX_SANDBOX_API_KEY.
  • Only alicloud-express is built in. OpenSandbox, CubeSandbox, E2B, and the container edition live in awesome-providers/ and install with registry:<id> from https://registry.agent-sandbox.cn/providers/index.json. A background check writes newer versions to ~/.abx/providers/updates.json.
  • E2B and the container edition no longer call routes those APIs do not have. Command start sends stdin: false. Directory watch reads filesystem.name / filesystem.type. The container edition lists via GET /v2/sandboxes, puts /49983 on the private envd path, runs code at port 49999, and does not declare pty. E2B connect tries POST /v2/sandboxes/{id}/connect first.
  • CubeSandbox data plane matches the current Cube SDK. envd URLs are http://49983-{id}.{domain}, a missing envdAccessToken is not an error, process RPCs use a Connect frame, run_code posts to Jupyter port 49999, and ABX_CUBESANDBOX_PROXY dials CubeProxy while keeping the virtual Host. Review: CubeSandbox.
  • E2B, CubeSandbox, and container-edition defaults match the current upstream SDKs. E2B defaults to https://api.e2b.app and domain e2b.app. CubeSandbox's domain default is cube.app. connect tries POST /sandboxes/{id}/connect before GET. Cube process and file calls send root when the user is omitted, and files.watch is declared. Readiness notes: provider-readiness.
  • Live provider end-to-end tests (e2e/test_08_providers.py). Each built-in provider is created for real when its backend is up. OpenSandbox on 127.0.0.1:8080 and Alibaba Cloud Express (SDK and CLI) are executed there. CubeSandbox, E2B, and the container edition skip when their own endpoint or key is absent, and they do not reuse the Express key.
  • Catalog providers besides Express. alicloud-container, cubesandbox, e2b, and opensandbox install from awesome-providers with registry:<id>. They are not compiled into the SDK. alicloud-container is the ACS/ACK sandbox-manager. cubesandbox speaks CubeAPI (default http://127.0.0.1:3000). e2b speaks https://api.e2b.app with ABX_E2B_API_KEY. OpenSandbox talks HTTP from the Node host (provider.mjs: execd SSE, raw file bodies, PTY on the execd WebSocket). None of them reads ABX_SANDBOX_API_KEY. After install, the CLI loads these ids (abx --provider <id>).
  • Fine-grained, per-endpoint capability management in agent-sandbox-server. In addition to capability groups, every built-in and custom route can now be enabled/disabled individually and constrained by a declarative policy: required permission scopes (files:read, process:run, ...), path scoping (allow/deny globs, read-only roots, symlink modes), size and rate limits, parameter rules (upload overwrite and extensions, command allow/deny lists, code languages, URL allow/deny and private-network blocking, signal and shell allow lists) and audit logging. Configure through SandboxServer(policy=...), agent-sandbox-server serve --policy FILE --preset NAME, ABX_SERVER_POLICY / ABX_SERVER_POLICY_FILE, /etc/agent-sandbox/server-policy.json, or the template.yaml server: block (presets: default, transfer-only, read-only, hardened, locked; multiple token identities with scopes). An unconfigured server behaves exactly as before. Error bodies gain a stable code (path_not_allowed, missing_scope, endpoint_disabled, rate_limited, ...). Design, two review rounds and bypass analysis: fine-grained-capabilities, review log.
  • Server discovery v2. GET /capabilities adds api_version, server_version, identity, policy and a per-endpoint table (groups unchanged); POST /capabilities/check returns the policy decision for a hypothetical call without touching the filesystem.
  • New server endpoints to match the client: GET /files/watch (SSE), POST /process/{pid}/stdin, GET /process/{pid}/output, GET /pty/sessions/{id}, POST /pty/sessions/{id}/resize; additive cwd/env/timeout for /shell* and env/capture_output/stdin for /process/start.
  • agent-sandbox-server console command (serve, healthcheck, check-config, version; also python -m agent_sandbox.server) for container start/ready commands and policy validation.
  • ServerClient and Sandbox.server / Sandbox.server_at() / Sandbox.start_server(). A typed async client (with *_sync twins and SSE/WebSocket streaming) for every SandboxServer route, explicit capability discovery (discover() -> ServerCapabilities, fail-fast pre-checks), and typed errors ServerAPIError (E9000), ServerAuthError, PolicyDeniedError, FilePolicyDeniedError, EndpointNotAvailableError, PayloadTooLargeError, RateLimitedError (E9001-E9005; see error codes). Alignment matrix: client-server-alignment.
  • Template server: block. SandboxTemplate.server carries the declarative server policy block. Official base image and Dockerfile lint are the CLI's job (abx template build); see base-image-and-server-sdk.
  • Canonical names for every credential and configuration key, with a complete alias table (agent_sandbox.utils.config_keys, agent_sandbox.transport.config). Environment variables are ABX_<KEY> (core) and ABX_<PROVIDER>_<KEY> (provider scoped), for example ABX_SANDBOX_API_KEY, ABX_SANDBOX_BASE_URL, ABX_SANDBOX_DOMAIN, ABX_ALICLOUD_EXPRESS_REGION, ABX_ALICLOUD_EXPRESS_ACCESS_KEY_ID, ABX_ALICLOUD_EXPRESS_ACR_NAMESPACE, ABX_GITHUB_TOKEN, ABX_HTTP_TIMEOUT, ABX_LOG_LEVEL. TransportConfig fields and Sandbox.create/connect keyword arguments gain sandbox_api_key, sandbox_base_url, sandbox_domain. The product reads only these names. Vendor names that the vendor publishes (ALICLOUD_*, ACR_*, GITHUB_TOKEN, OPENAI_*, DASHSCOPE_API_KEY) keep their own names. E2B_* and SANDBOX_* environment variables are not read. See Configuration.
  • Audit and migration helpers: audit_config() lists the legacy names in use (names only, never values); explain_config() reports which layer and name decided each key (secrets masked); plan_migration() / apply_migration() rewrite stored names to the canonical ones (backups *.bak, mode 600). Opt in to a DeprecationWarning per legacy keyword with ABX_WARN_DEPRECATED=1.
  • Provider plugins (agent_sandbox.providers). The built-in backend is now presented as Alibaba Cloud Express Edition (阿里云极速版), id alicloud-express, and stays the default. Third-party providers install from a directory or git URL with python -m agent_sandbox.providers install|list|info|update|uninstall|default|doctor (the same layout, receipts and tree digest the abx provider commands use) and are selected with Sandbox.create(provider=..., provider_options=...), ABX_PROVIDER, ./.env, ~/.abx/.env or [core] provider in config.toml. Plugins are rest (declarative E2B-protocol manifest), exec (EPP/1, JSON-RPC 2.0 over stdio, language neutral) or python (register_provider() / entry-point group agent_sandbox.providers). Install executes nothing from the plugin, pins by commit or digest, verifies the digest on every start, scrubs the process environment, and gives generic credentials (sandbox_api_key, sandbox_base_url, sandbox_domain) to a plugin only through a manifest [core] inherit the user consented to. 18 capability features; unsupported ones raise ProviderFeatureNotSupportedError. A reusable contract-test kit is in agent_sandbox.providers.testing, and reference plugins are in examples/providers/. See Providers and the design.
  • Provider plugin follow-ups. python -m agent_sandbox.providers test <id> runs the contract kit (now 18 tests: exec stream, files, timeouts, kill idempotence, E8004, secret redaction) against an installed provider; update gains --allow-insecure-transport and --no-verify; epp-methods.json is a machine-readable EPP/1 method table (params, result, support level) mirrored byte-identically to the CLI fixtures; Sandbox.create(provider_options=...) is also forwarded to the plugin as per-create options (secret fields removed); secure is optional (None keeps the previous behaviour, plugins receive it only when set); Sandbox.network.resolve() / resolve_url() use the provider's ports.url; exec adapters fall back from sandbox.connect to sandbox.get when the plugin lacks connect; ProcessInfo.pid and Commands accept int | str (EPP process_id is a string).
  • Provider error codes E8000-E8030 (ProviderError and subclasses, including ProviderResourceNotFoundError E8005 and ProviderFeatureNotSupportedError E8004, which is also a CapabilityNotSupportedError).
  • Sandbox.provider property and Sandbox.close() / close_sync() (release provider resources such as a plugin process). LocalSessionStore sessions record their provider.
  • ABX_LOG_LEVEL is the canonical name of SANDBOX_LOG_LEVEL.
  • Language-neutral conformance fixtures (client-sdk/tests/fixtures/*.json) shared with the Node CLI: key registry, resolution vectors, tree-digest vectors, EPP error mapping, migration vectors.
  • Real-cloud E2E suite and the Definition of Done. make e2e runs e2e/ (pytest, marker e2e) against the real platform: lifecycle, commands, files, processes, ports, timeouts, the declarative @sandbox decorator and agent-sandbox-server inside a real sandbox; make e2e-all adds slow tests. Tests skip with an explicit reason without credentials and are never collected by the unit CI. Every sandbox and template is tagged and removed in finalizers; make e2e-cleanup (scripts/e2e-cleanup.py) is the janitor. Defects found are pinned as strict xfails and listed in e2e/KNOWN-ISSUES.md (KI-001 to KI-011). New rules in .agents/notes/DEFINITION-OF-DONE.md (English and Chinese, with ADR and evidence templates), linked from CONTRIBUTING.md and the PR template. Guide: Testing & Definition of Done (中文).

Fixed

  • Sync factories keep the class. Sandbox.create_sync, connect_sync, list_sync, and kill_by_id_sync are classmethods. They pass the class through, including a subclass, instead of binding the first argument to cls (TypeError: Sandbox.connect() missing 1 required positional argument: 'sandbox_id').
  • Alias capability lookup. Sandbox.create / connect try the caller's template string, then the platform template id (info.template) and info.alias_name, and use the first ~/.abx/templates/**/template.yaml that matches. A unique alias with no local file stays at debug and uses the default capabilities. The platform GET /templates/{id} payload has no capabilities field, so a cache miss cannot be filled from the API. The longer no matching template.yaml in ~/.abx/templates warning is emitted by the abx CLI, not this package.
  • Express template author path. Sandbox.create through the local engine copies envdVersion onto Sandbox.info.envd_version (generation 1 is 0.5.2, generation 2 is 0.6.1). A remote template id no longer logs a warning when no local template.yaml exists; capabilities still fall back to the defaults. sandbox.run(name, **kwargs) returns the command value. An unknown name is CommandNotFoundError and includes the server's available-command list. Bad arguments are CommandArgumentError (HTTP 400). A command that raises is CommandExecutionError (HTTP 500), which is also a ServerAPIError. timeout= on sandbox.run is the HTTP timeout and is not sent as a command argument. Named commands do not stream stdout; a shell command uses sandbox.commands.run(..., on_stdout=).
  • Express generation-2 envd streaming. commands.run / files go through the local engine to envd. Generation-2 envd (v0.6+, Express --generation 2) requires the 5-byte Connect envelope on streaming RPCs such as process.Process/Start. The client was sending raw JSON, which envd reported as invalid_argument: protocol error: promised N bytes in enveloped message. Streaming calls are enveloped. Unary RPCs stay raw JSON and use Content-Type: application/json (generation-2 envd returns HTTP 415 for application/connect+json on filesystem.Filesystem/ListDir). Generation-1 envd (v0.5.x) still receives raw JSON on streams and application/connect+json on unary calls. A Connect error trailer, or a raw JSON error body, is raised as EnvdRpcError carrying the envd code and message. That error survives the engine gRPC boundary instead of becoming RuntimeError with an empty message. commands.run accepts on_stdout and on_stderr.
  • Express port 9000. Sandbox.server, server_at(), and sandbox.run() do not send the sandbox access token. On the current Express image an unconfigured agent-sandbox-server answers HTTP 401 when X-Access-Token or Authorization is present, because it treats any presented credential as a login. network.get_access_headers() stays X-Access-Token only, for the platform gateway (envd /files and a manual GET /health). A server with no ABX_SERVER_TOKEN now keeps a presented but unmatched credential anonymous, so a later image tolerates a forwarded gateway token. A server that sets ABX_SERVER_TOKEN still requires that token (server_at(token=...)).

  • Provider installer and contract kit. A failed update no longer loses the plugin's data/ directory (rollback restores it exactly); python -m agent_sandbox.providers update accepts --allow-insecure-transport like install; the documented contract-test invocation no longer collects 0 tests; the streaming exec adapter raises CommandTimeoutError instead of a bare asyncio.TimeoutError.

  • agent-sandbox-server: HTTP and archive hardening that applies to every server, configured or not. A non-numeric, negative, signed or conflicting Content-Length is now answered with 400 instead of crashing the request thread, and POST /files/archive (zip) no longer follows a file symlink that points outside the base directory (previously the target's content was archived).
  • agent-sandbox mcp (STDIO): a ping sent right behind the first tools/call could wait hundreds of milliseconds. The first tool call imported the SDK's sandbox layer lazily (about 300 modules, CPU-bound) on the event loop, which stalled every other request; the server now imports it at startup. Commands.send_signal and the API reference / SDK usage guide (en, zh) now state that only SIGTERM (15) and SIGKILL (9) are delivered and any other number raises ValueError.
  • SDK defects found by the real-cloud E2E suite (present since 0.2.0; ids from e2e/KNOWN-ISSUES.md, each pinned by regression tests in client-sdk/tests/test_known_issues/ and by the now ordinary tests in e2e/):
  • KI-001 commands.run/start/stream(env=...) sent the variables as process.envVars; envd's ProcessConfig field is envs, so per-call environment variables were silently dropped. They now reach the command (sandbox-create envVars is unchanged).
  • KI-002 files.list / files.get_info now understand envd's EntryInfo: the numeric type (2 = directory; FILE_TYPE_DIRECTORY and a string size are accepted too) and the entry object of Stat. Directories were reported as file and get_info returned a blank name/path.
  • KI-003 a command that outlives its timeout now raises CommandTimeoutError (E3001) instead of a raw httpx.ReadTimeout; the process is also killed on a best-effort basis (closing the HTTP stream did not stop it). A connect timeout is a ConnectionError_. The timeout is still an inactivity limit (no output for timeout + 5 s), not a wall-clock deadline.
  • KI-004 commands.kill, send_signal, send_input (and ProcessProtocol.connect_to_process / update) posted a flat {"pid": N, ...} body that envd ignores. They now send {"process": {"pid": N}, "signal": "SIGNAL_SIGTERM"|"SIGNAL_SIGKILL"} and {"process": {"pid": N}, "input": {"stdin": <base64>}}; a non-numeric string pid is sent as a process tag. envd can only deliver SIGTERM (15) and SIGKILL (9): any other signal number raises ValueError instead of being silently lost. HTTP errors of these calls are EnvdRpcError (for example process not found).
  • KI-005 not-found conditions no longer leak httpx.HTTPStatusError: Sandbox.connect() / get_info() / set_timeout() / pause() / resume() of an unknown sandbox raise the new SandboxNotFoundError (E2009, error codes; kill stays idempotent), and every envd file operation maps HTTP 404 to FileNotFoundError_, 403 to PermissionDeniedError and any other status to FileOperationError.
  • KI-006 a Platform API 401 raises InvalidAPIKeyError (InvalidCredentialsError with AK/SK), both AuthenticationError, instead of a raw httpx.HTTPStatusError; the message never contains the key or the URL. Sandbox.create with a bad key is therefore an AuthenticationError, not a SandboxCreationError.
  • KI-007 files.list of a missing directory raises FileNotFoundError_ instead of returning [] (envd answers ListDir with HTTP 200 and no entries; an empty answer is now disambiguated with one Stat).
  • KI-010 @sandbox on an async def function returned the string <coroutine object ...>; the generated remote script now awaits it (asyncio.run).
  • Not SDK defects (behaviour unchanged, reported clearly): KI-008 an envd upload/download that outlives the HTTP timeout is now a FileOperationError naming the path, the size and ABX_HTTP_TIMEOUT instead of a bare httpx timeout; KI-009 (Jupyter service answers 404: run_code already logs the fallback to a shell) and KI-011 (ACR push bandwidth: the E2E canary skips with the reason) need no SDK change.

Removed

  • The abx CLI moved out of the Python package to a Node.js/TypeScript project (@agent-sandbox/cli, the cli repository). Gone from agent-sandbox: the agent_sandbox.cli package, the [cli] and [binary] extras, the abx console script, the PyInstaller standalone-binary build (scripts/build_binary.py) and the release-binary workflow, together with the CLI documentation (CLI design / tutorial / reference, binary installation, using templates, deploy & build, e2e template workflow, templates catalog, agent-skill installation) and SKILL.md, which now live in the cli repository. The CLI behaviour, flags, output and configuration files (~/.abx/...) are unchanged by the move. Migration: replace pip install "agent-sandbox-client[cli]" with npm install -g @agent-sandbox/cli; pip install "agent-sandbox-client[cli,alicloud]" becomes npm install -g @agent-sandbox/cli (the CLI carries its own Alibaba Cloud template client).
  • The coding-agent modules of agent_sandbox.agent moved to the CLI: adopt, clarify, codegen, coding_agent, qwen_code, template_guide and dockerfile_sources (used only by abx create "DESCRIPTION", abx template init and abx template init --adopt). agent_sandbox.agent.{tools,mcp,mcp_http} stay in the SDK; python -m agent_sandbox.agent.mcp still starts the MCP stdio server.
  • The client is a runtime SDK; template build and deploy belong to the CLI. Removed from agent-sandbox: Sandbox.deploy, DockerBuilder, Image, FCTemplate*, agent_sandbox.api.{deploy,docker_builder,fc_template,image,base_image,template}, agent_sandbox.protocol.template, agent_sandbox.utils.dockerignore, the [alicloud] extra, the models BuildInfo, BuildStatus, TemplateInfo, and the E7xxx (deploy/build/docker/ACR) error codes. Migration: abx template build|deploy (see Build & Deploy).
  • One way to call a named command: sandbox.run(name, **kwargs). Sandbox.custom(), Sandbox.run_command(), CommandResult, CustomCommand, CustomCommandArg and the template.yaml key custom_commands (including {placeholder} substitution) are gone; a template.yaml that still has custom_commands fails validation. sandbox.run("name", **kwargs) is POST /commands/name on the in-sandbox server (CommandNotFoundError when unknown; list_commands() lists them). Bare shell stays sandbox.commands.run(cmd). @sandbox.register no longer takes image=.
  • One way to run an agent in a sandbox: the Agents API (/v1/agents/**). BUILTIN_AGENTS, agent_sandbox.agent.builtin, agent_sandbox.agent.infer and the design docs built-in-agents.md and agents-api-cli-followups.md are removed. The CLI has no abx agent command.
  • One capability switch, and the client follows it. Groups are aliases for endpoint ids; ABX_SERVER_ENABLED_GROUPS is the only group variable (it only turns groups on) and ABX_SERVER_DISABLED_GROUPS, enable_builtin and disable_builtin are gone (use enable_group() or server.groups). The /ops surface and server/core/* are deleted; the server declares one ENDPOINTS table (118 endpoints). In the client, ServerCapabilities has no legacy mode and no ENDPOINT_GROUPS table; it exposes groups, group_summary and rule(endpoint). EndpointInfo gains summary and rule, ServerAPIError gains rule, a 404 with code: endpoint_disabled maps to EndpointNotAvailableError, and path violations are 403 path_not_allowed (FilePolicyDeniedError).
  • template.yaml server.groups is a list (groups: [file_ops]) or a map (groups: {process: false}); validate_server_block checks the group names (SERVER_GROUP_NAMES) and core cannot be turned off.
  • sandbox.register.upload() and .download() are removed. File transfer is the file_ops group (/files/*, /upload, /download); sandbox.register only registers named commands.
  • Examples, templates and e2e use the current server API. examples/templates/python-hello and every awesome-templates/*/commands.py register with @command and start with start(); agents-cli limits the server with an endpoint policy instead of a group alias; awesome-templates/CONTRIBUTING.md no longer mentions custom_commands. The local e2e (e2e/test_server_http_e2e.py, test_agents_transport_e2e.py, test_client_sdk_local_e2e.py) test endpoint states, rule codes and path_not_allowed instead of /ops, and examples/run_examples_e2e.py runs examples/agents/complete_case.py.
  • agent_sandbox.extensions.{oss,vpc,domain} removed. They were empty shells. The platform exposes no per-sandbox API for them: VPC is a template runtime setting, volumes are created through the control plane, and custom domains are account level.
  • Env variables: E2B_API_KEY/SANDBOX_API_KEY in error text and docs now read ABX_SANDBOX_API_KEY. Product descriptions no longer claim E2B protocol compatibility or a drop-in replacement.
  • Sandbox.create(description=...) and the natural-language hint are gone. Natural-language creation lives in the CLI (abx create "...", abx template init "..."). The error classes E2005-E2008 (AI template generation) are removed with the E7xxx codes; they belong to the CLI.
  • e2e and scripts follow the runtime-only client. e2e/test_08_custom_template_docker.py, e2e/e2e_acr.py, scripts/e2e/* (build, push and cloud-flow scripts) are deleted; the pytest suite in e2e/ and abx template cover them. The suite reads ABX_SANDBOX_API_KEY; make e2e-all no longer needs Docker or ACR; scripts/e2e-cleanup.py only kills tagged sandboxes. docs/*/design/sdk-api-design.md is rewritten to the current two paradigms; agent_sandbox.compat is documented as a partial migration helper.

[0.2.0] - 2026-09-30

Breaking Changes

  1. CLI config uses one name per credential. abx config lists sandbox_api_key for the sandbox service key (still stored as E2B_API_KEY; abx config get/set api_key remains an alias). NL inference and the coding agent share llm_api_key, llm_base_url, and llm_model. qwen_code_api_key, qwen_code_base_url, and qwen_code_model are no longer configurable; config get / config set name the llm_* replacement. An older ABX_QWEN_CODE_API_KEY (and stored qwen_code_base_url / qwen_code_model) is still read when the matching llm_* value is unset, and shows up under the llm_* name. Migration: use abx config set sandbox_api_key <KEY> and abx config set llm_api_key <KEY>. Set llm_base_url / llm_model only when the DashScope default is not the endpoint you want. The Python SDK parameter stays api_key=.

  2. abx deploy is the fixed build → push → register pipeline. It now runs exactly what abx template deploy runs (docker build, push to ACR, CreateTemplate, wait for ready), with PATH defaulting to ., and shares every option of that command including -v/--verbose, --acr-namespace and --region. It needs no LLM and no LLM key, takes no description (the INSTRUCTION argument is gone), and no longer starts a qwen-code cloud sandbox or raises E7001. What a template is lives in template.yaml, authored by abx template init; deploy only reads its name, resources and generation. --traditional is deprecated and ignored (with a warning); the old traditional-mode-only --watch option is removed, and --alias now is template deploy's template alias. Migration: abx deploy ./p "instruction" becomes abx template init "DESCRIPTION" (the AI writes Dockerfile, commands.py, template.yaml into ./<name>/) followed by abx deploy ./<name>. The in-sandbox agent deploy remains available as the SDK API Sandbox.deploy().

Changed

  • Credentials resolve in one order everywhere. An explicit argument wins, then the process environment, then ./.env, then ~/.abx, then a built-in default. .env files merge per key, so a project file that omits a key no longer hides ~/.abx/.env. A blank or whitespace-only value does not count. Sandbox.create, Sandbox.deploy, natural-language abx create, GitHub template downloads, and abx mcp install follow that chain. abx mcp install copies E2B_API_URL and SANDBOX_REGION into the editor config only when the process environment sets them. The table is in the configuration reference.

Added

  • abx config delete KEY: remove one stored configuration value (a credential, acr_namespace, a connection setting, or shortcuts.<name>). The key falls back to its default or becomes not set. abx config set KEY "" still does the same thing. Environment variables are not unset, and there is still no command that wipes ~/.abx.
  • Long steps keep a moving header. Creating a sandbox, upload, download, template fetch, registering a template from an image, installing the coding-agent CLI, and abx kill --all use the same message... 12s header as deploy, redrawn once a second on a terminal. Grey lines are safe text only: relative paths, install milestones, and (for deploy) docker or poll output. File bytes, tool input, ACR tokens, and --build-arg values are not shown; the docker command logged at info level redacts build-arg values. --json, --quiet, CI, TERM=dumb, and non-TTY stay silent for these headers. Deploy still prints one progress line per phase in those modes, and --verbose still prints the full deploy log instead of the block.
  • Build, push, and wait steps show their log. On an interactive terminal, abx deploy / abx template deploy / abx template push draw each long step as a message... 12s header with the latest four lines of docker build, docker push, or READY-poll output in grey underneath (ABX_ACTIVITY_LINES changes the count). The elapsed time keeps moving once a second while the tool is silent. --verbose prints the full log instead. --json, --quiet, CI, and non-TTY stay one progress line. While a template is generated, a tool name appears when the call starts, still without tool input.
  • abx init "DESCRIPTION" asks for a directory. Natural-language abx init / abx template init asks an interactive terminal Directory for the template project before generating. Enter keeps ./<name>/ (or ./<--name>/). Any other path is the project directory itself. --yes, --json, and non-TTY skip the prompt. A file, or a directory that already has template files, is rejected before generation; --force overwrites.
  • abx template init --adopt [DIRECTORY]: turn an existing project into a deployable template. Qwen Code sees a staged copy (secrets, keys and secret-looking files excluded) and only Dockerfile, commands.py, template.yaml and a generated .dockerignore are written back, after a preview. --hint adds what the code cannot say, --dry-run lists the files that would be sent and contacts no model, --yes skips both confirmations, and --force is what replaces an existing Dockerfile when there is no interactive preview. Replaced files are kept as *.abx-bak. The agent process does not inherit cloud credentials. abx template init --from <local dir> now refuses a directory that has no template.yaml and points at --adopt. Nothing is built or deployed; publish with abx deploy.
  • abx create --dir DIRECTORY: choose the parent directory for the AI-generated template files (Dockerfile, template.yaml). Without it, an interactive terminal is asked where to save them (Enter keeps the default ~/.abx/generated); --yes, --json and non-TTY sessions use the default silently.
  • Live agent activity line: while Qwen Code researches, assesses or generates, a TTY shows the Assessing description... 12s header with the agent's last four activity lines in grey on the lines below it, scrolling line by line as the agent produces text or uses a tool (ABX_ACTIVITY_LINES=1..10 changes the count; also works under --verbose). It shows only assistant text lines and tool names, never tool input; it is absent for --json, --quiet, CI and TERM=dumb, and never touches stdout. Research now has its own "Researching public facts" phase.
  • Configurable CLI shortcuts: Command aliases are now configurable via [shortcuts] section in ~/.abx/config.toml. All existing top-level shortcuts (create, list, info, etc.) are enabled by default. Users can add custom shortcuts with abx config set shortcuts.<name> "<target>". Run abx config init to generate a complete shortcuts template with all available commands.
  • Natural-language template init: abx template init "DESCRIPTION" (and abx init "DESCRIPTION") generates Dockerfile, commands.py and template.yaml and stops. Interactive abx create "DESCRIPTION" / abx sandbox create "DESCRIPTION" first asks whether to switch to that template-only path before building, pushing, deploying, and creating a sandbox. --yes keeps the full create pipeline.
  • AI-generated templates ship a server: the natural-language generator now writes commands.py (an agent_sandbox.server SandboxServer on port 9000, the process the deployed sandbox answers HTTP with), template.yaml with capabilities / ports, and a README.md next to the Dockerfile, instead of a Dockerfile-only image. The prompt carries the server SDK reference (agent/template_guide.py); a result without a valid commands.py that starts the server is rejected. template init "DESCRIPTION" copies every generated file into ./<name>/.

Fixed

  • Remote MCP refuses to start without a Bearer token. The FC artifact calls require_auth_token, so an empty ABX_MCP_AUTH_TOKEN fails the process instead of serving /mcp with authentication disabled. STDIO still has no Bearer token (the IDE owns the local process). Loopback HTTP may omit the token and warns; any other bind requires one.
  • abx mcp start prints its configuration and can be stopped. A foreground STDIO process writes the transport, template, whether an API key is set, the tool list, and how to stop to stderr, and leaves stdout for JSON-RPC. --http serves Streamable HTTP; --background detaches that HTTP server (the API key and token stay in the child environment). abx mcp stop sends SIGTERM to the pid recorded under ~/.abx/run. abx mcp status reports mcp_running.
  • MCP sessions follow the documented agent loop. create_sandbox becomes the default sandbox, so later tools can omit sandbox_id and kill_sandbox destroys that sandbox; killing when nothing exists returns an error. An omitted template uses the server template. Lazy creation is single-flight, and each use extends the sandbox timeout. run_command runs via sh -c. A non-zero exit is a tool error. STDIO accepts messages up to 8 MiB and answers ping while a tool call is in flight. GET /mcp returns 405. abx mcp deploy refuses to write an artifact without a non-empty Bearer token and sets SANDBOX_REGION. abx mcp install --target vscode writes .vscode/mcp.json and leaves non-strict JSON alone.
  • abx config init asks for the template-deploy prerequisites. The guided wizard now also prompts for the ACR namespace and the Alibaba Cloud AccessKey ID / Secret (Enter skips any prompt). acr_namespace is a config key stored in ~/.abx/.env as ACR_NAMESPACE, so abx install and abx template deploy pick it up without --acr-namespace. The missing-prerequisite errors name abx config init and abx config set.
  • Invalid shortcut targets explain the mistake. abx config set shortcuts.<name> "abx template init" now says to drop the abx prefix and prints the command to retry ("template init"). Other unknown targets are grouped by command. The unknown-command hint uses the same example.
  • SDK wheel injection works for installed abx. DockerBuilder.inject_sdk_wheel only knew how to build from a source checkout, so an abx installed from PyPI (or the standalone binary, which has no pip) injected nothing and images silently got whatever agent-sandbox was newest on PyPI. It now downloads the released wheel of the running version from PyPI (SHA-256 verified) and falls back to the Dockerfile's PyPI install only when that is unavailable; source checkouts still build from the working tree, and a pyproject.toml that is not agent-sandbox is no longer mistaken for the SDK.
  • abx create "<description>" no longer appears hung and no longer misreports failures. The research round is bounded (20 turns, 240 s; ABX_QWEN_RESEARCH_TIMEOUT overrides) and its prompt caps slow web fetches; on timeout or turn exhaustion the CLI warns with the reason. The whole agent process tree (qwen relaunches itself as a child) is now terminated on timeout or Ctrl-C instead of being orphaned. After a failed research round the assessment starts a fresh session, because qwen rejects re-pinning a --session-id that already exists; this was the cause of the bogus "assessment unavailable; continuing straight to generation" warning.
  • DeployLLMKeyMissingError (E7001) suggestion now mentions ABX_LLM_API_KEY and llm_api_key=.

[0.1.0] - 2026-09-29

First stable release. Includes all changes below (formerly tracked as 0.1.0-dev) plus the current cycle:

Breaking Changes (Task 201 — config Reset Removal & Value Semantics)

  1. Removed abx config reset. Clearing is now per key via abx config set KEY "": the stored value is removed and the key returns to its business default or to not set. An empty string is never stored as a credential or as an override. When an environment variable still overrides the key at runtime, the command says so explicitly without printing its value. Migration: replace abx config reset --yes with one abx config set KEY "" per key you want to clear (e.g. abx config set region "").

  2. abx config list shows effective values and their sources. Sources are annotated as (env), (user), (default) or (not set). Keys with a real business default (qwen_code_base_url, qwen_code_model) show the concrete default; keys without one (llm_api_key, llm_base_url, llm_model) show (not set) instead of a blank (default). Secrets stay masked. Migration: consumers parsing config list output now see source suffixes and (not set) where the old output showed blank defaults.

  3. abx config init secret prompts echo one * per character. Previously typed secrets were completely invisible; now every typed or pasted character shows a single * (never the plaintext), with Backspace / Ctrl-C / EOF / Unicode handled correctly. Terminals that cannot render it fall back to the previous no-echo behaviour with an explicit notice. Migration: no action required — the plaintext is never displayed in either mode.

Breaking Changes (ADR 2026-09-23 — Overdesign Cleanup)

  1. abx template install default behaviour changed: download → download+build+deploy. install now fetches the template sources and then builds the Docker image, pushes to ACR, and registers the template via the official API by default — cloud-side operations that can incur Alibaba Cloud costs (ACR storage/traffic, template resources). The previous download-only behaviour is available via --download-only. Migration: add --download-only to abx template install / abx install invocations that should not build and deploy.

  2. Removed SerializerType.PICKLE / SerializerType.MSGPACK. The @sandbox decorator now only supports serializer="json". Non-JSON serializable return values must be converted to dict/list/str before returning. Migration: change @sandbox(serializer="pickle") → @sandbox(serializer="json") and ensure return values are JSON-compatible.

  3. Removed runtime check_capability() gate from most modules. CommandsModule, FilesModule, and NetworkModule no longer raise CapabilityNotSupportedError (E3004) at call time. Exception: CodeContextModule retains the code capability gate — all its methods (run, create_context, list_contexts, restart_context, remove_context) still raise E3004 when the code capability is missing (fail-closed). E3004 is also still raised during template resolution / model validation via resolve_capabilities(). Migration: remove try/except CapabilityNotSupportedError around commands.*, files.*, and network.* calls; declare required capabilities in template.yaml instead. Keep try/except CapabilityNotSupportedError around run_code() / code.* calls if your template may lack the code capability.

  4. Removed agent_sandbox.integrations sub-module. The LangChain/CrewAI/AutoGen adapter module was an empty abstract placeholder and has been deleted. Migration: use agent.tools or MCP integration directly.

  5. Removed SessionStore abstract base class. Only LocalSessionStore remains. The session/base.py ABC has been deleted. Migration: if you were subclassing SessionStore, switch to LocalSessionStore or implement your own storage directly.

  6. SecretStore changed from macOS Keychain to file-based storage. Secrets are now stored in ~/.abx/secrets.json (plaintext, chmod 600). Old Keychain entries are not automatically migrated. Migration: re-add secrets via environment variables (E2B_API_KEY, SANDBOX_API_KEY) or ~/.abx/.env file. Use abx config set api_key <value> to persist API keys.

  7. Removed abx auth CLI command group. The abx auth login/logout/status/switch commands have been removed. Migration: use abx config set api_key <value> to persist credentials, or set E2B_API_KEY / SANDBOX_API_KEY environment variables directly.

  8. Removed abx secret CLI command group. The abx secret create/list/delete/inject commands have been removed. Migration: use environment variables or .env files to manage credentials and secrets. For sandbox environment injection, use abx create --env KEY=VALUE.

  9. Removed abx session / abx sessions CLI command group. The abx sessions list/info/rename/export/import/clean and abx start/connect commands have been removed. Migration: session data is still stored locally in ~/.abx/sessions/ by LocalSessionStore. Use the SDK's Sandbox.connect() API programmatically.

  10. Removed abx skill CLI command group. The abx skill search/install/list/create/publish commands have been removed. Migration: Skills system is a future planned feature. Use templates as the current capability distribution mechanism.

  11. Sandbox.run() is now a bare-shell shortcut (was named-command dispatcher). Sandbox.run(cmd) now delegates to sandbox.commands.run(cmd) and returns ProcessResult | StreamReader. It no longer dispatches named custom commands. Migration: replace sandbox.run("name", **kwargs) with sandbox.custom("name", **kwargs).

Breaking Changes (ADR 2026-09-29 — init/create Semantics, partially superseded)

Update (2026-09-29, ADR 2026-09-29-init-restore-and-create-explicit-error): item 1 below is superseded — the top-level abx init shortcut has been restored as an exact alias of abx template init (same click command object, option surface unchanged). Items 2–3 stand, and item 3 replaces the earlier "abx create (no arguments) uses the base template" routing.

  1. ~~Removed the top-level abx init shortcut.~~ Superseded: restored. The top-level abx init shortcut is back and delegates to the exact same command object as abx template init (options unchanged). Guided credentials setup remains abx config init; cloud sandbox creation remains abx create. Migration: abx init [DIRECTORY] and abx template init [DIRECTORY] are interchangeable again.

  2. abx create "DESCRIPTION" --template NAME is now rejected. Previously --template silently won and the description was ignored. Passing both now raises a usage error (exit code 1) before any AI generation or network call — neither input is silently dropped. Migration: keep DESCRIPTION for the Qwen Code AI path, or --template for a direct launch, but not both.

  3. abx create with no arguments is now an explicit usage error (exit code 2). Previously bare abx create silently launched the base template. It now prints a routing hint (--template base, --template <NAME>, or "DESCRIPTION" for the AI path) so the choice is always explicit. Migration: use abx create --template base to launch the base template.

Changed (CLI UX)

  • Unknown top-level commands now get targeted hints. A close spelling candidate (e.g. abx crate) gets a Did you mean 'create'? suggestion; with no plausible candidate the error points to template custom_commands (declared in template.yaml) and running them via abx run COMMAND. Exit code 2 and stderr-only output are preserved; only the root group is affected.
  • Top-level shortcut registration is explicit. Built-in top-level shortcuts (create, list, init, install, deploy, run, …) are registered in the LazyGroup(lazy_subcommands=...) map in src/agent_sandbox/cli/main.py. This map is a maintainer-facing registration point for the built-in top-level entry points.

(Historical note: an earlier CLI design draft rejected a [shortcuts] config section. This decision was superseded by ADR 2026-09-30-configurable-cli-shortcuts.md: [shortcuts] is now implemented as a user-configurable alias layer — see the [Unreleased] Configurable CLI shortcuts entry.)

Breaking Changes (ADR 2026-09-29 — qwen-code Session-Turns Parameter Unification)

  1. Renamed the qwen-code session-turns parameter to max_session_turns / --max-session-turns everywhere (SDK, CLI, qwen-code template template.yaml/commands.py, docs). The old names were misleading: Sandbox.deploy(max_tool_calls=...), DeployModule.deploy_project(max_tool_calls=...), and abx deploy --max-tool-calls all forwarded the value to qwen-code's official --max-session-turns flag (user/model/tool turn cap, exit code 53), not to the semantically different upstream --max-tool-calls budget (cumulative tool calls, exit code 55). The pre-existing template arg max_turns is renamed for the same reason and its default is unified to 100. Migration: rename max_tool_calls= → max_session_turns=, --max-tool-calls → --max-session-turns, and template arg max_turns → max_session_turns. Old names fail loudly (CLI usage error / SDK TypeError); no aliases are kept, matching the pre-release no-compat-shim policy.
  2. run_qwen_code_headless() / _build_headless_command() accept an optional max_session_turns keyword (None by default adds no flag). This is the stable naming contract for the natural-language abx create pipeline and future headless callers.

Breaking Changes (Task 187 — Template Catalog Single Source of Truth)

  1. The template catalog moved to the dedicated repository alibaba-agent-sandbox/awesome-templates. Template content, the machine-readable index (awesome-templates.yaml), releases and CI now live there — it is the single source of truth for official & community templates. This repository no longer bundles the template collection: examples/templates/ keeps only a minimal python-hello offline fixture, explicitly marked as a fixture (not a publishing source). The repository-root awesome-templates.yaml has been removed. Migration: instead of deploying a bundled folder (e.g. abx template deploy ./examples/templates/node-web), install from the index (abx template install node-web) or reference the source repo directly (abx template install alibaba-agent-sandbox/awesome-templates//node-web@v1.0.0).
  2. abx template search / abx template install <bare-name> now resolve against the remote index (cached under ~/.abx/index/). Bare names that are not builtins are looked up in the index; a miss triggers one forced refresh, and the resolved owner/repo//subdir[@ref] is printed (Resolved '<name>' via the template index: ...). Migration: no action needed for direct owner/repo references; bare names must exist in the index. Use --index-url / ABX_TEMPLATE_INDEX_URL for private mirrors.

Added

  • Remote template index client (agent_sandbox.utils.template_index): fetches awesome-templates.yaml from the SSOT repository via raw.githubusercontent.com (CDN — not subject to the API 60 req/hour anonymous limit), with a ~/.abx/index/ cache, 1-hour TTL, If-None-Match revalidation, and explicit degraded modes (stale-cache fallback with a warning on network failures / rate limits / 5xx; loud errors with remediation when no cache exists; schema_version newer than supported fails with an upgrade hint). --index-url / ABX_TEMPLATE_INDEX_URL and --token / GITHUB_TOKEN are supported.
  • SKILL.md: Static Agent Skills–style usage guide at the repository root for AI coding tools and agents in other projects — covers when to use, install, credential safety (including never-leak rules), MCP vs SDK selection, sandbox create/execute/files/destroy workflows, and common error diagnosis. Referenced from llms.txt. Documentation only: the removed abx skill command group, Skills registry, and runtime are not restored (ADR 2026-09-29). Shipped in the sdist but not the wheel (evidence: tests/test_packaging.py; guide/code consistency: tests/test_agent_guide.py).
  • Sandbox.custom(name, *, server_port=9000, **kwargs) -> CommandResult: New method for named custom-command dispatch. Uses A→B resolution: first tries template custom_commands (mechanism A), then falls back to @registry.command on SandboxServer (mechanism B). Returns CommandResult with value, stdout, stderr, exit_code, execution_time, source ("template" | "server"), and success property.
  • CommandResult data model: Structured return type for custom() replacing the bare Any that run_command() returned.
  • abx template init: New scaffold command that generates a complete template project from built-in cases (python, node, minimal) or an existing registry reference (--from). Includes interactive case selection on TTY.
  • github_token config key (abx config set github_token): persistent GitHub token for template downloads, mapped to the GITHUB_TOKEN environment variable and stored in ~/.abx/.env (chmod 600). In an interactive terminal the value may be omitted — the token is read through the existing masked (asterisk) input and never echoed; abx config get / abx config list show it masked, and abx config set github_token "" removes it. Resolution order: --token > process GITHUB_TOKEN > stored github_token > no token.
  • One-shot GitHub rate-limit onboarding (E5000): abx template search / abx template install (abx install) now print the officially documented fine-grained PAT prefill URL when the anonymous limit (60/hour) is hit — public repositories need no extra permissions and a 90-day expiry is recommended. In an interactive terminal only, the CLI offers to store the token with masked input and retries the failed operation exactly once; declining, cancelling, or a retry that fails again surfaces the original error. CI / non-interactive sessions are told to inject GITHUB_TOKEN as a secret or to run abx config set github_token in a terminal. The CLI never runs gh auth token, never opens a browser, and never prints or logs a token.
  • Unified rate-limit guidance (agent_sandbox.utils.github_token): shared headline + remediation used by the registry tarball client and the template-index client; owner/repo//subdir@ref references are preserved verbatim in download errors (e.g. alibaba-agent-sandbox/awesome-templates//codex-agent-api@v1.0).

Deprecated

  • Sandbox.run_command() / Sandbox.run_command_sync(): Deprecated in favour of Sandbox.custom() / Sandbox.custom_sync(). Both deprecated methods wrap custom() internally but only return result.value (type Any) for backward compatibility — the full CommandResult (with stdout, stderr, exit_code, execution_time, source, success) is discarded. If you were treating the old return value as a ProcessResult, migrate to custom() / custom_sync() which return the complete CommandResult. Will be removed in a future release.

Breaking Changes (Official CreateTemplate API convergence)

  1. abx template build-local was removed and replaced by abx template build. The old build-local command name no longer exists (invoking it fails with No such command 'build-local'). abx template build runs the full pipeline: local Docker build → ACR push → template registration, and abx template deploy remains an alias invoking the same pipeline. Migration: replace abx template build-local <DIR> with abx template build <DIR> (same option surface).

  2. abx template build / template deploy default to the official CreateTemplate API. The legacy v3/v2 platform API is no longer the default; it remains available behind the explicit --legacy-api flag (the approved convergence decision — the default switched to the official API while the legacy code path stays behind a flag). The ACR push and the remote template registration are cloud-side operations that can incur Alibaba Cloud costs (ACR storage/traffic, template resources). Migration: scripts needing the legacy v3/v2 behaviour must pass --legacy-api explicitly.

Changed

  • --token is documented as a temporary override: abx template install / abx template search help now warns that --token <value> may leak into shell history and process listings, and recommends the persistent abx config set github_token as the default fix.
  • commands.run(), commands.stream(), and commands.start() now auto-wrap commands containing unquoted shell operators (|, ;, &&, ||, >, <, (...), $(...)) in sh -c. Variable expansion ($VAR), backticks, and globs still require explicit sh -c '...'.
  • abx template build (renamed from build-local): default mode switched to the official CreateTemplate API (--official-api). Legacy v3/v2 behaviour now requires an explicit --legacy-api flag.
  • Official template path prerequisites: abx template create and abx template build (default mode) now require the alicloud extra (pip install "agent-sandbox-client[cli,alicloud]" or pip install "agent-sandbox-client[alicloud]") and Alibaba Cloud AK/SK credentials.
  • When envdInject is enabled and --target-image is omitted, copy.image is now auto-derived with a -fcsandbox-<hex> random suffix to satisfy the platform requirement that copy.image must differ from sandboxConfig.image. For a stable tag, pass --target-image explicitly.

Migration

  • Replace abx template build-local <DIR> with abx template build <DIR> — the old command name was removed.
  • Existing automation scripts invoking the build pipeline without --legacy-api now hit the official CreateTemplate API. To preserve the legacy v3/v2 behaviour, add --legacy-api to the command.
  • Automation / CI hardening: pass --acr-namespace and the template directory explicitly on the command line instead of relying on ACR_NAMESPACE / ABX_TEMPLATE_DIR environment variables or .env files, so builds cannot silently drift with the surrounding environment. For abx template install / abx install, either pass --acr-namespace explicitly or use --download-only when the pipeline must not touch the cloud at all.

Added

  • Server Module: Container-side HTTP server (agent_sandbox.server) expanded from 6 to 42 endpoints across 8 capability groups (CORE, COMMANDS, FILE_OPS, PROCESS, SYSTEM, TERMINAL, DEV_TOOLS, BROWSER)
  • Server CapabilityGroup.BROWSER: New browser automation capability group with 8 Playwright-backed endpoints (navigate, screenshot, content, click, type, evaluate, pdf, console)
  • Server PTY Terminal: WebSocket-based interactive PTY terminal system with session management (REST create/list/delete + WebSocket I/O)
  • Server SSE Shell: Streaming shell execution via Server-Sent Events (POST /shell/stream) for real-time command output
  • Server RouteTable: Declarative route registry replacing if/elif dispatch; capability groups can be toggled at runtime or via ABX_SERVER_DISABLED_GROUPS env var
  • CLI abx sandbox files: 6 file-operation subcommands — list, stat, mkdir, rm, mv, search
  • CLI abx sandbox process: 4 process-management subcommands — list, start, info, signal
  • CLI abx sandbox system: 5 system-info subcommands — info, env, ports, packages, metrics
  • CLI abx sandbox capabilities: Show supported capability groups of a sandbox
  • CLI abx sandbox shell-stream: Real-time streaming command execution (SSE-backed)
  • CLI Global Options: Added --ci (CI/CD mode: quiet + no-color + json), --log-level (explicit DEBUG/INFO/WARNING/ERROR)
  • CLI OutputManager: Unified output manager (cli/output.py) with TTY/CI auto-detection, replacing ad-hoc click.echo calls
  • Template Migration: All 10 templates migrated to new CapabilityGroup API
  • Core SDK: Sandbox class with create(), connect(), kill(), run_code() and async context manager
  • Commands Module: run(), stream(), start() for executing commands in sandboxes
  • Files Module: read(), write(), list(), upload(), download(), exists(), remove(), make_dir()
  • Network Module: Port URL and access headers calculation (get_host(), get_url(), get_access_headers()).
  • Code Interpreter: run() for code execution with multi-language support
  • CLI (abx): create, list, info, kill, exec, shell, auth, config commands
  • Dual Authentication: API Key (SANDBOX_API_KEY) and AK/SK (ALICLOUD_ACCESS_KEY_ID/SECRET)
  • Connect Protocol: Full application/connect+json implementation with Server-Streaming support
  • Transport Layer: HTTP/2 connection pooling, WebSocket with heartbeat/reconnect, layered configuration
  • Error System: Structured exceptions with error codes (E1001-E5002), suggestions, and docs URLs
  • E2B Compatibility: Drop-in compatible compat.Sandbox wrapper
  • Output Formats: Table (rich), JSON, and quiet modes for CLI
  • Sync Support: All async methods have synchronous variants via run_sync()
  • Community Template Index: awesome-templates.yaml — curated index of official and community sandbox templates

Changed

  • Network Module: Removed experimental expose() and list_ports() APIs in favor of a simpler local URL calculation interface based on official documentation. Port URL is now computed client-side as https://{port}-sbx-{sandbox_id}.{domain}.

Architecture

  • Six-layer architecture: Transport → Protocol → Extensions → API → Declarative → Agent Integration (+ CLI + Server)
  • Async-first design with sync wrappers
  • Lazy imports for fast CLI startup (< 200ms)
  • Domain-partitioned HTTP connection pools (Platform API vs envd API)