How to run mini-me in a Docker Sandbox
This guide shows how to run mm inside a Docker Sandbox, so that every command the model runs and every file it edits happens in a container, on a mounted copy of your project. It covers the two ways of using it: the window mode in your terminal, and from an editor through the Agent Client Protocol. It assumes Docker Desktop with the sbx command, and a model server (Docker Model Runner or llama-server) running on your machine.
Everything lives under docker-sbx/ in the repository:
| Piece | What it is |
|---|---|
template/Dockerfile |
The template: Docker Sandboxes' shell image with mm built from this checkout, plus the two entry points below. |
kits/mm-tui/spec.yaml |
A sandbox kit: sbx run on it opens mm's window mode on the workspace. |
kits/mm-acp/spec.yaml |
A sandbox kit for an editor: created once with sbx create, the editor then runs mm -acp inside it. |
build.sh |
Builds the template image, k33g/mm-sandbox:<version>; PUSH=1 builds it for linux/amd64 and linux/arm64 and pushes it. |
sync-kits.sh, push-kits.sh |
Point the kits at one image, and publish them to Docker Hub as OCI kit artifacts. |
Use the published kits
Every release publishes the image and both kits to Docker Hub at mm's version — k33g/mm-sandbox:0.0.2, k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2 — so the shortest path needs no build at all. Docker Hub is an allowed kit source by default (sbx settings get kit.allowedSources shows docker.io/), and a reference with a / but no registry host is read as docker.io/…:
cd /path/to/your/project
sbx run k33g/mm-tui:0.0.2 . -- agent.dmr.yaml
for the window mode, and for an editor:
sbx create --name mm-acp k33g/mm-acp:0.0.2 . --kit-arg config=agent.dmr.yaml
then the editor registration of step 3 below. No --pull never: the kit names k33g/mm-sandbox:0.0.2 and sbx pulls it. sbx kit inspect k33g/mm-tui:0.0.2 shows what a kit declares before you run it. The steps that follow build the same thing locally, for a work-in-progress mm.
Steps
1. Build the template
From the repository root:
./docker-sbx/build.sh
This reads mm's tag from release.env (v0.0.2) and builds k33g/mm-sandbox:0.0.2: the image tag is the version without the v, like the release assets, and mm inside is stamped with the tag — mm --version is run in the image as proof. The script then rewrites the kits' default tag argument to 0.0.2, so the kits and the image move together. ./docker-sbx/build.sh v0.0.3 builds another version; an earlier image stays reachable with --kit-arg tag=0.0.1.
The image is in your local Docker image store: every sbx run or sbx create on these kits takes --pull never until the image is pushed (docker push k33g/mm-sandbox:0.0.2), or sbx tries to pull it and fails. If sbx runs on another machine, EXPORT=1 ./docker-sbx/build.sh also writes tmp/mm-sandbox-0.0.2.tar, to load there with sbx template load.
2. Window mode in the terminal (kit mm-tui)
From the project you want mm to work on:
sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
The first time, sbx creates the sandbox, mounts the current directory as its workspace and attaches; then it runs the kit's entry point with what follows -- as arguments — here mm -tui agent.dmr.yaml, in the workspace. Any mm flag passes the same way: -- -config other.yaml.
Without anything after --, mm reads the kit's config argument, then ./agent.yaml in the workspace, then its built-in defaults:
sbx run --pull never ./docker-sbx/kits/mm-tui . --kit-arg config=agent.dmr.yaml
--kit-arg |
Default | Effect |
|---|---|---|
config=<path> |
empty | The configuration file, as mm's AGENT_CONFIG: relative to the workspace, or absolute inside the sandbox. |
tag=<version> |
the version last built (0.0.2) |
Which k33g/mm-sandbox:<version> image the sandbox is made from. |
The sandbox keeps its name (mm-tui-<directory> unless you pass --name); sbx run --name <name> re-attaches to it later. Inside, the window is the one described in Use the window mode. Sessions, when sessions.enabled is on, are written under the workspace's .mm/sessions — that is your host directory, so they survive the sandbox.
3. From an editor (kit mm-acp)
An editor talks to mm -acp over the agent's raw stdin and stdout. sbx run cannot carry that: it always allocates a terminal. So the sandbox is created once without attaching, and the editor starts mm inside it with sbx exec -i, which pipes stdin and stdout untouched.
-
From the project the editor will open, create the sandbox with the configuration file baked in (
.is the workspace, sbx makes it absolute; the kit path must be an explicit./,../or absolute path):cd /path/to/your/project sbx create --pull never --name mm-acp /path/to/mini-me/docker-sbx/kits/mm-acp . \ --kit-arg config=agent.dmr.yamlA workspace path that does not exist on your machine makes sbx ask "The selected workspace does not exist. Would you like to create it?" — answer
Nand fix the path.--kit-arg configbecomes the container'sAGENT_CONFIG, relative to the workspace because that is wheresbx execstartsmm. The workspace is fixed at creation: one sandbox per project, each with its own--name. -
Register it in the editor. In Zed's
settings.json:{ "agent_servers": { "mini-me (sandbox)": { "type": "custom", "command": "sbx", "args": ["exec", "-i", "mm-acp", "mm", "-acp"] } } }Compared with the host-side setup, the command is
sbxand noenvis needed:AGENT_CONFIGis already in the container. If the editor cannot findsbx, put the absolute path fromwhich sbxin"command". -
Open the agent panel and pick mini-me (sandbox). The editor starts
mm -acpin the sandbox for every conversation;sbx execstarts the sandbox first when it is stopped. Tool calls, permission dialogs,@filementions and the slash-command menu work as they do on the host — the difference is where the commands run.
Attaching to this sandbox with sbx run --name mm-acp does not start mm: its entry point prints the wiring above with the sandbox's real name and paths, then opens a shell inside the sandbox. sbx exec -it mm-acp bash is the shorter way to that shell.
The model server stays on the host
Inside a sandbox localhost is the sandbox itself. Your model server keeps running on your machine and is reached through host.docker.internal, which the sandbox proxy maps to your host's localhost.
- Docker Model Runner — nothing to change:
agent.dmr.yamlalready hasfallback: http://host.docker.internal:12434/engines/v1, andmmswitches to it whenlocalhost:12434does not answer (the banner says which URL won). - llama-server —
agent.llamacpp.yamlhas no fallback. Either edit itsbaseUrltohttp://host.docker.internal:8080/v1, or pass--env AGENT_BASE_URL=http://host.docker.internal:8080/v1tosbx run/sbx create(see Run with llama.cpp).
Both kits allow ports 12434 and 8080 on the host in the sandbox's network policy. For another port: sbx policy allow network host.docker.internal:<port>.
Publishing a version
Publishing is a manual step, from a machine with Docker Desktop (buildx and the sbx CLI); the Release workflow builds only the binaries. One script builds the image for linux/amd64 and linux/arm64, pushes it, then validates and pushes the two kits, all at mm's tag:
export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
./docker-sbx/publish.sh # TAG from release.env: v0.0.3 → k33g/mm-sandbox:0.0.3, k33g/mm-tui:0.0.3, k33g/mm-acp:0.0.3
With both variables set, the script logs in with them and logs out when it is done; with neither, it reuses your existing docker login. Its two halves run alone as PUSH=1 ./docker-sbx/build.sh v0.0.3 (image) and ./docker-sbx/push-kits.sh v0.0.3 (kits, SBX=/path/to/sbx if the CLI is not on the PATH). Both call sync-kits.sh first, which rewrites the kits' version, default tag and image owner, so a published kit always names the image pushed with it — commit the two spec.yaml afterwards. sbx kit push talks to the registry directly and authenticates from the Docker credential store, no sandbox daemon involved. IMAGE_OWNER=<handle> publishes under another account.
Variants
- Another configuration for one editor session. Add
"-e", "AGENT_CONFIG=agent.lsp.yaml"before the sandbox name in"args";sbx exec -eoverrides the baked-in value for that run only. - Skills.
skillsDiris relative to the directorymmruns in, which is the workspace in both kits — the same rule as on the host. - Docker inside the sandbox. Build the template on the Docker-in-Docker shell instead:
SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx/build.sh. - Read the logs. In the window mode they are on screen; over ACP they go to stderr, which Zed shows under
dev: open acp logs. - Remove a sandbox.
sbx rm mm-acp. The project directory is a bind mount and is not touched.
See also
- The kit format these two files follow: the Docker Sandboxes kit specification (
schemaVersion: "2"), bundled with thesbxsources. - What
mm -acpexposes to the editor: ACP reference. - The flags and environment variables
mmreads: command line reference.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
|