In the previous article, I showed you how to plug Zed into Docker Agent thanks to the ACP protocol, with llmman serving the model locally.
It works very well, but there's one "small" detail: the agent runs directly on my machine. And it's allowed to use the shell... 😬
So today, we're going to do the same thing, but by running Docker Agent inside a Docker sandbox (sbx), and connecting Zed to the agent in that sandbox. And you'll see, there's almost nothing to change.
Here's a summary of my setup for this article:
sbx (Docker Sandboxes) is Docker's tool for running code agents (Claude Code, Codex, Gemini, Docker Agent, your own handmade agent...) in isolated sandboxes, based on microVMs:
sbx secret set, and the proxy injects them into outgoing requests. The keys are never present inside the sandbox, so the agent can neither read them nor leak them,A code agent is a program that decides on its own which commands it's going to run. In my setup, the agent has access to the shell toolset, and it's driven by a "small" local model. Even though Zed asks me for confirmation before each command, all it takes is a moment of inattention (or a prompt injected into a project file) for a misplaced rm -rf or a curl to an unknown server to get executed.
And on your machine, the agent also has access to your environment variables and your config files: a simple env or cat ~/.config/... and your API keys end up in the model's context (or worse, sent somewhere else).
With a sandbox, the "blast radius" is limited to the workspace and to what the network policy allows, and your secrets stay out of the agent's reach. So you keep all the power of the agent, without handing it the keys to the whole house.
Nothing changes on that side: llmman keeps running on my machine (and therefore keeps using my GPU):
For installing and downloading the model, see my dedicated article and the previous article.
I created a copy of my configuration file: sbx.llmman.docker-agent.yaml. The only thing that changes is the base_url line:
yaml
providers:
llmman:
api_type: openai_chatcompletions
#base_url: http://127.0.0.1:17434/v1
base_url: http://host.docker.internal:17434/v1
agents:
root:
model: mellum
description: A local code agent, powered by a small LLM.
instruction: |
Your name is Riker. You are a developer expert.
You act as a mentor and coding partner.
# Tool discipline
Built-in tools:
- shell: use the `shell` tool to explore the project, read files, or run commands.
Chain commands as long as it is useful, then give a clear final answer.
# Style
Be concise. Prefer a small, correct, compilable example over prose.
toolsets:
- type: shell
models:
mellum:
provider: llmman
model: huggingface.co/jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M
Why? Because the sandbox has its own localhost: inside it, 127.0.0.1 refers to the sandbox itself, not my machine. To reach llmman running on the host, we go through host.docker.internal.
From the project directory, a single command:
bash
sbx create docker-agent . --name docker-agent-acp
docker-agent: the agent to use in the sandbox,.: the current directory, which becomes the workspace shared with the sandbox,--name docker-agent-acp: the name of the sandbox, which we'll need for the Zed configuration.💡 If the agent can't reach llmman (request blocked by the proxy), you need to allow the port in the network policy, on your machine:
sbx policy allow network localhost:17434. Thesbx policy logcommand lets you see what was blocked and why.
In Zed's settings (settings.json), we add a new agent to the agent_servers section. This time, it's no longer docker-agent that Zed launches directly, but sbx exec, which will run docker-agent serve acp inside the sandbox:
json
"agent_servers": {
"🤖 docker-agent (sbx llmman)": {
"type": "custom",
"command": "sbx",
"args": [
"exec",
"-i",
"docker-agent-acp",
"docker-agent",
"serve",
"acp",
"/Users/k33g/kDrive/Rickub/demo-docker-agent-acp/sbx.llmman.docker-agent.yaml"
]
}
}
A few remarks:
-i is essential: ACP goes through stdin/stdout, so standard input must stay open between Zed and the sandbox,docker-agent-acp is the name of the sandbox we just created,Obviously, adapt the sandbox name and the path to your own configuration file.
Open Zed's agent panel, pick "🤖 docker-agent (sbx llmman)" from the list of available agents, and it's exactly the same experience as in the previous article: the agent explores your project, reads files, runs shell commands... except that all of this happens inside the sandbox. Files modified by the agent in the workspace of course show up directly in Zed, since it's the same directory.

sbx exec -i, and talks to it over ACP (JSON-RPC over stdio).host.docker.internal, going through the sandbox proxy.There you go, with next to nothing, we keep the same "100% local" setup as in the previous article, but with an agent that can no longer do whatever it wants on your machine. Feel free to ask questions 🙂