> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs-dev.band.ai/integrations/sandboxes/docker-sbx-kit/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-dev.band.ai/_mcp/server. # Docker Sandbox (sbx) Kit > Use the Docker Sandbox (sbx) kit to run a locked Python workspace with restricted egress and proxy-managed credentials The Docker Sandbox (`sbx`) kit runs a locked Python workspace inside a Docker Sandbox microVM. Its included example is a deterministic, non-agent echo bot: it repeats each Band message without a model or reasoning loop. Replace the example entrypoint with any runnable Python agent. If you already have runnable Python agent code, complete the sandbox setup first, then follow [Replace the Echo Bot with an Agent](#replace-the-echo-bot-with-an-agent) to connect it. The published Docker image is named `bandhq/band-python-kit-image`. The kit installs no dependencies into your host environment, synchronizes the workspace's committed `uv.lock`, and starts the configured entrypoint whenever the sandbox starts. > **Warning** > > This guide pins Band SDK and image version `3.1.1` and is tested with `sbx` v0.43.0. The published `bandhq/band-python-kit:3.1.1` OCI kit uses the older experimental schema supported by `sbx` v0.35.0. `sbx` v0.42.1 and v0.43.0 reject that artifact. The compatibility step below uses the same digest-pinned image through a local schema-v1 specification that v0.43.0 validates. ## How It Works ```mermaid flowchart TD Host["Host workspace
band.yaml, source, uv.lock"] Proxy["Docker host proxy
real credentials"] Band["Band REST and WebSocket"] subgraph Sandbox[Docker Sandbox microVM] Launcher[Docker Sandbox kit launcher] Runtime[Echo bot or runnable Python agent] Launcher -->|sync locked dependencies and exec| Runtime end Host -->|read/write mount| Launcher Runtime -->|proxy-managed sentinel| Proxy Proxy -->|inject real credential| Band ``` The sandbox contains two Python environments: * The kit environment runs the launcher and reports configuration or startup failures. * The workspace environment contains only the dependencies selected by your `uv.lock`. The launcher reads `band.yaml`, creates the workspace environment outside the mounted workspace, and replaces itself with the configured entrypoint. Signals from `sbx stop` therefore reach your process directly. ## Prerequisites * macOS. This guide's credential storage and recovery steps use the macOS Keychain (`security`) and Terminal.app; they do not apply on Linux, where Docker Sandboxes uses a different secret-storage backend. * Docker Desktop and [Docker Sandboxes](https://docs.docker.com/ai/sandboxes/) (`sbx`), tested with v0.43.0 * `uv` on the host * Exactly one Band credential path: * **New Band identity:** A user API key that can register an agent * **Existing Band identity:** The existing agent ID and agent API key > **Warning** > > Choose one path. If you already created the agent in Band, do not run `band-kit provision`. Skip to [Existing Band Identity: Create Only the Sandbox](#existing-band-identity-create-only-the-sandbox). ## New Band Identity: Self-Registration Quickstart ### Install Docker Sandboxes The next two commands install the Docker Sandboxes CLI with Homebrew, then authenticate `sbx` with Docker so it can pull kits and manage local sandboxes. ```bash brew install docker/tap/sbx sbx login ``` > **Warning** > > Do not continue until `sbx login` succeeds. On macOS, Docker stores the `sbx` sign-in credential in the system Keychain. `--password-stdin` changes how login receives a credential, but does not change where Docker stores it. ### Initialize Docker's global network policy Docker requires a one-time global network policy before the first sandbox can start. First, check whether a policy already exists: ```bash sbx policy ls ``` If Docker reports that the global network policy has not been initialized, initialize its recommended balanced policy: ```bash sbx policy init balanced ``` Do not reset an existing policy. Continue only when `sbx policy ls` lists the current policy. ### Prepare the compatible kit specification > **Note** > > This section — and the `$BAND_KIT_DIR` workaround it feeds into under "Start and attach to the Docker Sandbox," "Existing Band Identity: Create Only the Sandbox," and the `invalid spec.yaml` troubleshooting row below — is temporary. It works around a schema mismatch in the published `3.1.1` kit (declares `schemaVersion: "2"` but still uses v1-era fields) that [band-ai/band-sdk-python#642](https://github.com/band-ai/band-sdk-python/pull/642) fixes at the source. Once that ships in a released kit version, this local-patch flow collapses to validating and running the published kit directly by tag. Delete this section and every `$BAND_KIT_DIR` reference at that point. Docker changed its experimental schema after the `3.1.1` kit was published. The commands below download the immutable release specification, declare it as schema v1 for current `sbx`, replace its build-time image placeholder with the published digest-pinned image, then validate the result. The local specification contains no credentials. ```bash export BAND_KIT_VERSION=3.1.1 export BAND_KIT_SOURCE_COMMIT=8a26713f70678b4a5ef1cbed27f8190c8474ea79 export BAND_KIT_IMAGE_DIGEST=sha256:f6ed66a631e2ce239686f06959aafe4ff26a0c502aee3542f8f26948a88a22e5 export BAND_KIT_DIR="$HOME/.config/band/band-python-kit-${BAND_KIT_VERSION}-sbx-v1" mkdir -p "$BAND_KIT_DIR" curl -fsSL \ "https://raw.githubusercontent.com/band-ai/band-sdk-python/${BAND_KIT_SOURCE_COMMIT}/docker/band_python_kit/spec.yaml" \ -o "$BAND_KIT_DIR/spec.yaml" /usr/bin/sed -i '' \ -e '1,5d' \ -e 's/schemaVersion: "2"/schemaVersion: "1"/' \ -e "s|image: band-python-kit:local|image: docker.io/bandhq/band-python-kit-image:${BAND_KIT_VERSION}@${BAND_KIT_IMAGE_DIGEST}|" \ "$BAND_KIT_DIR/spec.yaml" sbx kit validate "$BAND_KIT_DIR" sbx kit inspect "$BAND_KIT_DIR" ``` Validation should report `VALID`. v0.43.0 also warns that `caps` is deprecated under schema v1; this warning is expected for the compatibility copy. Stop on any validation error. Inspection must show the `3.1.1` image with the digest above. ### Download the pinned starter workspace The starter is a plain `uv` project containing the non-agent echo bot, `band.yaml`, and a committed lockfile. The commands below create an empty workspace directory and extract only the matching echo example from the SDK release archive. ```bash mkdir -p "$HOME/my-band-agent" curl -fsSL "https://codeload.github.com/band-ai/band-sdk-python/tar.gz/refs/tags/band-sdk-v${BAND_KIT_VERSION}" \ | tar -xz --strip-components=4 -C "$HOME/my-band-agent" \ "band-sdk-python-band-sdk-v${BAND_KIT_VERSION}/docker/band_python_kit/echo-agent" ``` ### Verify macOS Keychain access Agent registration returns its API key once, but `band-kit provision` must store that key in Docker's secret store afterward. Verify Keychain writes before registering anything. The first command unlocks your login Keychain and may prompt for your macOS password. The next command writes a harmless test value under a temporary sandbox scope, which forces the same Keychain write used during provisioning. The final command removes that test value. ```bash security unlock-keychain "$HOME/Library/Keychains/login.keychain-db" sbx secret set-custom \ --sandbox band-keychain-preflight \ --host keychain-preflight.invalid \ --env BAND_KEYCHAIN_PREFLIGHT \ --placeholder band-keychain-preflight \ --value not-a-secret sbx secret rm \ --sandbox band-keychain-preflight \ --placeholder band-keychain-preflight \ --force ``` Continue only when both test commands succeed. If macOS displays **Keychain Not Found**, choose **Cancel**, not **Reset To Defaults**, then follow [Keychain Not Found during preflight](#keychain-not-found-during-preflight). ### Register the Band identity and store its key **Do not create an agent in Band before this step.** Create only a user API key in [Band settings](https://app.band.ai/users/settings). Prefer a key limited to agent registration, and keep it out of source control. The commands below put the user key in the current shell, then use `uvx` to run the `band-kit` executable supplied by `band-sdk==3.1.1` in an isolated tool environment. `--no-create` registers the identity, writes the non-secret ID to `band.yaml`, and stores the generated agent API key in Docker's host-side secret store without invoking the incompatible published OCI kit. > **Warning** > > Registration and local secret storage are separate operations. If storage fails after registration, the CLI prints the agent API key once. Do not rerun provisioning, paste that key into chat or an issue, or close the terminal before following [Recover from a Keychain failure](#recover-from-a-keychain-failure). ```bash export BAND_API_KEY_USER="" uvx --from "band-sdk==${BAND_KIT_VERSION}" band-kit provision \ --name my-band-agent \ --agent-name "My Sandbox Echo" \ --description "A deterministic echo bot running in a Docker Sandbox." \ --workspace "$HOME/my-band-agent" \ --no-create ``` A successful run prints the new Band agent UUID and returns to the shell prompt. ### Start and attach to the Docker Sandbox The local compatibility specification uses the same published `3.1.1` image as the OCI kit. `sbx` v0.43.0 automatically stops a sandbox created with `sbx create` after it becomes idle. Run and attach instead, then keep this terminal open while the agent should receive messages. > **Note** > > If an earlier command already reported `agent.id=, secret present`, skip registration and run this command. The existing Band identity and secret remain valid. ```bash sbx run "$BAND_KIT_DIR" \ --name my-band-agent \ "$HOME/my-band-agent" ``` The sandbox is ready when Docker finishes any image-pull and VM-startup work, then displays `root@my-band-agent` inside the attached sandbox. ### Verify the echo bot Keep the attached terminal open. In a second host terminal, verify that Docker started the sandbox and its background agent process: ```bash sbx ls sbx exec my-band-agent cat /var/log/sbx-kit-startup.log ``` `sbx ls` must show `my-band-agent` with status `running`. The startup log should include `Launching customer entrypoint` for `main.py` and no later error. A `running` sandbox confirms that Docker started the environment. The echo reply confirms that the agent also connected to Band. In Band, add **My Sandbox Echo** to a room, then send a new message after the sandbox is running: ```text @My Sandbox Echo hello from Band ``` The non-agent echo bot sends an `echo:` reply containing the received message from inside the sandbox. After this smoke test passes, follow [Replace the Echo Bot with an Agent](#replace-the-echo-bot-with-an-agent) to replace the starter with your own runnable Python agent. ## Recover from a Keychain Failure The preflight exposes Docker secret-storage failures before agent registration. A failed preflight does not create a Band identity. If provisioning had already registered an identity before storage failed, keep its printed key private. On macOS, recovery cannot continue until both `sbx login` and the Keychain preflight succeed. ### Keychain Not Found during preflight Choose **Cancel** in the dialog. Do not choose **Reset To Defaults** as a troubleshooting shortcut. [Apple states that resetting the default Keychain deletes all passwords stored in it](https://support.apple.com/guide/keychain-access/if-you-need-to-update-your-keychain-password-kyca2429/mac) and requires logging out and back in. The next three commands only inspect your user Keychain configuration. They print the default Keychain, the Keychain search list, and whether the expected login Keychain can be opened. They do not change or delete Keychain data. ```bash security default-keychain -d user security list-keychains -d user security show-keychain-info "$HOME/Library/Keychains/login.keychain-db" ``` If those commands identify the login Keychain, restart the Docker Sandboxes daemon as your logged-in user. The commands below stop any user-owned daemon, then start a fresh one with the current desktop user's Keychain context. Do not run them with `sudo`. ```bash sbx daemon stop sbx daemon start ``` Run the preflight again from Terminal.app in an active macOS desktop session. Avoid SSH, `sudo`, and background launch contexts. Docker has confirmed that a locked Keychain in an SSH session prevents `sbx` from reading credentials in [docker/sbx-releases#486](https://github.com/docker/sbx-releases/issues/486), and a root-started daemon caused a separate macOS credential-store failure in [docker/sbx-releases#77](https://github.com/docker/sbx-releases/issues/77). If the dialog still appears, do not register an agent. The following command generates Docker diagnostics as a local GitHub issue report. Review it for sensitive paths or values before sharing it with [Docker Sandbox support](https://github.com/docker/sbx-releases/issues). ```bash sbx diagnose --output github-issue ``` ### No file-backed Keychain bypass on macOS [Docker documents that macOS stores both literal values and dynamic secret sources in the system Keychain](https://docs.docker.com/ai/sandboxes/configuration/credentials/#where-secrets-are-stored). `--command` and `--ref` change how Docker resolves a secret, but their source configuration still uses Docker's Keychain-backed secret store. `sbx login --password-stdin` also persists the resulting Docker credential in Keychain. Docker's automatic file-backed secret store is available only on Linux when no Secret Service is running. It is not a macOS fallback. If `sbx login` fails while saving credentials, stop. Repair Docker's Keychain access or run the sandbox from a supported Linux host before continuing. Do not run `band-kit provision`, because it can register a Band identity before the local Docker operation fails. If an earlier version of this guide caused you to save a still-private key at `~/.config/band/my-band-agent-api-key`, leave the mode-`600` file in place until Keychain access is repaired. Do not print or paste its contents. After `sbx login` and the Keychain preflight both succeed, the commands below import that key into Docker's secret store. ```bash export BAND_KIT_VERSION=3.1.1 export BAND_KIT_DIR="$HOME/.config/band/band-python-kit-${BAND_KIT_VERSION}-sbx-v1" BAND_SECRET_FILE="$HOME/.config/band/my-band-agent-api-key" /bin/cat "$BAND_SECRET_FILE" | sbx secret set-custom \ --sandbox my-band-agent \ --host '**.band.ai' \ --env BAND_API_KEY \ --placeholder proxy-managed ``` Continue only when `sbx secret set-custom` succeeds. The next commands delete the plaintext file, remove its path from the shell, then start and attach to the sandbox. ```bash rm -f "$BAND_SECRET_FILE" unset BAND_SECRET_FILE sbx run "$BAND_KIT_DIR" \ --name my-band-agent \ "$HOME/my-band-agent" ``` ### Provisioning failed but the printed key is still private Do not rerun `band-kit provision`. The failed command already registered the Band identity and wrote its ID to `band.yaml`. The commands below unlock your login Keychain, read the printed agent key without displaying it or saving it in shell history, pipe it to `sbx` using the current `--sandbox` syntax, and remove it from the shell. The final command starts and attaches to the sandbox that provisioning did not reach. ```bash export BAND_KIT_DIR="$HOME/.config/band/band-python-kit-3.1.1-sbx-v1" security unlock-keychain "$HOME/Library/Keychains/login.keychain-db" printf "Agent API key: " read -r -s BAND_API_KEY printf "\n" printf '%s' "$BAND_API_KEY" | sbx secret set-custom \ --sandbox my-band-agent \ --host '**.band.ai' \ --env BAND_API_KEY \ --placeholder proxy-managed unset BAND_API_KEY sbx run "$BAND_KIT_DIR" \ --name my-band-agent \ "$HOME/my-band-agent" ``` If Keychain storage fails again, keep the key private and stop. Do not create the sandbox until `sbx secret set-custom` succeeds. ### The key is lost or exposed Treat a key copied into chat, an issue, or shared logs as exposed. Do not inject it into the sandbox. 1. Delete the orphaned identity from Band. You can use Band's agent management interface or the [`DELETE /api/v1/me/agents/{id}` endpoint](/api/human-api/human-api-agents/delete-my-agent). 2. Restore `agent.id: replace-with-agent-id` in the starter's `band.yaml`. 3. Complete the Keychain preflight above. 4. Run self-registration again. Use a new `--agent-name` if the orphaned identity could not be deleted. An orphaned identity still counts against your plan's agent limit until you delete it. ## Existing Band Identity: Create Only the Sandbox Use this flow instead of the self-registration quickstart when the agent already exists in Band. Do not run `band-kit provision`. Create the remote Band identity by following [Connect Any Agent](/getting-started/connect-remote-agent#step-2-create-a-remote-agent-in-band). The following `band.yaml` entry tells the kit which identity to use and which Python file to execute: **`band.yaml`** ```yaml title="band.yaml" agent: id: "" entrypoint: main.py ``` Store that same identity's API key on the host, then start and attach to the sandbox. The commands below read the key without displaying it or saving it in shell history, pipe it to Docker's secret store under the `my-band-agent` sandbox scope, remove it from the shell, and run the compatible local specification prepared above. ```bash export BAND_KIT_VERSION=3.1.1 export BAND_KIT_DIR="$HOME/.config/band/band-python-kit-${BAND_KIT_VERSION}-sbx-v1" printf "Agent API key: " read -r -s BAND_API_KEY printf "\n" printf '%s' "$BAND_API_KEY" | sbx secret set-custom \ --sandbox my-band-agent \ --host '**.band.ai' \ --env BAND_API_KEY \ --placeholder proxy-managed unset BAND_API_KEY sbx run "$BAND_KIT_DIR" \ --name my-band-agent \ "$HOME/my-band-agent" ``` `BAND_API_KEY` must belong to the UUID in `band.yaml`. Do not create the sandbox unless secret storage succeeds. If Keychain writes fail on macOS, stop and follow [No file-backed Keychain bypass on macOS](#no-file-backed-keychain-bypass-on-macos). ## Credential Custody The echo bot starter uses `credentials.source: proxy-managed`. | Location | Stored value | | ------------------------- | ------------------------------------------------------------------- | | macOS Keychain | Real Band API key, or the configuration for a dynamic secret source | | Sandbox environment | Literal `proxy-managed` sentinel | | Request forwarded to Band | Real key injected by Docker's trusted host-side proxy | The real Band key does not enter the VM. The SDK sends the sentinel in the normal authentication field, and the proxy replaces it only for the configured Band host. After `sbx login` succeeds, a plaintext workspace env file can bypass proxy-managed agent-secret storage, but it stores the real credential in both the mounted workspace and the VM. It does not bypass Docker authentication. Use it only when proxy injection is unavailable. The annotated [`band.yaml`](https://github.com/band-ai/band-sdk-python/blob/band-sdk-v3.1.1/docker/band_python_kit/echo-agent/band.yaml) shows the required acknowledgement and file path. ## Replace the Echo Bot with an Agent The starter's `main.py` uses a deterministic echo adapter and no model. Replace it with any runnable Python agent. Keep `agent.entrypoint` in `band.yaml` pointed at the file that starts your process. For a Band framework adapter: 1. Replace the echo adapter in `main.py`, or replace the file and update `agent.entrypoint`. 2. Add the matching `band-sdk` extra and any application dependencies to `pyproject.toml`. 3. Store each provider credential on the host. 4. Allow only the network hosts the agent needs. 5. Regenerate and commit `uv.lock`. For example, the first command below stores an Anthropic key in Docker's host-side secret store. The second permits this sandbox to reach Anthropic. The third resolves the workspace dependencies and updates `uv.lock`. ```bash sbx secret set -g anthropic sbx policy allow network --sandbox my-band-agent api.anthropic.com uv lock ``` After changing dependencies, stop and restart the sandbox. This makes the kit launcher synchronize the updated lockfile before it executes your entrypoint: ```bash sbx stop my-band-agent sbx run --name my-band-agent ``` ## Network Access The kit's baseline allows Band Cloud plus `pypi.org` and `files.pythonhosted.org`, which are required to synchronize locked dependencies in a fresh sandbox. LLM providers, source-control hosts, custom APIs, and non-production Band deployments require explicit per-sandbox rules. The following commands allow only OpenAI's API and GitHub for `my-band-agent`. Add a host only when the code inside that sandbox needs it: ```bash sbx policy allow network --sandbox my-band-agent api.openai.com sbx policy allow network --sandbox my-band-agent github.com ``` Kit rules are part of the effective sandbox policy, not a complete statement of everything reachable. A selected base policy or organization governance can add, restrict, or override access. The next command displays allowed and blocked requests for this sandbox so you can identify the exact host behind a failed network call: ```bash sbx policy log my-band-agent ``` ## Troubleshooting | Symptom | Check | | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Docker reports that the global network policy is not initialized | Run `sbx policy init balanced`, then confirm `sbx policy ls` lists the policy before starting the sandbox. | | `invalid spec.yaml`, including unknown `aiFilename`, `commands`, `caps`, or `agentContext` fields | `sbx` v0.42.1 or v0.43.0 is parsing the older published OCI kit as the current v2 schema. Do not register another agent. Prepare the [compatible kit specification](#prepare-the-compatible-kit-specification), then run the local `sbx run` command. | | The sandbox becomes `stopped` after several idle minutes | `sbx` v0.43.0 stops unattached sandboxes when they become idle. Run `sbx run "$BAND_KIT_DIR" --name my-band-agent "$HOME/my-band-agent"` and keep that attached terminal open while the agent should receive messages. | | `band-kit: command not found` | Run `uvx --from "band-sdk==3.1.1" band-kit provision ...` as shown above. `uvx` invokes the executable without requiring it on `PATH`. If you intentionally used `uv tool install`, run `uv tool update-shell` and open a new shell before calling `band-kit` directly. | | `Keychain Error. (-60006)` | macOS canceled the Keychain authorization request. During `sbx login`, Docker authentication was not saved. During preflight, no Band identity was created. If provisioning printed a key, keep it private and follow [Recover from a Keychain failure](#recover-from-a-keychain-failure). | | **Keychain Not Found** dialog | Choose **Cancel**, not **Reset To Defaults**. Follow [Keychain Not Found during preflight](#keychain-not-found-during-preflight). Do not register an agent until both `sbx login` and the Keychain preflight succeed. | | `positional sandbox scope is deprecated` | This is a warning from the pinned `band-kit` CLI, not the cause of a failure. Recovery commands use the current `--sandbox` syntax. | | Sandbox is `running`, but the echo bot does not reply | Confirm the `sbx run` terminal remains attached. Read `sbx exec my-band-agent cat /var/log/sbx-kit-startup.log` from a second host terminal. Confirm it reaches `Launching customer entrypoint` for `main.py` without a later error, then send a new mention. | | Launch fails in `[sync]` | Run `uv lock`, confirm `uv.lock` is committed, then restart the sandbox | | REST or WebSocket requests are blocked | Run `sbx policy log my-band-agent` and allow the exact host shown | | Band returns an authentication error | Confirm the injected key belongs to the agent UUID in `band.yaml` | | Model calls are blocked | Store the provider secret and add its API host to this sandbox's policy | | A non-production Band deployment is unreachable | Set `BAND_REST_URL` and `BAND_WS_URL`, then allow that deployment's host | ## Source Reference * [Docker Sandbox (`sbx`) kit release source](https://github.com/band-ai/band-sdk-python/tree/band-sdk-v3.1.1/docker/band_python_kit) * [Non-agent echo bot workspace](https://github.com/band-ai/band-sdk-python/tree/band-sdk-v3.1.1/docker/band_python_kit/echo-agent) * [Docker Sandbox kits](https://docs.docker.com/ai/sandboxes/customize/kits/) * [Docker `sbx secret set-custom` CLI reference](https://docs.docker.com/reference/cli/sbx/secret/set-custom/) * [Docker Sandbox credential storage](https://docs.docker.com/ai/sandboxes/configuration/credentials/) ## Next Steps #### [Compare sandbox integrations](/integrations/sandboxes/overview) Choose between the Docker Sandbox (`sbx`) kit, Copilot MCP mixin, and NemoClaw. #### [GitHub Copilot inside a Docker Sandbox](/integrations/sandboxes/copilot-mcp-kit) Keep Copilot and its Band tools inside a Docker Sandbox. > Run the included echo bot or your own runnable agent in a Docker Sandbox