Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog.
[Unreleased]
Next release: 0.3.0. Both distributions (
agent-sandbox,agent-sandbox-server) and the MCP server version are already set to0.3.0.
Changed
- The Python project is split into two lock-step PyPI distributions in one repository (
python-sdk).client-sdk/is theagent-sandboxdistribution (importagent_sandbox: transport, protocol, models, API, declarative@sandbox, MCP server, E2B migration helper).server-sdk/is the newagent-sandbox-serverdistribution (importagent_sandbox.server): the container-side runtime that used to ship insideagent-sandbox. Both share theagent_sandboxnamespace (the server distribution ships onlyagent_sandbox/server/and has noagent_sandbox/__init__.py), each has its ownpyproject.toml, tests, README,py.typedmarker and_version.py, and both are released with the same version number (publish.ymlpublishesagent-sandbox-serverfirst, thenagent-sandbox). Migration: install the in-container runtime withpip install agent-sandbox-server(template Dockerfiles, e.g.examples/templates/python-hello).agent-sandboxhard-depends onagent-sandbox-server==<same version>, sopip install agent-sandboxstill providesagent_sandbox.server; the[server]extra remains as an empty alias.from agent_sandbox.server import ...is unchanged. A server-only install has noagent_sandbox.__version__; useagent_sandbox.server.__version__. - Missing or broken
agent-sandbox-servernow raises an actionableImportErrorfrom the@sandboxdecorator'ssandbox.serverproxy, namingpip install agent-sandbox-serverand the--force-reinstall --no-depsrepair. - Project URLs point at the renamed repositories (
agent-sandbox/python-sdk,agent-sandbox/agent-sandbox). -
Repository plumbing follows the split.
Makefiletargets (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, runstwine check, verifiespy.typedin both wheels and that client + server install into one virtualenv and import; Dependabot watches/client-sdkand/server-sdk. The packaging test (test_packaging.py) is ported to both packages (client wheel has noagent_sandbox/server, server wheel has noagent_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), theabxexecutable used byscripts/cloud_e2e_test.pyandexamples/compat-demos/e2e_capability_validation.pyis resolved fromPATH(override withABX_BIN), and.env.exampleuses the<your-namespace>placeholder. New regression guardmake hygiene(scripts/check-no-local-paths.sh, allowlist inscripts/local-paths.allowlist) runs in CI and fails on user-home paths, Windows user paths,.venv/binassumptions, personal identifiers and key-like strings. - Dotenv resolution is layer first.
./.envand~/.abx/.envused to be merged per exact variable name before name priority was applied, so./.env: SANDBOX_API_KEY=awith~/.abx/.env: E2B_API_KEY=bresolved tobalthough 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
- 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 throughSandboxServer(policy=...),agent-sandbox-server serve --policy FILE --preset NAME,ABX_SERVER_POLICY/ABX_SERVER_POLICY_FILE,/etc/agent-sandbox/server-policy.json, or thetemplate.yamlserver: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 stablecode(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 /capabilitiesaddsapi_version,server_version,identity,policyand a per-endpoint table (groupsunchanged);POST /capabilities/checkreturns 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; additivecwd/env/timeoutfor/shell*andenv/capture_output/stdinfor/process/start. agent-sandbox-serverconsole command (serve,healthcheck,check-config,version; alsopython -m agent_sandbox.server) for container start/ready commands and policy validation.ServerClientandSandbox.server/Sandbox.server_at()/Sandbox.start_server(). A typed async client (with*_synctwins and SSE/WebSocket streaming) for every SandboxServer route, explicit capability discovery (discover()->ServerCapabilities, fail-fast pre-checks), and typed errorsServerAPIError(E9000),ServerAuthError,PolicyDeniedError,FilePolicyDeniedError,EndpointNotAvailableError,PayloadTooLargeError,RateLimitedError(E9001-E9005; see error codes). Alignment matrix: client-server-alignment.- Template
server:block.SandboxTemplate.servercarries 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 areABX_<KEY>(core) andABX_<PROVIDER>_<KEY>(provider scoped), for exampleABX_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.TransportConfigfields andSandbox.create/connectkeyword arguments gainsandbox_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_*andSANDBOX_*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 aDeprecationWarningper legacy keyword withABX_WARN_DEPRECATED=1. - Provider plugins (
agent_sandbox.providers). The built-in backend is now presented as Alibaba Cloud Express Edition (阿里云极速版), idalicloud-express, and stays the default. Third-party providers install from a directory or git URL withpython -m agent_sandbox.providers install|list|info|update|uninstall|default|doctor(the same layout, receipts and tree digest theabx providercommands use) and are selected withSandbox.create(provider=..., provider_options=...),ABX_PROVIDER,./.env,~/.abx/.envor[core] providerinconfig.toml. Plugins arerest(declarative E2B-protocol manifest),exec(EPP/1, JSON-RPC 2.0 over stdio, language neutral) orpython(register_provider()/ entry-point groupagent_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] inheritthe user consented to. 18 capability features; unsupported ones raiseProviderFeatureNotSupportedError. A reusable contract-test kit is inagent_sandbox.providers.testing, and reference plugins are inexamples/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;updategains--allow-insecure-transportand--no-verify;epp-methods.jsonis 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-createoptions(secret fields removed);secureis optional (Nonekeeps the previous behaviour, plugins receive it only when set);Sandbox.network.resolve()/resolve_url()use the provider'sports.url;execadapters fall back fromsandbox.connecttosandbox.getwhen the plugin lacksconnect;ProcessInfo.pidandCommandsacceptint | str(EPPprocess_idis a string). - Provider error codes E8000-E8030 (
ProviderErrorand subclasses, includingProviderResourceNotFoundErrorE8005 andProviderFeatureNotSupportedErrorE8004, which is also aCapabilityNotSupportedError). Sandbox.providerproperty andSandbox.close()/close_sync()(release provider resources such as a plugin process).LocalSessionStoresessions record their provider.ABX_LOG_LEVELis the canonical name ofSANDBOX_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 e2erunse2e/(pytest, markere2e) against the real platform: lifecycle, commands, files, processes, ports, timeouts, the declarative@sandboxdecorator andagent-sandbox-serverinside a real sandbox;make e2e-alladds 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 ine2e/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 fromCONTRIBUTING.mdand the PR template. Guide: Testing & Definition of Done (中文).
Fixed
- Provider installer and contract kit. A failed
updateno longer loses the plugin'sdata/directory (rollback restores it exactly);python -m agent_sandbox.providers updateaccepts--allow-insecure-transportlikeinstall; the documented contract-test invocation no longer collects 0 tests; the streaming exec adapter raisesCommandTimeoutErrorinstead of a bareasyncio.TimeoutError. agent-sandbox-server: HTTP and archive hardening that applies to every server, configured or not. A non-numeric, negative, signed or conflictingContent-Lengthis now answered with400instead of crashing the request thread, andPOST /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): apingsent right behind the firsttools/callcould 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_signaland the API reference / SDK usage guide (en, zh) now state that only SIGTERM (15) and SIGKILL (9) are delivered and any other number raisesValueError.- 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 inclient-sdk/tests/test_known_issues/and by the now ordinary tests ine2e/): - KI-001
commands.run/start/stream(env=...)sent the variables asprocess.envVars; envd'sProcessConfigfield isenvs, so per-call environment variables were silently dropped. They now reach the command (sandbox-createenvVarsis unchanged). - KI-002
files.list/files.get_infonow understand envd'sEntryInfo: the numerictype(2= directory;FILE_TYPE_DIRECTORYand a stringsizeare accepted too) and theentryobject ofStat. Directories were reported asfileandget_inforeturned a blank name/path. - KI-003 a command that outlives its timeout now raises
CommandTimeoutError(E3001) instead of a rawhttpx.ReadTimeout; the process is also killed on a best-effort basis (closing the HTTP stream did not stop it). A connect timeout is aConnectionError_. The timeout is still an inactivity limit (no output fortimeout + 5s), not a wall-clock deadline. - KI-004
commands.kill,send_signal,send_input(andProcessProtocol.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 processtag. envd can only deliver SIGTERM (15) and SIGKILL (9): any other signal number raisesValueErrorinstead of being silently lost. HTTP errors of these calls areEnvdRpcError(for exampleprocess 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 newSandboxNotFoundError(E2009, error codes;killstays idempotent), and every envd file operation maps HTTP 404 toFileNotFoundError_, 403 toPermissionDeniedErrorand any other status toFileOperationError. - KI-006 a Platform API 401 raises
InvalidAPIKeyError(InvalidCredentialsErrorwith AK/SK), bothAuthenticationError, instead of a rawhttpx.HTTPStatusError; the message never contains the key or the URL.Sandbox.createwith a bad key is therefore anAuthenticationError, not aSandboxCreationError. - KI-007
files.listof a missing directory raisesFileNotFoundError_instead of returning[](envd answersListDirwith HTTP 200 and no entries; an empty answer is now disambiguated with oneStat). - KI-010
@sandboxon anasync deffunction 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
FileOperationErrornaming the path, the size andABX_HTTP_TIMEOUTinstead of a barehttpxtimeout; KI-009 (Jupyter service answers 404:run_codealready 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
abxCLI moved out of the Python package to a Node.js/TypeScript project (@agent-sandbox/cli, theclirepository). Gone fromagent-sandbox: theagent_sandbox.clipackage, the[cli]and[binary]extras, theabxconsole 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) andSKILL.md, which now live in theclirepository. The CLI behaviour, flags, output and configuration files (~/.abx/...) are unchanged by the move. Migration: replacepip install "agent-sandbox[cli]"withnpm install -g @agent-sandbox/cli;pip install "agent-sandbox[cli,alicloud]"becomesnpm install -g @agent-sandbox/cli(the CLI carries its own Alibaba Cloud template client). - The coding-agent modules of
agent_sandbox.agentmoved to the CLI:adopt,clarify,codegen,coding_agent,qwen_code,template_guideanddockerfile_sources(used only byabx create "DESCRIPTION",abx template initandabx template init --adopt).agent_sandbox.agent.{tools,mcp,mcp_http}stay in the SDK;python -m agent_sandbox.agent.mcpstill 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 modelsBuildInfo,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,CustomCommandArgand thetemplate.yamlkeycustom_commands(including{placeholder}substitution) are gone; atemplate.yamlthat still hascustom_commandsfails validation.sandbox.run("name", **kwargs)isPOST /commands/nameon the in-sandbox server (CommandNotFoundErrorwhen unknown;list_commands()lists them). Bare shell stayssandbox.commands.run(cmd).@sandbox.registerno longer takesimage=. - One way to run an agent in a sandbox: the Agents API (
/v1/agents/**).BUILTIN_AGENTS,agent_sandbox.agent.builtin,agent_sandbox.agent.inferand the design docsbuilt-in-agents.mdandagents-api-cli-followups.mdare removed. The CLI has noabx agentcommand. - One capability switch, and the client follows it. Groups are aliases for endpoint ids;
ABX_SERVER_ENABLED_GROUPSis the only group variable (it only turns groups on) andABX_SERVER_DISABLED_GROUPS,enable_builtinanddisable_builtinare gone (useenable_group()orserver.groups). The/opssurface andserver/core/*are deleted; the server declares oneENDPOINTStable (118 endpoints). In the client,ServerCapabilitieshas no legacy mode and noENDPOINT_GROUPStable; it exposesgroups,group_summaryandrule(endpoint).EndpointInfogainssummaryandrule,ServerAPIErrorgainsrule, a 404 withcode: endpoint_disabledmaps toEndpointNotAvailableError, and path violations are 403path_not_allowed(FilePolicyDeniedError). template.yamlserver.groupsis a list (groups: [file_ops]) or a map (groups: {process: false});validate_server_blockchecks the group names (SERVER_GROUP_NAMES) andcorecannot be turned off.sandbox.register.upload()and.download()are removed. File transfer is thefile_opsgroup (/files/*,/upload,/download);sandbox.registeronly registers named commands.- Examples, templates and e2e use the current server API.
examples/templates/python-helloand everyawesome-templates/*/commands.pyregister with@commandand start withstart();agents-clilimits the server with an endpoint policy instead of a group alias;awesome-templates/CONTRIBUTING.mdno longer mentionscustom_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 andpath_not_allowedinstead of/ops, andexamples/run_examples_e2e.pyrunsexamples/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_KEYin error text and docs now readABX_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 classesE2005-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 ine2e/andabx templatecover them. The suite readsABX_SANDBOX_API_KEY;make e2e-allno longer needs Docker or ACR;scripts/e2e-cleanup.pyonly kills tagged sandboxes.docs/*/design/sdk-api-design.mdis rewritten to the current two paradigms;agent_sandbox.compatis documented as a partial migration helper.
[0.2.0] - 2026-09-30
Breaking Changes
-
CLI config uses one name per credential.
abx configlistssandbox_api_keyfor the sandbox service key (still stored asE2B_API_KEY;abx config get/set api_keyremains an alias). NL inference and the coding agent sharellm_api_key,llm_base_url, andllm_model.qwen_code_api_key,qwen_code_base_url, andqwen_code_modelare no longer configurable;config get/config setname thellm_*replacement. An olderABX_QWEN_CODE_API_KEY(and storedqwen_code_base_url/qwen_code_model) is still read when the matchingllm_*value is unset, and shows up under thellm_*name. Migration: useabx config set sandbox_api_key <KEY>andabx config set llm_api_key <KEY>. Setllm_base_url/llm_modelonly when the DashScope default is not the endpoint you want. The Python SDK parameter staysapi_key=. -
abx deployis the fixed build → push → register pipeline. It now runs exactly whatabx template deployruns (docker build, push to ACR,CreateTemplate, wait for ready), withPATHdefaulting to., and shares every option of that command including-v/--verbose,--acr-namespaceand--region. It needs no LLM and no LLM key, takes no description (theINSTRUCTIONargument is gone), and no longer starts aqwen-codecloud sandbox or raisesE7001. What a template is lives intemplate.yaml, authored byabx template init;deployonly reads itsname,resourcesandgeneration.--traditionalis deprecated and ignored (with a warning); the old traditional-mode-only--watchoption is removed, and--aliasnow istemplate deploy's template alias. Migration:abx deploy ./p "instruction"becomesabx template init "DESCRIPTION"(the AI writesDockerfile,commands.py,template.yamlinto./<name>/) followed byabx deploy ./<name>. The in-sandbox agent deploy remains available as the SDK APISandbox.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..envfiles 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-languageabx create, GitHub template downloads, andabx mcp installfollow that chain.abx mcp installcopiesE2B_API_URLandSANDBOX_REGIONinto 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, orshortcuts.<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 --alluse the samemessage... 12sheader 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-argvalues 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--verbosestill 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 pushdraw each long step as amessage... 12sheader with the latest four lines ofdocker build,docker push, or READY-poll output in grey underneath (ABX_ACTIVITY_LINESchanges the count). The elapsed time keeps moving once a second while the tool is silent.--verboseprints 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-languageabx init/abx template initasks an interactive terminalDirectory for the template projectbefore 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;--forceoverwrites.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 onlyDockerfile,commands.py,template.yamland a generated.dockerignoreare written back, after a preview.--hintadds what the code cannot say,--dry-runlists the files that would be sent and contacts no model,--yesskips both confirmations, and--forceis 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 notemplate.yamland points at--adopt. Nothing is built or deployed; publish withabx 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,--jsonand non-TTY sessions use the default silently.- Live agent activity line: while Qwen Code researches, assesses or generates, a TTY shows the
Assessing description... 12sheader 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..10changes 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 andTERM=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 withabx config set shortcuts.<name> "<target>". Runabx config initto generate a complete shortcuts template with all available commands. - Natural-language template init:
abx template init "DESCRIPTION"(andabx init "DESCRIPTION") generatesDockerfile,commands.pyandtemplate.yamland stops. Interactiveabx create "DESCRIPTION"/abx sandbox create "DESCRIPTION"first asks whether to switch to that template-only path before building, pushing, deploying, and creating a sandbox.--yeskeeps the full create pipeline. - AI-generated templates ship a server: the natural-language generator now writes
commands.py(anagent_sandbox.serverSandboxServeron port 9000, the process the deployed sandbox answers HTTP with),template.yamlwithcapabilities/ports, and aREADME.mdnext to theDockerfile, instead of a Dockerfile-only image. The prompt carries the server SDK reference (agent/template_guide.py); a result without a validcommands.pythat 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 emptyABX_MCP_AUTH_TOKENfails the process instead of serving/mcpwith 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 startprints 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.--httpserves Streamable HTTP;--backgrounddetaches that HTTP server (the API key and token stay in the child environment).abx mcp stopsends SIGTERM to the pid recorded under~/.abx/run.abx mcp statusreportsmcp_running.- MCP sessions follow the documented agent loop.
create_sandboxbecomes the default sandbox, so later tools can omitsandbox_idandkill_sandboxdestroys 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_commandruns viash -c. A non-zero exit is a tool error. STDIO accepts messages up to 8 MiB and answerspingwhile a tool call is in flight.GET /mcpreturns 405.abx mcp deployrefuses to write an artifact without a non-empty Bearer token and setsSANDBOX_REGION.abx mcp install --target vscodewrites.vscode/mcp.jsonand leaves non-strict JSON alone. abx config initasks 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_namespaceis a config key stored in~/.abx/.envasACR_NAMESPACE, soabx installandabx template deploypick it up without--acr-namespace. The missing-prerequisite errors nameabx config initandabx config set.- Invalid shortcut targets explain the mistake.
abx config set shortcuts.<name> "abx template init"now says to drop theabxprefix 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_wheelonly knew how to build from a source checkout, so anabxinstalled from PyPI (or the standalone binary, which has nopip) injected nothing and images silently got whateveragent-sandboxwas 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 apyproject.tomlthat is notagent-sandboxis 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_TIMEOUToverrides) 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-idthat already exists; this was the cause of the bogus "assessment unavailable; continuing straight to generation" warning.DeployLLMKeyMissingError(E7001) suggestion now mentionsABX_LLM_API_KEYandllm_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)
-
Removed
abx config reset. Clearing is now per key viaabx 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: replaceabx config reset --yeswith oneabx config set KEY ""per key you want to clear (e.g.abx config set region ""). -
abx config listshows 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 parsingconfig listoutput now see source suffixes and(not set)where the old output showed blank defaults. -
abx config initsecret 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)
-
abx template installdefault behaviour changed: download → download+build+deploy.installnow 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-onlytoabx template install/abx installinvocations that should not build and deploy. -
Removed
SerializerType.PICKLE/SerializerType.MSGPACK. The@sandboxdecorator now only supportsserializer="json". Non-JSON serializable return values must be converted todict/list/strbefore returning. Migration: change@sandbox(serializer="pickle")→@sandbox(serializer="json")and ensure return values are JSON-compatible. -
Removed runtime
check_capability()gate from most modules.CommandsModule,FilesModule, andNetworkModuleno longer raiseCapabilityNotSupportedError(E3004) at call time. Exception:CodeContextModuleretains thecodecapability gate — all its methods (run,create_context,list_contexts,restart_context,remove_context) still raise E3004 when thecodecapability is missing (fail-closed). E3004 is also still raised during template resolution / model validation viaresolve_capabilities(). Migration: removetry/except CapabilityNotSupportedErroraroundcommands.*,files.*, andnetwork.*calls; declare required capabilities intemplate.yamlinstead. Keeptry/except CapabilityNotSupportedErroraroundrun_code()/code.*calls if your template may lack thecodecapability. -
Removed
agent_sandbox.integrationssub-module. The LangChain/CrewAI/AutoGen adapter module was an empty abstract placeholder and has been deleted. Migration: useagent.toolsor MCP integration directly. -
Removed
SessionStoreabstract base class. OnlyLocalSessionStoreremains. Thesession/base.pyABC has been deleted. Migration: if you were subclassingSessionStore, switch toLocalSessionStoreor implement your own storage directly. -
SecretStorechanged 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/.envfile. Useabx config set api_key <value>to persist API keys. -
Removed
abx authCLI command group. Theabx auth login/logout/status/switchcommands have been removed. Migration: useabx config set api_key <value>to persist credentials, or setE2B_API_KEY/SANDBOX_API_KEYenvironment variables directly. -
Removed
abx secretCLI command group. Theabx secret create/list/delete/injectcommands have been removed. Migration: use environment variables or.envfiles to manage credentials and secrets. For sandbox environment injection, useabx create --env KEY=VALUE. -
Removed
abx session/abx sessionsCLI command group. Theabx sessions list/info/rename/export/import/cleanandabx start/connectcommands have been removed. Migration: session data is still stored locally in~/.abx/sessions/byLocalSessionStore. Use the SDK'sSandbox.connect()API programmatically. -
Removed
abx skillCLI command group. Theabx skill search/install/list/create/publishcommands have been removed. Migration: Skills system is a future planned feature. Use templates as the current capability distribution mechanism. -
Sandbox.run()is now a bare-shell shortcut (was named-command dispatcher).Sandbox.run(cmd)now delegates tosandbox.commands.run(cmd)and returnsProcessResult | StreamReader. It no longer dispatches named custom commands. Migration: replacesandbox.run("name", **kwargs)withsandbox.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-levelabx initshortcut has been restored as an exact alias ofabx template init(same click command object, option surface unchanged). Items 2–3 stand, and item 3 replaces the earlier "abx create(no arguments) uses thebasetemplate" routing.
-
~~Removed the top-level
abx initshortcut.~~ Superseded: restored. The top-levelabx initshortcut is back and delegates to the exact same command object asabx template init(options unchanged). Guided credentials setup remainsabx config init; cloud sandbox creation remainsabx create. Migration:abx init [DIRECTORY]andabx template init [DIRECTORY]are interchangeable again. -
abx create "DESCRIPTION" --template NAMEis now rejected. Previously--templatesilently 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--templatefor a direct launch, but not both. -
abx createwith no arguments is now an explicit usage error (exit code 2). Previously bareabx createsilently launched thebasetemplate. It now prints a routing hint (--template base,--template <NAME>, or"DESCRIPTION"for the AI path) so the choice is always explicit. Migration: useabx create --template baseto launch the base template.
Changed (CLI UX)
- Unknown top-level commands now get targeted hints. A close spelling candidate (e.g.
abx crate) gets aDid you mean 'create'?suggestion; with no plausible candidate the error points to templatecustom_commands(declared intemplate.yaml) and running them viaabx 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 theLazyGroup(lazy_subcommands=...)map insrc/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)
- Renamed the qwen-code session-turns parameter to
max_session_turns/--max-session-turnseverywhere (SDK, CLI, qwen-code templatetemplate.yaml/commands.py, docs). The old names were misleading:Sandbox.deploy(max_tool_calls=...),DeployModule.deploy_project(max_tool_calls=...), andabx deploy --max-tool-callsall forwarded the value to qwen-code's official--max-session-turnsflag (user/model/tool turn cap, exit code 53), not to the semantically different upstream--max-tool-callsbudget (cumulative tool calls, exit code 55). The pre-existing template argmax_turnsis renamed for the same reason and its default is unified to100. Migration: renamemax_tool_calls=→max_session_turns=,--max-tool-calls→--max-session-turns, and template argmax_turns→max_session_turns. Old names fail loudly (CLI usage error / SDKTypeError); no aliases are kept, matching the pre-release no-compat-shim policy. run_qwen_code_headless()/_build_headless_command()accept an optionalmax_session_turnskeyword (Noneby default adds no flag). This is the stable naming contract for the natural-languageabx createpipeline and future headless callers.
Breaking Changes (Task 187 — Template Catalog Single Source of Truth)
- 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 minimalpython-hellooffline fixture, explicitly marked as a fixture (not a publishing source). The repository-rootawesome-templates.yamlhas 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). 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 resolvedowner/repo//subdir[@ref]is printed (Resolved '<name>' via the template index: ...). Migration: no action needed for directowner/reporeferences; bare names must exist in the index. Use--index-url/ABX_TEMPLATE_INDEX_URLfor private mirrors.
Added
- Remote template index client (
agent_sandbox.utils.template_index): fetchesawesome-templates.yamlfrom the SSOT repository viaraw.githubusercontent.com(CDN — not subject to the API 60 req/hour anonymous limit), with a~/.abx/index/cache, 1-hour TTL,If-None-Matchrevalidation, 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_versionnewer than supported fails with an upgrade hint).--index-url/ABX_TEMPLATE_INDEX_URLand--token/GITHUB_TOKENare 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 fromllms.txt. Documentation only: the removedabx skillcommand 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 templatecustom_commands(mechanism A), then falls back to@registry.commandon SandboxServer (mechanism B). ReturnsCommandResultwithvalue,stdout,stderr,exit_code,execution_time,source("template"|"server"), andsuccessproperty.CommandResultdata model: Structured return type forcustom()replacing the bareAnythatrun_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_tokenconfig key (abx config set github_token): persistent GitHub token for template downloads, mapped to theGITHUB_TOKENenvironment 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 listshow it masked, andabx config set github_token ""removes it. Resolution order:--token> processGITHUB_TOKEN> storedgithub_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 injectGITHUB_TOKENas a secret or to runabx config set github_tokenin a terminal. The CLI never runsgh 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@refreferences 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 ofSandbox.custom()/Sandbox.custom_sync(). Both deprecated methods wrapcustom()internally but only returnresult.value(typeAny) for backward compatibility — the fullCommandResult(withstdout,stderr,exit_code,execution_time,source,success) is discarded. If you were treating the old return value as aProcessResult, migrate tocustom()/custom_sync()which return the completeCommandResult. Will be removed in a future release.
Breaking Changes (Official CreateTemplate API convergence)
-
abx template build-localwas removed and replaced byabx template build. The oldbuild-localcommand name no longer exists (invoking it fails withNo such command 'build-local').abx template buildruns the full pipeline: local Docker build → ACR push → template registration, andabx template deployremains an alias invoking the same pipeline. Migration: replaceabx template build-local <DIR>withabx template build <DIR>(same option surface). -
abx template build/template deploydefault to the official CreateTemplate API. The legacy v3/v2 platform API is no longer the default; it remains available behind the explicit--legacy-apiflag (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-apiexplicitly.
Changed
--tokenis documented as a temporary override:abx template install/abx template searchhelp now warns that--token <value>may leak into shell history and process listings, and recommends the persistentabx config set github_tokenas the default fix.commands.run(),commands.stream(), andcommands.start()now auto-wrap commands containing unquoted shell operators (|,;,&&,||,>,<,(...),$(...)) insh -c. Variable expansion ($VAR), backticks, and globs still require explicitsh -c '...'.abx template build(renamed frombuild-local): default mode switched to the official CreateTemplate API (--official-api). Legacy v3/v2 behaviour now requires an explicit--legacy-apiflag.- Official template path prerequisites:
abx template createandabx template build(default mode) now require thealicloudextra (pip install "agent-sandbox[cli,alicloud]"orpip install "agent-sandbox[alicloud]") and Alibaba Cloud AK/SK credentials. - When
envdInjectis enabled and--target-imageis omitted,copy.imageis now auto-derived with a-fcsandbox-<hex>random suffix to satisfy the platform requirement thatcopy.imagemust differ fromsandboxConfig.image. For a stable tag, pass--target-imageexplicitly.
Migration
- Replace
abx template build-local <DIR>withabx template build <DIR>— the old command name was removed. - Existing automation scripts invoking the build pipeline without
--legacy-apinow hit the official CreateTemplate API. To preserve the legacy v3/v2 behaviour, add--legacy-apito the command. - Automation / CI hardening: pass
--acr-namespaceand the template directory explicitly on the command line instead of relying onACR_NAMESPACE/ABX_TEMPLATE_DIRenvironment variables or.envfiles, so builds cannot silently drift with the surrounding environment. Forabx template install/abx install, either pass--acr-namespaceexplicitly or use--download-onlywhen 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_GROUPSenv 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
CapabilityGroupAPI - Core SDK:
Sandboxclass withcreate(),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,configcommands - Dual Authentication: API Key (
SANDBOX_API_KEY) and AK/SK (ALICLOUD_ACCESS_KEY_ID/SECRET) - Connect Protocol: Full
application/connect+jsonimplementation 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.Sandboxwrapper - 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()andlist_ports()APIs in favor of a simpler local URL calculation interface based on official documentation. Port URL is now computed client-side ashttps://{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)