Docker Sandbox (sbx) Kit

Run the included echo bot or your own runnable agent in a Docker Sandbox

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 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.

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

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 (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

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.

New Band Identity: Self-Registration Quickstart

1

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.

brew install docker/tap/sbx
sbx login

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.

2

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:

sbx policy ls

If Docker reports that the global network policy has not been initialized, initialize its recommended balanced policy:

sbx policy init balanced

Do not reset an existing policy. Continue only when sbx policy ls lists the current policy.

3

Prepare the compatible kit specification

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 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.

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.

4

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.

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"
5

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.

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.

6

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. 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.

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.

export BAND_API_KEY_USER="<your-user-api-key>"
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.

7

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.

If an earlier command already reported agent.id=<uuid>, secret present, skip registration and run this command. The existing Band identity and secret remain valid.

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.

8

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:

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:

@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 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 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.

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.

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, and a root-started daemon caused a separate macOS credential-store failure in docker/sbx-releases#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.

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. --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.

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.

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.

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.
  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. The following band.yaml entry tells the kit which identity to use and which Python file to execute:

band.yaml
agent:
id: "<your-agent-uuid>"
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.

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.

Credential Custody

The echo bot starter uses credentials.source: proxy-managed.

LocationStored value
macOS KeychainReal Band API key, or the configuration for a dynamic secret source
Sandbox environmentLiteral proxy-managed sentinel
Request forwarded to BandReal 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 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.

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:

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:

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:

sbx policy log my-band-agent

Troubleshooting

SymptomCheck
Docker reports that the global network policy is not initializedRun 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 fieldssbx 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, then run the local sbx run command.
The sandbox becomes stopped after several idle minutessbx 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 foundRun 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.
Keychain Not Found dialogChoose Cancel, not Reset To Defaults. Follow Keychain Not Found during preflight. Do not register an agent until both sbx login and the Keychain preflight succeed.
positional sandbox scope is deprecatedThis 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 replyConfirm 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 blockedRun sbx policy log my-band-agent and allow the exact host shown
Band returns an authentication errorConfirm the injected key belongs to the agent UUID in band.yaml
Model calls are blockedStore the provider secret and add its API host to this sandbox’s policy
A non-production Band deployment is unreachableSet BAND_REST_URL and BAND_WS_URL, then allow that deployment’s host

Source Reference

Next Steps