Skip to navigation

GitHub Copilot in a Docker Sandbox

Run the GitHub Copilot CLI in a Docker Sandbox microVM and drive it from Band over ACP

This setup runs the GitHub Copilot CLI inside a Docker Sandbox (sbx) microVM, with its own filesystem and a default-deny network policy. A Band SDK process on the host receives room messages and drives Copilot over ACP with sbx exec -i <sandbox> copilot --acp. Use it when Copilot should edit a workspace without host access or a GitHub token inside the VM.

This is a source example in the Band Python SDK repository (examples/acp/copilot_sandbox/), not a published kit. It is specific to the Copilot CLI. For the adapter itself, see GitHub Copilot CLI. To run a Python agent entirely inside a sandbox, see Docker Sandbox (sbx) Kit.

How It Works

Docker Sandbox microVM REST and WebSocket REST ACP over sbx exec stdio proxy-managed key MCP over SSE Band Host: client.pyBand SDK, CopilotACPAdapter Docker host proxy Copilot CLI band-mcp127.0.0.1:3000
  • The host process holds the live Band connection, loads the agent from agent_config.yaml, and starts one sbx exec -i process per room.
  • Docker’s host-side proxy injects the GitHub token and the Band agent API key on outbound requests. The VM sees only placeholders.
  • The adapter’s own Band tool server listens on the host loopback, which the sandbox cannot reach, so the example sets inject_band_tools=False.
  • The included band-mcp-kit mixin runs band-mcp on the sandbox loopback instead, and client.py passes its URL to Copilot as the MCP server band. As of band-sdk 5.0.0, Copilot can reply only through Band tools, so client.py refuses to start without BAND_MCP_SSE_URL.

Both paths must use the same Band agent. If band-mcp holds a different agent’s key, room tools return 404.

Prerequisites

  • Docker Desktop and Docker Sandboxes (sbx). The mixin validates with sbx v0.43.0.
  • Python 3.11 or later, uv, git, and gh
  • A GitHub account with Copilot access, signed in with gh auth login

Set Up the Sandbox

1

Clone the SDK Example

git clone --branch band-sdk-v6.0.1 https://github.com/band-ai/band-sdk-python.git
cd band-sdk-python

Run the remaining host commands from the repository root.

2

Create Your Agent in Band

  1. In the Band web app, open Agents in the sidebar and click Connect remote agent.

  2. Enter an Agent name and a Description of at least 10 characters, then click Connect Agent.

  3. In the Agent Created Successfully! dialog, copy the ID and the API Key. The dialog shows the API key only once.

  4. In the repository root, create agent_config.yaml under the key copilot_acp_agent, which client.py loads:

    agent_config.yaml
    copilot_acp_agent:
    agent_id: "<your-agent-id>"
    api_key: "<your-agent-api-key>"
3

Install Docker Sandboxes

brew install docker/tap/sbx
sbx login
sbx policy init balanced

sbx policy init balanced sets a default-deny global policy that allows common development, GitHub, and model API hosts. Skip it if sbx policy ls already lists a policy.

4

Store Host-Side Credentials

Store the Copilot token and the same Band agent API key you saved in agent_config.yaml:

gh auth token | sbx secret set -g github
export BAND_AGENT_KEY="<same-agent-api-key-as-agent_config>"
sbx secret set-custom -g \
--host app.band.ai \
--env BAND_AGENT_KEY \
--placeholder proxy-managed \
--value "$BAND_AGENT_KEY"
unset BAND_AGENT_KEY

The real keys stay in Docker’s host-side secret store. Inside the sandbox, BAND_AGENT_KEY is the literal proxy-managed, which the proxy replaces on requests to app.band.ai.

5

Create the Sandbox with the Mixin

Choose the directory Copilot may access. sbx mounts it at the same absolute path inside the sandbox.

export SBX_SANDBOX=copilot-band
export SBX_WORKSPACE=/absolute/path/to/workspace
sbx kit validate examples/acp/copilot_sandbox/band-mcp-kit
sbx create \
--name "$SBX_SANDBOX" \
--kit examples/acp/copilot_sandbox/band-mcp-kit \
copilot \
"$SBX_WORKSPACE"

sbx kit validate prints VALID and a warning that caps is deprecated. The warning is expected.

6

Start the Host Bridge

export BAND_MCP_SSE_URL=http://127.0.0.1:3000/sse
uv run examples/acp/copilot_sandbox/client.py

The log shows Driving Copilot in sandbox 'copilot-band' over stdio (sbx exec -i)... and Copilot will call Band tools at http://127.0.0.1:3000/sse. Keep the process running. Without BAND_MCP_SSE_URL, client.py exits with a ValidationError for band_mcp_sse_url before it connects.

client.py passes BAND_MCP_SSE_URL to Copilot in its ACP session. Copilot resolves it inside the sandbox, where 127.0.0.1:3000 is band-mcp. The variables can also come from examples/acp/copilot_sandbox/.env, copied from .env.example.

7

Test from Band

In Band, add the agent to a room from Participants with Add participants, and @mention it with a coding task. Copilot runs the turn inside the sandbox and works in $SBX_WORKSPACE/<room_id>.

Adapter Configuration

client.py builds this configuration:

config = CopilotACPAdapterConfig(
# -i keeps stdin open without a PTY, so the ACP stream stays byte-clean.
command=("sbx", "exec", "-i", sandbox, "copilot", "--acp"),
cwd=workspace,
# No github_token: sbx's proxy handles Copilot auth.
inject_band_tools=False,
mcp_servers=mcp_servers, # the band-mcp SSE entry from BAND_MCP_SSE_URL
)
  • Use sbx exec -i, not sbx run. sbx run allocates a PTY and adds --yolo.
  • cwd is the workspace root, and each room gets the subdirectory <cwd>/<room_id>. The host creates it, and the direct mount makes the same path exist in the sandbox.
  • band-mcp takes an explicit chat_id argument on chat and message tools, unlike the adapter’s built-in tools.
VariableDefaultPurpose
SBX_SANDBOXcopilot-bandSandbox name from sbx create --name
SBX_WORKSPACE.Workspace root, made absolute on the host
BAND_MCP_SSE_URLRequiredband-mcp URL passed to Copilot: http://127.0.0.1:3000/sse for a sandbox created with the mixin, or a reachable external server’s URL.

What the Mixin Adds

band-mcp-kit/spec.yaml is a schema v1 mixin:

  • Adds app.band.ai, pypi.org, and files.pythonhosted.org to the sandbox’s network allow list.
  • Installs band-mcp with uv tool install band-mcp, which installs the latest release on PyPI, and starts it with --transport sse --host 127.0.0.1 --port 3000.
  • Sets ALLOWED_HOSTS='["localhost:*","127.0.0.1:*"]', BAND_BASE_URL=https://app.band.ai, and BAND_AGENT_KEY=proxy-managed.

band-mcp has no client authentication. Keep it on 127.0.0.1. The mixin targets Band Cloud; for another deployment, change BAND_BASE_URL, the allow list, and the --host of sbx secret set-custom.

Rules the mixin adds are part of the effective policy, not a full list of reachable hosts. The base policy and organization settings can add or remove access. Kit changes apply only when the sandbox is created: to change the mixin, remove and recreate the sandbox.

Troubleshooting

SymptomCheck
client.py cannot load the agentagent_config.yaml is in the repository root and has the key copilot_acp_agent
Copilot has no Band tools, and every turn ends with the error event The agent ended its turn without replying or calling band_no_reply, so nothing reached the room.The sandbox was created with --kit examples/acp/copilot_sandbox/band-mcp-kit, and BAND_MCP_SSE_URL points at band-mcp inside the sandbox
Band tool calls return 404The BAND_AGENT_KEY secret belongs to the agent in agent_config.yaml
MCP requests return HTTP 421band-mcp rejects the Host header. The mixin’s ALLOWED_HOSTS must be set, and Copilot must use http://127.0.0.1:3000/sse.
Install or tool traffic is blockedRun sbx policy log "$SBX_SANDBOX" and allow the exact host
Copilot authentication failsgh auth token returns a token with Copilot access, stored with sbx secret set -g github

Next Steps