bots-garden/mini-mepublic Fork
⑂ fead47a
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

🛟 Updated.

k33g committed 2026-09-21T23:30:14+02:00 Browse files
fead47a parent: c26f9e8
added .dockerignore +19 -0
new file mode 100644
@@ -0,0 +1,19 @@
1+# Build context of docker-sbx/template/Dockerfile (run from the repository
2+# root). Everything `go build .` does not need stays out, so the context is a
3+# few megabytes rather than the sandboxes/ checkout and the release binaries.
4+.git
5+sandboxes
6+release
7+tmp
8+kits
9+ebook
10+blog
11+mm
12+.mm
13+**/.mm
14+.memory
15+.quality
16+.qlty
17+notes.txt
18+*.env
19+*.tar
new file mode 100644
@@ -0,0 +1,19 @@
1+# Build context of docker-sbx/template/Dockerfile (run from the repository
2+# root). Everything `go build .` does not need stays out, so the context is a
3+# few megabytes rather than the sandboxes/ checkout and the release binaries.
4+.git
5+sandboxes
6+release
7+tmp
8+kits
9+ebook
10+blog
11+mm
12+.mm
13+**/.mm
14+.memory
15+.quality
16+.qlty
17+notes.txt
18+*.env
19+*.tar
modified .github/workflows/release.yml +64 -0
@@ -97,3 +97,67 @@ jobs:
9797 release/${{ github.ref_name }}/SHA256SUMS
9898 release/${{ github.ref_name }}/README.md
9999 fail_on_unmatched_files: true
100+
101+ # The Docker Sandbox template and its two kits, on Docker Hub, at the same
102+ # version as the binaries: k33g/mm-sandbox:0.0.2 (the image, linux/amd64 +
103+ # linux/arm64), k33g/mm-tui:0.0.2 and k33g/mm-acp:0.0.2 (the kits, OCI
104+ # artifacts). The scripts are the ones a laptop runs — docker-sbx/build.sh
105+ # with PUSH=1, then docker-sbx/push-kits.sh — so a local publish and a CI
106+ # publish are the same pipeline. Runs after `release` so nothing is pushed
107+ # to the Hub when the tests failed.
108+ #
109+ # Credentials: two repository secrets, DOCKER_HANDLE (the Docker Hub
110+ # account, which is also the image owner) and DOCKER_PAT (an access token
111+ # with read/write scope), exposed to the job as environment variables.
112+ docker-sandbox:
113+ name: publish the Docker Sandbox template and kits ${{ github.ref_name }}
114+ runs-on: ubuntu-latest
115+ needs: release
116+ env:
117+ DOCKER_HANDLE: ${{ secrets.DOCKER_HANDLE }}
118+ DOCKER_PAT: ${{ secrets.DOCKER_PAT }}
119+ # The sbx release whose CLI publishes the kits (docker/sbx-releases).
120+ SBX_VERSION: v0.45.0
121+ steps:
122+ - name: Checkout
123+ uses: actions/checkout@v4
124+
125+ - name: Check the Docker Hub credentials are set
126+ run: |
127+ set -euo pipefail
128+ if [ -z "${DOCKER_HANDLE}" ] || [ -z "${DOCKER_PAT}" ]; then
129+ echo "❌ DOCKER_HANDLE and DOCKER_PAT must be set as repository secrets"
130+ exit 1
131+ fi
132+
133+ - name: Set up QEMU
134+ # The final image stage runs `mm --version` for linux/arm64 on an
135+ # amd64 runner; the Go stage itself cross-compiles without emulation.
136+ uses: docker/setup-qemu-action@v3
137+
138+ - name: Set up Docker Buildx
139+ uses: docker/setup-buildx-action@v3
140+
141+ - name: Log in to Docker Hub
142+ run: printf '%s' "${DOCKER_PAT}" | docker login --username "${DOCKER_HANDLE}" --password-stdin
143+
144+ - name: Build and push the template image
145+ run: PUSH=1 IMAGE_OWNER="${DOCKER_HANDLE}" bash ./docker-sbx/build.sh "${GITHUB_REF_NAME}"
146+
147+ - name: Install the sbx CLI
148+ # `sbx kit push` talks to the registry directly and reads the Docker
149+ # credential store; no sandbox daemon is started here.
150+ run: |
151+ set -euo pipefail
152+ mkdir -p "${RUNNER_TEMP}/sbx"
153+ curl -fsSL -o "${RUNNER_TEMP}/sbx.tgz" \
154+ "https://github.com/docker/sbx-releases/releases/download/${SBX_VERSION}/DockerSandboxes-linux-amd64.tar.gz"
155+ tar -xzf "${RUNNER_TEMP}/sbx.tgz" -C "${RUNNER_TEMP}/sbx" --strip-components=1 docker-sbx/sbx
156+ "${RUNNER_TEMP}/sbx/sbx" version
157+
158+ - name: Publish the kits
159+ run: IMAGE_OWNER="${DOCKER_HANDLE}" SBX="${RUNNER_TEMP}/sbx/sbx" bash ./docker-sbx/push-kits.sh "${GITHUB_REF_NAME}"
160+
161+ - name: Log out of Docker Hub
162+ if: always()
163+ run: docker logout || true
@@ -97,3 +97,67 @@ jobs:
97 release/${{ github.ref_name }}/SHA256SUMS97 release/${{ github.ref_name }}/SHA256SUMS
98 release/${{ github.ref_name }}/README.md98 release/${{ github.ref_name }}/README.md
99 fail_on_unmatched_files: true99 fail_on_unmatched_files: true
100+
101+ # The Docker Sandbox template and its two kits, on Docker Hub, at the same
102+ # version as the binaries: k33g/mm-sandbox:0.0.2 (the image, linux/amd64 +
103+ # linux/arm64), k33g/mm-tui:0.0.2 and k33g/mm-acp:0.0.2 (the kits, OCI
104+ # artifacts). The scripts are the ones a laptop runs — docker-sbx/build.sh
105+ # with PUSH=1, then docker-sbx/push-kits.sh — so a local publish and a CI
106+ # publish are the same pipeline. Runs after `release` so nothing is pushed
107+ # to the Hub when the tests failed.
108+ #
109+ # Credentials: two repository secrets, DOCKER_HANDLE (the Docker Hub
110+ # account, which is also the image owner) and DOCKER_PAT (an access token
111+ # with read/write scope), exposed to the job as environment variables.
112+ docker-sandbox:
113+ name: publish the Docker Sandbox template and kits ${{ github.ref_name }}
114+ runs-on: ubuntu-latest
115+ needs: release
116+ env:
117+ DOCKER_HANDLE: ${{ secrets.DOCKER_HANDLE }}
118+ DOCKER_PAT: ${{ secrets.DOCKER_PAT }}
119+ # The sbx release whose CLI publishes the kits (docker/sbx-releases).
120+ SBX_VERSION: v0.45.0
121+ steps:
122+ - name: Checkout
123+ uses: actions/checkout@v4
124+
125+ - name: Check the Docker Hub credentials are set
126+ run: |
127+ set -euo pipefail
128+ if [ -z "${DOCKER_HANDLE}" ] || [ -z "${DOCKER_PAT}" ]; then
129+ echo "❌ DOCKER_HANDLE and DOCKER_PAT must be set as repository secrets"
130+ exit 1
131+ fi
132+
133+ - name: Set up QEMU
134+ # The final image stage runs `mm --version` for linux/arm64 on an
135+ # amd64 runner; the Go stage itself cross-compiles without emulation.
136+ uses: docker/setup-qemu-action@v3
137+
138+ - name: Set up Docker Buildx
139+ uses: docker/setup-buildx-action@v3
140+
141+ - name: Log in to Docker Hub
142+ run: printf '%s' "${DOCKER_PAT}" | docker login --username "${DOCKER_HANDLE}" --password-stdin
143+
144+ - name: Build and push the template image
145+ run: PUSH=1 IMAGE_OWNER="${DOCKER_HANDLE}" bash ./docker-sbx/build.sh "${GITHUB_REF_NAME}"
146+
147+ - name: Install the sbx CLI
148+ # `sbx kit push` talks to the registry directly and reads the Docker
149+ # credential store; no sandbox daemon is started here.
150+ run: |
151+ set -euo pipefail
152+ mkdir -p "${RUNNER_TEMP}/sbx"
153+ curl -fsSL -o "${RUNNER_TEMP}/sbx.tgz" \
154+ "https://github.com/docker/sbx-releases/releases/download/${SBX_VERSION}/DockerSandboxes-linux-amd64.tar.gz"
155+ tar -xzf "${RUNNER_TEMP}/sbx.tgz" -C "${RUNNER_TEMP}/sbx" --strip-components=1 docker-sbx/sbx
156+ "${RUNNER_TEMP}/sbx/sbx" version
157+
158+ - name: Publish the kits
159+ run: IMAGE_OWNER="${DOCKER_HANDLE}" SBX="${RUNNER_TEMP}/sbx/sbx" bash ./docker-sbx/push-kits.sh "${GITHUB_REF_NAME}"
160+
161+ - name: Log out of Docker Hub
162+ if: always()
163+ run: docker logout || true
added docker-sbx/README.md +197 -0
new file mode 100644
@@ -0,0 +1,197 @@
1+# mm in a Docker Sandbox
2+
3+Everything needed to run `mm` inside a [Docker Sandbox](https://docs.docker.com/ai/sandboxes/): a **template** (the `shell` sandbox image with `mm` installed) and two **kits** that start it — one for the window mode in your terminal, one for an editor that speaks the Agent Client Protocol.
4+
5+The full guide, with the reasoning, is in [`docs/en/how-to/run-in-a-docker-sandbox.md`](../docs/en/how-to/run-in-a-docker-sandbox.md) ([français](../docs/fr/how-to/run-in-a-docker-sandbox.md)). This page is the short version.
6+
7+```
8+docker-sbx/
9+├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)
10+├── sync-kits.sh points the kits at one image: owner + version
11+├── push-kits.sh publishes the kits to Docker Hub as OCI artifacts (sbx kit push)
12+├── template/
13+│ ├── Dockerfile docker/sandbox-templates:shell + mm (built from this checkout)
14+│ ├── mm-tui entry point of the mm-tui kit: `mm -tui "$@"`
15+│ └── mm-acp-info entry point of the mm-acp kit: prints the editor wiring, opens a shell
16+└── kits/
17+ ├── mm-tui/spec.yaml kind: sandbox — `sbx run` opens mm's window on the workspace
18+ └── mm-acp/spec.yaml kind: sandbox — `sbx create` once, the editor runs `sbx exec -i … mm -acp`
19+```
20+
21+## 0. Use the published kits (no build)
22+
23+Every release publishes the image and the two kits to Docker Hub at mm's version:
24+
25+| On Docker Hub | What it is |
26+|---|---|
27+| `k33g/mm-sandbox:0.0.2` | The template image. You never name it yourself: each kit pulls it. |
28+| `k33g/mm-tui:0.0.2` | The window-mode kit, for `sbx run`. |
29+| `k33g/mm-acp:0.0.2` | The editor kit, for `sbx create` + `sbx exec -i … mm -acp`. |
30+
31+Nothing to build, no `--pull never`, and no setting to change: Docker Hub is an allowed kit source out of the box (`sbx settings get kit.allowedSources` shows `docker.io/`), and a reference with a `/` but no registry host is read as `docker.io/…`. Only Docker Desktop with the `sbx` command, and a model server on your machine, are needed.
32+
33+**Look before you run.** `sbx kit inspect` reads the kit from the Hub without creating anything: its image, its entry point, its arguments and their defaults, the ports it allows.
34+
35+```bash
36+sbx kit inspect k33g/mm-tui:0.0.2
37+```
38+
39+**Window mode.** From the project you want mm to work on:
40+
41+```bash
42+cd /path/to/your/project
43+sbx run k33g/mm-tui:0.0.2 . -- agent.dmr.yaml
44+```
45+
46+The first run pulls the kit and the image, creates the sandbox `mm-tui-<directory>`, mounts the current directory as its workspace and opens `mm -tui agent.dmr.yaml` in it. What follows `--` is mm's own command line, so `-- -config other.yaml` works too. Without anything after `--`, mm reads the kit's `config` argument, then `./agent.yaml` in the workspace:
47+
48+```bash
49+sbx run k33g/mm-tui:0.0.2 . --kit-arg config=agent.dmr.yaml
50+```
51+
52+Later, `sbx run --name mm-tui-<directory>` re-attaches to that sandbox; `sbx ls` lists them.
53+
54+**From an editor.** Create the sandbox once, from the project the editor will open, with the configuration file baked in:
55+
56+```bash
57+cd /path/to/your/project
58+sbx create --name mm-acp k33g/mm-acp:0.0.2 . --kit-arg config=agent.dmr.yaml
59+```
60+
61+then register it in the editor — in Zed's `settings.json`:
62+
63+```json
64+{
65+ "agent_servers": {
66+ "mini-me (sandbox)": {
67+ "type": "custom",
68+ "command": "sbx",
69+ "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
70+ }
71+ }
72+}
73+```
74+
75+The editor starts `mm -acp` inside the sandbox for every conversation; `sbx exec` starts the sandbox first when it is stopped, and runs mm in the workspace with the baked-in `AGENT_CONFIG`. One sandbox per project, each with its own `--name` and its own editor entry. Section 3 has the details (another config for one session, where the logs are, why `sbx exec -i` and not `sbx run`).
76+
77+**Kit arguments.** Both kits take the same two, passed with `--kit-arg name=value` (repeatable) to `sbx run` or `sbx create`:
78+
79+| `--kit-arg` | Default | Effect |
80+|---|---|---|
81+| `config=<path>` | empty | The file mm reads (its `AGENT_CONFIG`): relative to the workspace, or absolute inside the sandbox. Empty: `./agent.yaml`, then the built-in defaults. |
82+| `tag=<version>` | the kit's own version (`0.0.2`) | Which `k33g/mm-sandbox:<version>` image to use. Normally left alone: a kit and its image share a version. |
83+
84+**Other versions.** Replace `0.0.2` with the release you want, in the kit reference only — the kit brings the matching image. A kit can also be pinned by digest, `k33g/mm-tui@sha256:…`, the digest being what `sbx kit inspect` or the Hub page shows.
85+
86+**If sbx refuses the source.** A message like `its source is not in your allowlist` means `kit.allowedSources` was narrowed on this machine; `sbx settings set kit.allowedSources '["docker.io/"]'` restores the default, or add `docker.io/k33g/` to your list.
87+
88+Sections 1–3 are the same flow with a template and kits built locally, for a work-in-progress mm.
89+
90+## 1. Build the template
91+
92+From the repository root:
93+
94+```bash
95+./docker-sbx/build.sh # TAG from release.env: v0.0.2 → k33g/mm-sandbox:0.0.2
96+./docker-sbx/build.sh v0.0.3 # → k33g/mm-sandbox:0.0.3
97+```
98+
99+The image tag is mm's tag without the `v`, the same rule as the release assets, and the script rewrites the kits' default `tag` argument to the version it built, so the kits always name the image just built. The image lands in the local Docker image store: every `sbx run` / `sbx create` below carries `--pull never` until you `docker push k33g/mm-sandbox:0.0.2`. If `sbx` runs on another machine, `EXPORT=1 ./docker-sbx/build.sh` also writes `tmp/mm-sandbox-<version>.tar`; load it there with `sbx template load`.
100+
101+## 2. Window mode in the terminal — kit `mm-tui`
102+
103+From the project you want `mm` to work on:
104+
105+```bash
106+sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
107+```
108+
109+What follows `--` reaches `mm` as its own arguments, so this runs `mm -tui agent.dmr.yaml` in the workspace. Any `mm` flag passes through the same way (`-- -config other.yaml`). Two kit arguments exist as well:
110+
111+| `--kit-arg` | Default | Effect |
112+|---|---|---|
113+| `config=<path>` | empty | The file `mm` reads when nothing follows `--` (its `AGENT_CONFIG`). Relative to the workspace, or absolute. Empty: `./agent.yaml`, then the built-in defaults. |
114+| `tag=<version>` | the version last built (`0.0.2`) | Which `k33g/mm-sandbox:<version>` image to use. |
115+
116+`sbx run --name <name>` re-attaches to a sandbox that already exists. Sessions, when enabled in the YAML, are written under the workspace's `.mm/sessions`, which is your host directory.
117+
118+## 3. From an editor (ACP) — kit `mm-acp`
119+
120+Create the sandbox once, without attaching, **from the project the editor will open**. `.` is the workspace; sbx makes it absolute. A path that does not exist on your machine makes sbx ask "The selected workspace does not exist. Would you like to create it?" — answer `N` and fix the path. The kit path must be explicit: `./`, `../` or absolute.
121+
122+```bash
123+cd /path/to/your/project
124+sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . \
125+ --kit-arg config=agent.dmr.yaml
126+
127+# once the image is pushed (docker push k33g/mm-sandbox:0.0.2), --pull never is not needed:
128+sbx create --name mm-acp ./docker-sbx/kits/mm-acp . \
129+ --kit-arg config=agent.dmr.yaml
130+```
131+
132+Then register it in the editor. In Zed's `settings.json`:
133+
134+```json
135+{
136+ "agent_servers": {
137+ "📦 mini-me (dmr sbx)": {
138+ "type": "custom",
139+ "command": "sbx",
140+ "args": ["exec", "-i", "mm-acp", "mm", "-acp"],
141+ },
142+ }
143+}
144+```
145+
146+Or:
147+
148+```bash
149+sbx create --pull never --name mm-acp-2 ./docker-sbx/kits/mm-acp .
150+```
151+
152+And:
153+
154+```json
155+{
156+ "agent_servers": {
157+ "😄 mini-me (dmr sbx)": {
158+ "type": "custom",
159+ "command": "sbx",
160+ "args": ["exec", "-i", "mm-acp-2", "mm", "-acp"],
161+ "env": { "AGENT_CONFIG": "/Users/k33g/kDrive/Rickub/bots-garden/mini-me/demo/agent.dmr.yaml" }
162+ },
163+ }
164+}
165+```
166+
167+
168+
169+The editor starts `mm -acp` inside the sandbox for every conversation; `sbx exec` starts the sandbox first when it is stopped, and runs `mm` in the workspace with the `AGENT_CONFIG` baked in by `--kit-arg config`. Everything the model does — commands, file edits — happens inside the sandbox, on the mounted project.
170+
171+Why `sbx exec -i` and not `sbx run`: an ACP client speaks JSON-RPC on the agent's raw stdin/stdout, and `sbx run` always allocates a terminal. Attaching to this sandbox with `sbx run --name mm-acp` is still useful: its entry point prints the wiring above with the sandbox's real name, then opens a shell.
172+
173+- One sandbox per project: the workspace is fixed at creation. Give each one its own `--name` and its own entry in the editor.
174+- Another configuration file for one session: `"args": ["exec", "-i", "-e", "AGENT_CONFIG=agent.lsp.yaml", "mm-acp", "mm", "-acp"]`.
175+- `sbx` not found by the editor: use the absolute path printed by `which sbx` as `"command"`.
176+- Logs: in Zed, `dev: open acp logs` shows `mm`'s banner, warnings and `[acp] …` trail.
177+
178+## 4. Publishing a version
179+
180+The Release workflow (`.github/workflows/release.yml`, job `docker-sandbox`) does this on every `v*` tag, after the binaries: it reads two repository secrets, `DOCKER_HANDLE` (the Docker Hub account, also the image owner) and `DOCKER_PAT` (an access token), logs in, then runs the same two scripts you can run from a laptop:
181+
182+```bash
183+docker login -u k33g # with an access token
184+PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, pushed as k33g/mm-sandbox:0.0.2
185+./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
186+```
187+
188+`push-kits.sh` needs the `sbx` CLI (the workflow downloads the Linux tarball from `docker/sbx-releases`); `sbx kit push` talks to the registry directly and authenticates from the Docker credential store, no sandbox daemon involved. Both scripts call `sync-kits.sh` first, so the published kits always name the image just pushed. `IMAGE_OWNER=<handle>` publishes under another account.
189+
190+## The model server stays on the host
191+
192+Inside a sandbox `localhost` is the sandbox itself. Docker Model Runner and llama-server keep running on your machine and are reached through `host.docker.internal`, which the sandbox proxy maps to your host's `localhost`:
193+
194+- `agent.dmr.yaml` already has `fallback: http://host.docker.internal:12434/engines/v1` — nothing to change.
195+- `agent.llamacpp.yaml` has no fallback: pass `--env AGENT_BASE_URL=http://host.docker.internal:8080/v1` to `sbx run` / `sbx create`, or edit its `baseUrl`.
196+
197+Both kits allow ports 12434 (Docker Model Runner) and 8080 (llama-server) on the host. Another port: `sbx policy allow network host.docker.internal:<port>`.
new file mode 100644
@@ -0,0 +1,197 @@
1+# mm in a Docker Sandbox
2+
3+Everything needed to run `mm` inside a [Docker Sandbox](https://docs.docker.com/ai/sandboxes/): a **template** (the `shell` sandbox image with `mm` installed) and two **kits** that start it — one for the window mode in your terminal, one for an editor that speaks the Agent Client Protocol.
4+
5+The full guide, with the reasoning, is in [`docs/en/how-to/run-in-a-docker-sandbox.md`](../docs/en/how-to/run-in-a-docker-sandbox.md) ([français](../docs/fr/how-to/run-in-a-docker-sandbox.md)). This page is the short version.
6+
7+```
8+docker-sbx/
9+├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)
10+├── sync-kits.sh points the kits at one image: owner + version
11+├── push-kits.sh publishes the kits to Docker Hub as OCI artifacts (sbx kit push)
12+├── template/
13+│ ├── Dockerfile docker/sandbox-templates:shell + mm (built from this checkout)
14+│ ├── mm-tui entry point of the mm-tui kit: `mm -tui "$@"`
15+│ └── mm-acp-info entry point of the mm-acp kit: prints the editor wiring, opens a shell
16+└── kits/
17+ ├── mm-tui/spec.yaml kind: sandbox — `sbx run` opens mm's window on the workspace
18+ └── mm-acp/spec.yaml kind: sandbox — `sbx create` once, the editor runs `sbx exec -i … mm -acp`
19+```
20+
21+## 0. Use the published kits (no build)
22+
23+Every release publishes the image and the two kits to Docker Hub at mm's version:
24+
25+| On Docker Hub | What it is |
26+|---|---|
27+| `k33g/mm-sandbox:0.0.2` | The template image. You never name it yourself: each kit pulls it. |
28+| `k33g/mm-tui:0.0.2` | The window-mode kit, for `sbx run`. |
29+| `k33g/mm-acp:0.0.2` | The editor kit, for `sbx create` + `sbx exec -i … mm -acp`. |
30+
31+Nothing to build, no `--pull never`, and no setting to change: Docker Hub is an allowed kit source out of the box (`sbx settings get kit.allowedSources` shows `docker.io/`), and a reference with a `/` but no registry host is read as `docker.io/…`. Only Docker Desktop with the `sbx` command, and a model server on your machine, are needed.
32+
33+**Look before you run.** `sbx kit inspect` reads the kit from the Hub without creating anything: its image, its entry point, its arguments and their defaults, the ports it allows.
34+
35+```bash
36+sbx kit inspect k33g/mm-tui:0.0.2
37+```
38+
39+**Window mode.** From the project you want mm to work on:
40+
41+```bash
42+cd /path/to/your/project
43+sbx run k33g/mm-tui:0.0.2 . -- agent.dmr.yaml
44+```
45+
46+The first run pulls the kit and the image, creates the sandbox `mm-tui-<directory>`, mounts the current directory as its workspace and opens `mm -tui agent.dmr.yaml` in it. What follows `--` is mm's own command line, so `-- -config other.yaml` works too. Without anything after `--`, mm reads the kit's `config` argument, then `./agent.yaml` in the workspace:
47+
48+```bash
49+sbx run k33g/mm-tui:0.0.2 . --kit-arg config=agent.dmr.yaml
50+```
51+
52+Later, `sbx run --name mm-tui-<directory>` re-attaches to that sandbox; `sbx ls` lists them.
53+
54+**From an editor.** Create the sandbox once, from the project the editor will open, with the configuration file baked in:
55+
56+```bash
57+cd /path/to/your/project
58+sbx create --name mm-acp k33g/mm-acp:0.0.2 . --kit-arg config=agent.dmr.yaml
59+```
60+
61+then register it in the editor — in Zed's `settings.json`:
62+
63+```json
64+{
65+ "agent_servers": {
66+ "mini-me (sandbox)": {
67+ "type": "custom",
68+ "command": "sbx",
69+ "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
70+ }
71+ }
72+}
73+```
74+
75+The editor starts `mm -acp` inside the sandbox for every conversation; `sbx exec` starts the sandbox first when it is stopped, and runs mm in the workspace with the baked-in `AGENT_CONFIG`. One sandbox per project, each with its own `--name` and its own editor entry. Section 3 has the details (another config for one session, where the logs are, why `sbx exec -i` and not `sbx run`).
76+
77+**Kit arguments.** Both kits take the same two, passed with `--kit-arg name=value` (repeatable) to `sbx run` or `sbx create`:
78+
79+| `--kit-arg` | Default | Effect |
80+|---|---|---|
81+| `config=<path>` | empty | The file mm reads (its `AGENT_CONFIG`): relative to the workspace, or absolute inside the sandbox. Empty: `./agent.yaml`, then the built-in defaults. |
82+| `tag=<version>` | the kit's own version (`0.0.2`) | Which `k33g/mm-sandbox:<version>` image to use. Normally left alone: a kit and its image share a version. |
83+
84+**Other versions.** Replace `0.0.2` with the release you want, in the kit reference only — the kit brings the matching image. A kit can also be pinned by digest, `k33g/mm-tui@sha256:…`, the digest being what `sbx kit inspect` or the Hub page shows.
85+
86+**If sbx refuses the source.** A message like `its source is not in your allowlist` means `kit.allowedSources` was narrowed on this machine; `sbx settings set kit.allowedSources '["docker.io/"]'` restores the default, or add `docker.io/k33g/` to your list.
87+
88+Sections 1–3 are the same flow with a template and kits built locally, for a work-in-progress mm.
89+
90+## 1. Build the template
91+
92+From the repository root:
93+
94+```bash
95+./docker-sbx/build.sh # TAG from release.env: v0.0.2 → k33g/mm-sandbox:0.0.2
96+./docker-sbx/build.sh v0.0.3 # → k33g/mm-sandbox:0.0.3
97+```
98+
99+The image tag is mm's tag without the `v`, the same rule as the release assets, and the script rewrites the kits' default `tag` argument to the version it built, so the kits always name the image just built. The image lands in the local Docker image store: every `sbx run` / `sbx create` below carries `--pull never` until you `docker push k33g/mm-sandbox:0.0.2`. If `sbx` runs on another machine, `EXPORT=1 ./docker-sbx/build.sh` also writes `tmp/mm-sandbox-<version>.tar`; load it there with `sbx template load`.
100+
101+## 2. Window mode in the terminal — kit `mm-tui`
102+
103+From the project you want `mm` to work on:
104+
105+```bash
106+sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
107+```
108+
109+What follows `--` reaches `mm` as its own arguments, so this runs `mm -tui agent.dmr.yaml` in the workspace. Any `mm` flag passes through the same way (`-- -config other.yaml`). Two kit arguments exist as well:
110+
111+| `--kit-arg` | Default | Effect |
112+|---|---|---|
113+| `config=<path>` | empty | The file `mm` reads when nothing follows `--` (its `AGENT_CONFIG`). Relative to the workspace, or absolute. Empty: `./agent.yaml`, then the built-in defaults. |
114+| `tag=<version>` | the version last built (`0.0.2`) | Which `k33g/mm-sandbox:<version>` image to use. |
115+
116+`sbx run --name <name>` re-attaches to a sandbox that already exists. Sessions, when enabled in the YAML, are written under the workspace's `.mm/sessions`, which is your host directory.
117+
118+## 3. From an editor (ACP) — kit `mm-acp`
119+
120+Create the sandbox once, without attaching, **from the project the editor will open**. `.` is the workspace; sbx makes it absolute. A path that does not exist on your machine makes sbx ask "The selected workspace does not exist. Would you like to create it?" — answer `N` and fix the path. The kit path must be explicit: `./`, `../` or absolute.
121+
122+```bash
123+cd /path/to/your/project
124+sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . \
125+ --kit-arg config=agent.dmr.yaml
126+
127+# once the image is pushed (docker push k33g/mm-sandbox:0.0.2), --pull never is not needed:
128+sbx create --name mm-acp ./docker-sbx/kits/mm-acp . \
129+ --kit-arg config=agent.dmr.yaml
130+```
131+
132+Then register it in the editor. In Zed's `settings.json`:
133+
134+```json
135+{
136+ "agent_servers": {
137+ "📦 mini-me (dmr sbx)": {
138+ "type": "custom",
139+ "command": "sbx",
140+ "args": ["exec", "-i", "mm-acp", "mm", "-acp"],
141+ },
142+ }
143+}
144+```
145+
146+Or:
147+
148+```bash
149+sbx create --pull never --name mm-acp-2 ./docker-sbx/kits/mm-acp .
150+```
151+
152+And:
153+
154+```json
155+{
156+ "agent_servers": {
157+ "😄 mini-me (dmr sbx)": {
158+ "type": "custom",
159+ "command": "sbx",
160+ "args": ["exec", "-i", "mm-acp-2", "mm", "-acp"],
161+ "env": { "AGENT_CONFIG": "/Users/k33g/kDrive/Rickub/bots-garden/mini-me/demo/agent.dmr.yaml" }
162+ },
163+ }
164+}
165+```
166+
167+
168+
169+The editor starts `mm -acp` inside the sandbox for every conversation; `sbx exec` starts the sandbox first when it is stopped, and runs `mm` in the workspace with the `AGENT_CONFIG` baked in by `--kit-arg config`. Everything the model does — commands, file edits — happens inside the sandbox, on the mounted project.
170+
171+Why `sbx exec -i` and not `sbx run`: an ACP client speaks JSON-RPC on the agent's raw stdin/stdout, and `sbx run` always allocates a terminal. Attaching to this sandbox with `sbx run --name mm-acp` is still useful: its entry point prints the wiring above with the sandbox's real name, then opens a shell.
172+
173+- One sandbox per project: the workspace is fixed at creation. Give each one its own `--name` and its own entry in the editor.
174+- Another configuration file for one session: `"args": ["exec", "-i", "-e", "AGENT_CONFIG=agent.lsp.yaml", "mm-acp", "mm", "-acp"]`.
175+- `sbx` not found by the editor: use the absolute path printed by `which sbx` as `"command"`.
176+- Logs: in Zed, `dev: open acp logs` shows `mm`'s banner, warnings and `[acp] …` trail.
177+
178+## 4. Publishing a version
179+
180+The Release workflow (`.github/workflows/release.yml`, job `docker-sandbox`) does this on every `v*` tag, after the binaries: it reads two repository secrets, `DOCKER_HANDLE` (the Docker Hub account, also the image owner) and `DOCKER_PAT` (an access token), logs in, then runs the same two scripts you can run from a laptop:
181+
182+```bash
183+docker login -u k33g # with an access token
184+PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, pushed as k33g/mm-sandbox:0.0.2
185+./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
186+```
187+
188+`push-kits.sh` needs the `sbx` CLI (the workflow downloads the Linux tarball from `docker/sbx-releases`); `sbx kit push` talks to the registry directly and authenticates from the Docker credential store, no sandbox daemon involved. Both scripts call `sync-kits.sh` first, so the published kits always name the image just pushed. `IMAGE_OWNER=<handle>` publishes under another account.
189+
190+## The model server stays on the host
191+
192+Inside a sandbox `localhost` is the sandbox itself. Docker Model Runner and llama-server keep running on your machine and are reached through `host.docker.internal`, which the sandbox proxy maps to your host's `localhost`:
193+
194+- `agent.dmr.yaml` already has `fallback: http://host.docker.internal:12434/engines/v1` — nothing to change.
195+- `agent.llamacpp.yaml` has no fallback: pass `--env AGENT_BASE_URL=http://host.docker.internal:8080/v1` to `sbx run` / `sbx create`, or edit its `baseUrl`.
196+
197+Both kits allow ports 12434 (Docker Model Runner) and 8080 (llama-server) on the host. Another port: `sbx policy allow network host.docker.internal:<port>`.
added docker-sbx/build.sh +105 -0
new file mode 100755
@@ -0,0 +1,105 @@
1+#!/usr/bin/env bash
2+# Build the mm sandbox template image, <owner>/mm-sandbox:<version>, from this
3+# checkout. The image tag follows mm's own tag, minus the "v": release.env
4+# says TAG="v0.0.2", the image is k33g/mm-sandbox:0.0.2 and `mm --version`
5+# inside it reports v0.0.2 — the same rule as the release assets.
6+#
7+# Usage:
8+# ./docker-sbx/build.sh # TAG from release.env, image for this machine
9+# ./docker-sbx/build.sh v0.0.3 # override the tag for this run (what CI does)
10+# PUSH=1 ./docker-sbx/build.sh # multi-arch (linux/amd64 + linux/arm64) built
11+# # with buildx and PUSHED to the registry —
12+# # needs `docker login`; this is the CI path
13+# IMAGE_OWNER=someone ./docker-sbx/build.sh # another image owner (default k33g)
14+# PLATFORMS=linux/amd64 PUSH=1 … # narrower multi-arch set
15+# SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx/build.sh
16+# # base it on the Docker-in-Docker shell
17+# EXPORT=1 ./docker-sbx/build.sh # also `docker save` to tmp/, for
18+# # `sbx template load` on another host
19+#
20+# Whatever the mode, the two kits under docker-sbx/kits/ are then pointed at
21+# the image just built (docker-sbx/sync-kits.sh), so kits and image move
22+# together. Publishing the kits themselves is docker-sbx/push-kits.sh.
23+set -euo pipefail
24+
25+cd "$(dirname "$0")/.."
26+
27+# release.env carries TAG ("v0.0.2"). It is git-ignored, so a checkout without
28+# it names the tag on the command line. A tag given on the command line wins.
29+if [ -f release.env ]; then
30+ # shellcheck source=/dev/null
31+ source release.env
32+fi
33+TAG="${1:-${TAG:-}}"
34+if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
35+ echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx/build.sh v1.2.3)"
36+ exit 1
37+fi
38+
39+# Not OWNER: release.env uses that name for the git owner (bots-garden), and
40+# the image owner is a different thing — the Docker Hub account, k33g.
41+IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
42+VERSION="${TAG#v}"
43+IMAGE="${IMAGE_OWNER}/mm-sandbox:${VERSION}"
44+PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
45+
46+build_args=(--build-arg "MM_VERSION=${TAG}")
47+if [ -n "${SHELL_TEMPLATE:-}" ]; then
48+ build_args+=(--build-arg "SHELL_TEMPLATE=${SHELL_TEMPLATE}")
49+fi
50+
51+if [ -n "${PUSH:-}" ]; then
52+ # Multi-arch needs buildx's container driver: the classic builder can
53+ # neither assemble a manifest list nor build for a foreign platform. The
54+ # Go stage cross-compiles on the build platform; only the final stage's
55+ # `RUN mm --version` runs under emulation (QEMU, set up by the caller).
56+ echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
57+ if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
58+ docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
59+ fi
60+ docker buildx build --builder mm-sandbox-builder \
61+ --platform "${PLATFORMS}" \
62+ -f docker-sbx/template/Dockerfile "${build_args[@]}" \
63+ -t "${IMAGE}" --push .
64+ # The proof that ships: the registry holds one manifest per platform.
65+ docker buildx imagetools inspect "${IMAGE}" | grep -E '^Name:|Platform:' | sed 's/^/ /'
66+else
67+ echo "🐳 Building ${IMAGE} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
68+ docker build -f docker-sbx/template/Dockerfile "${build_args[@]}" -t "${IMAGE}" .
69+
70+ # The one proof that what was built starts: --version needs no config and
71+ # no model server. It also confirms the stamp reached the binary.
72+ reported="$(docker run --rm "${IMAGE}" mm --version)"
73+ if ! grep -q -- "${TAG}" <<<"${reported}"; then
74+ echo "❌ the image does not report ${TAG}: ${reported}"
75+ exit 1
76+ fi
77+ echo "✅ ${reported}"
78+fi
79+
80+./docker-sbx/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
81+
82+if [ -n "${EXPORT:-}" ]; then
83+ mkdir -p tmp
84+ docker save -o "tmp/mm-sandbox-${VERSION}.tar" "${IMAGE}"
85+ echo "📦 tmp/mm-sandbox-${VERSION}.tar — load it where sbx runs with: sbx template load tmp/mm-sandbox-${VERSION}.tar"
86+fi
87+
88+if [ -n "${PUSH:-}" ]; then
89+ cat <<NEXT
90+
91+Image on the registry. Publish the kits next: ./docker-sbx/push-kits.sh ${TAG}
92+NEXT
93+else
94+ cat <<NEXT
95+
96+Next, from the project you want mm to work on:
97+
98+ window mode sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
99+ editor (ACP) sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . --kit-arg config=agent.dmr.yaml
100+ then register sbx exec -i mm-acp mm -acp in the editor (docker-sbx/README.md)
101+
102+ --pull never because ${IMAGE} exists only in the local image store;
103+ after \`docker push ${IMAGE}\` (or PUSH=1) it is no longer needed.
104+NEXT
105+fi
new file mode 100755
@@ -0,0 +1,105 @@
1+#!/usr/bin/env bash
2+# Build the mm sandbox template image, <owner>/mm-sandbox:<version>, from this
3+# checkout. The image tag follows mm's own tag, minus the "v": release.env
4+# says TAG="v0.0.2", the image is k33g/mm-sandbox:0.0.2 and `mm --version`
5+# inside it reports v0.0.2 — the same rule as the release assets.
6+#
7+# Usage:
8+# ./docker-sbx/build.sh # TAG from release.env, image for this machine
9+# ./docker-sbx/build.sh v0.0.3 # override the tag for this run (what CI does)
10+# PUSH=1 ./docker-sbx/build.sh # multi-arch (linux/amd64 + linux/arm64) built
11+# # with buildx and PUSHED to the registry —
12+# # needs `docker login`; this is the CI path
13+# IMAGE_OWNER=someone ./docker-sbx/build.sh # another image owner (default k33g)
14+# PLATFORMS=linux/amd64 PUSH=1 … # narrower multi-arch set
15+# SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx/build.sh
16+# # base it on the Docker-in-Docker shell
17+# EXPORT=1 ./docker-sbx/build.sh # also `docker save` to tmp/, for
18+# # `sbx template load` on another host
19+#
20+# Whatever the mode, the two kits under docker-sbx/kits/ are then pointed at
21+# the image just built (docker-sbx/sync-kits.sh), so kits and image move
22+# together. Publishing the kits themselves is docker-sbx/push-kits.sh.
23+set -euo pipefail
24+
25+cd "$(dirname "$0")/.."
26+
27+# release.env carries TAG ("v0.0.2"). It is git-ignored, so a checkout without
28+# it names the tag on the command line. A tag given on the command line wins.
29+if [ -f release.env ]; then
30+ # shellcheck source=/dev/null
31+ source release.env
32+fi
33+TAG="${1:-${TAG:-}}"
34+if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
35+ echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx/build.sh v1.2.3)"
36+ exit 1
37+fi
38+
39+# Not OWNER: release.env uses that name for the git owner (bots-garden), and
40+# the image owner is a different thing — the Docker Hub account, k33g.
41+IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
42+VERSION="${TAG#v}"
43+IMAGE="${IMAGE_OWNER}/mm-sandbox:${VERSION}"
44+PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
45+
46+build_args=(--build-arg "MM_VERSION=${TAG}")
47+if [ -n "${SHELL_TEMPLATE:-}" ]; then
48+ build_args+=(--build-arg "SHELL_TEMPLATE=${SHELL_TEMPLATE}")
49+fi
50+
51+if [ -n "${PUSH:-}" ]; then
52+ # Multi-arch needs buildx's container driver: the classic builder can
53+ # neither assemble a manifest list nor build for a foreign platform. The
54+ # Go stage cross-compiles on the build platform; only the final stage's
55+ # `RUN mm --version` runs under emulation (QEMU, set up by the caller).
56+ echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
57+ if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
58+ docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
59+ fi
60+ docker buildx build --builder mm-sandbox-builder \
61+ --platform "${PLATFORMS}" \
62+ -f docker-sbx/template/Dockerfile "${build_args[@]}" \
63+ -t "${IMAGE}" --push .
64+ # The proof that ships: the registry holds one manifest per platform.
65+ docker buildx imagetools inspect "${IMAGE}" | grep -E '^Name:|Platform:' | sed 's/^/ /'
66+else
67+ echo "🐳 Building ${IMAGE} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
68+ docker build -f docker-sbx/template/Dockerfile "${build_args[@]}" -t "${IMAGE}" .
69+
70+ # The one proof that what was built starts: --version needs no config and
71+ # no model server. It also confirms the stamp reached the binary.
72+ reported="$(docker run --rm "${IMAGE}" mm --version)"
73+ if ! grep -q -- "${TAG}" <<<"${reported}"; then
74+ echo "❌ the image does not report ${TAG}: ${reported}"
75+ exit 1
76+ fi
77+ echo "✅ ${reported}"
78+fi
79+
80+./docker-sbx/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
81+
82+if [ -n "${EXPORT:-}" ]; then
83+ mkdir -p tmp
84+ docker save -o "tmp/mm-sandbox-${VERSION}.tar" "${IMAGE}"
85+ echo "📦 tmp/mm-sandbox-${VERSION}.tar — load it where sbx runs with: sbx template load tmp/mm-sandbox-${VERSION}.tar"
86+fi
87+
88+if [ -n "${PUSH:-}" ]; then
89+ cat <<NEXT
90+
91+Image on the registry. Publish the kits next: ./docker-sbx/push-kits.sh ${TAG}
92+NEXT
93+else
94+ cat <<NEXT
95+
96+Next, from the project you want mm to work on:
97+
98+ window mode sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
99+ editor (ACP) sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . --kit-arg config=agent.dmr.yaml
100+ then register sbx exec -i mm-acp mm -acp in the editor (docker-sbx/README.md)
101+
102+ --pull never because ${IMAGE} exists only in the local image store;
103+ after \`docker push ${IMAGE}\` (or PUSH=1) it is no longer needed.
104+NEXT
105+fi
added docker-sbx/push-kits.sh +59 -0
new file mode 100755
@@ -0,0 +1,59 @@
1+#!/usr/bin/env bash
2+# Publish the two kits to Docker Hub as OCI kit artifacts:
3+# <owner>/mm-tui:<version> and <owner>/mm-acp:<version>
4+#
5+# Usage:
6+# ./docker-sbx/push-kits.sh # TAG from release.env
7+# ./docker-sbx/push-kits.sh v0.0.3 # override the tag (what CI does)
8+# IMAGE_OWNER=someone … # another owner (default k33g); the kits
9+# # are re-pointed at someone/mm-sandbox too
10+# REGISTRY=localhost:5000 … # another registry (default docker.io)
11+# SBX=/path/to/sbx … # the sbx binary, if not on the PATH
12+#
13+# Needs a login: `docker login -u <handle>` with a Docker Hub access token.
14+# `sbx kit push` talks to the registry directly — no sandbox daemon involved —
15+# and falls back to the Docker credential store for authentication.
16+#
17+# Push the image first (PUSH=1 ./docker-sbx/build.sh): a kit names
18+# <owner>/mm-sandbox:<version>, and sbx pulls that image when the kit is used.
19+set -euo pipefail
20+
21+cd "$(dirname "$0")/.."
22+
23+if [ -f release.env ]; then
24+ # shellcheck source=/dev/null
25+ source release.env
26+fi
27+TAG="${1:-${TAG:-}}"
28+if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
29+ echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx/push-kits.sh v1.2.3)"
30+ exit 1
31+fi
32+
33+IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
34+REGISTRY="${REGISTRY:-docker.io}"
35+VERSION="${TAG#v}"
36+SBX="${SBX:-sbx}"
37+
38+if ! command -v "${SBX}" >/dev/null 2>&1; then
39+ echo "❌ sbx not found (${SBX}). Install Docker Sandboxes, or SBX=/path/to/sbx"
40+ exit 1
41+fi
42+
43+./docker-sbx/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
44+
45+for dir in docker-sbx/kits/*/; do
46+ kit="$(basename "${dir}")"
47+ ref="${REGISTRY}/${IMAGE_OWNER}/${kit}:${VERSION}"
48+ "${SBX}" kit validate "${dir}"
49+ "${SBX}" kit push "${dir}" "${ref}"
50+done
51+
52+cat <<NEXT
53+
54+Published. From any machine with Docker Sandboxes (docker.io is an allowed kit source by default):
55+
56+ window mode sbx run ${IMAGE_OWNER}/mm-tui:${VERSION} . -- agent.dmr.yaml
57+ editor (ACP) sbx create --name mm-acp ${IMAGE_OWNER}/mm-acp:${VERSION} . --kit-arg config=agent.dmr.yaml
58+ then register sbx exec -i mm-acp mm -acp in the editor
59+NEXT
new file mode 100755
@@ -0,0 +1,59 @@
1+#!/usr/bin/env bash
2+# Publish the two kits to Docker Hub as OCI kit artifacts:
3+# <owner>/mm-tui:<version> and <owner>/mm-acp:<version>
4+#
5+# Usage:
6+# ./docker-sbx/push-kits.sh # TAG from release.env
7+# ./docker-sbx/push-kits.sh v0.0.3 # override the tag (what CI does)
8+# IMAGE_OWNER=someone … # another owner (default k33g); the kits
9+# # are re-pointed at someone/mm-sandbox too
10+# REGISTRY=localhost:5000 … # another registry (default docker.io)
11+# SBX=/path/to/sbx … # the sbx binary, if not on the PATH
12+#
13+# Needs a login: `docker login -u <handle>` with a Docker Hub access token.
14+# `sbx kit push` talks to the registry directly — no sandbox daemon involved —
15+# and falls back to the Docker credential store for authentication.
16+#
17+# Push the image first (PUSH=1 ./docker-sbx/build.sh): a kit names
18+# <owner>/mm-sandbox:<version>, and sbx pulls that image when the kit is used.
19+set -euo pipefail
20+
21+cd "$(dirname "$0")/.."
22+
23+if [ -f release.env ]; then
24+ # shellcheck source=/dev/null
25+ source release.env
26+fi
27+TAG="${1:-${TAG:-}}"
28+if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
29+ echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx/push-kits.sh v1.2.3)"
30+ exit 1
31+fi
32+
33+IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
34+REGISTRY="${REGISTRY:-docker.io}"
35+VERSION="${TAG#v}"
36+SBX="${SBX:-sbx}"
37+
38+if ! command -v "${SBX}" >/dev/null 2>&1; then
39+ echo "❌ sbx not found (${SBX}). Install Docker Sandboxes, or SBX=/path/to/sbx"
40+ exit 1
41+fi
42+
43+./docker-sbx/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
44+
45+for dir in docker-sbx/kits/*/; do
46+ kit="$(basename "${dir}")"
47+ ref="${REGISTRY}/${IMAGE_OWNER}/${kit}:${VERSION}"
48+ "${SBX}" kit validate "${dir}"
49+ "${SBX}" kit push "${dir}" "${ref}"
50+done
51+
52+cat <<NEXT
53+
54+Published. From any machine with Docker Sandboxes (docker.io is an allowed kit source by default):
55+
56+ window mode sbx run ${IMAGE_OWNER}/mm-tui:${VERSION} . -- agent.dmr.yaml
57+ editor (ACP) sbx create --name mm-acp ${IMAGE_OWNER}/mm-acp:${VERSION} . --kit-arg config=agent.dmr.yaml
58+ then register sbx exec -i mm-acp mm -acp in the editor
59+NEXT
added docker-sbx/sync-kits.sh +37 -0
new file mode 100755
@@ -0,0 +1,37 @@
1+#!/usr/bin/env bash
2+# Point the two kits at one image: <owner>/mm-sandbox:<version>.
3+#
4+# Usage: ./docker-sbx/sync-kits.sh OWNER VERSION (e.g. k33g 0.0.2)
5+#
6+# Rewrites, in docker-sbx/kits/*/spec.yaml, only these three values:
7+# version: "<version>" the kit's own version
8+# args.tag.default: "<version>" which image tag the kit uses
9+# sandbox.image: "<owner>/mm-sandbox:…" which owner the image lives under
10+# Everything else — comments included — is left byte-for-byte alone, so a
11+# kit that already matches is not changed at all. build.sh and push-kits.sh
12+# call this; CI relies on it so the published kits name the image it pushed.
13+set -euo pipefail
14+
15+if [ $# -ne 2 ]; then
16+ echo "usage: $0 OWNER VERSION" >&2
17+ exit 2
18+fi
19+OWNER="$1"
20+VERSION="$2"
21+
22+cd "$(dirname "$0")/.."
23+
24+for kit in docker-sbx/kits/*/spec.yaml; do
25+ if ! grep -q '^ tag:$' "${kit}" || ! grep -q '^version: ' "${kit}" || ! grep -q '^ image: "' "${kit}"; then
26+ echo "❌ ${kit}: expected a top-level 'version:', an 'args.tag' and a quoted 'sandbox.image' — not updated" >&2
27+ exit 1
28+ fi
29+ # sed -i.bak works on both GNU and BSD sed; the backup is removed at once.
30+ sed -i.bak -E \
31+ -e "s|^(version: )\"[^\"]*\"|\1\"${VERSION}\"|" \
32+ -e "/^ tag:\$/,/^ default:/ s|^( default: )\"[^\"]*\"|\1\"${VERSION}\"|" \
33+ -e "s|^( image: \")[^/\"]+(/mm-sandbox:.*)|\1${OWNER}\2|" \
34+ "${kit}"
35+ rm -f "${kit}.bak"
36+ echo "✅ ${kit} → version \"${VERSION}\", tag default \"${VERSION}\", image ${OWNER}/mm-sandbox:\${{ kit.args.tag }}"
37+done
new file mode 100755
@@ -0,0 +1,37 @@
1+#!/usr/bin/env bash
2+# Point the two kits at one image: <owner>/mm-sandbox:<version>.
3+#
4+# Usage: ./docker-sbx/sync-kits.sh OWNER VERSION (e.g. k33g 0.0.2)
5+#
6+# Rewrites, in docker-sbx/kits/*/spec.yaml, only these three values:
7+# version: "<version>" the kit's own version
8+# args.tag.default: "<version>" which image tag the kit uses
9+# sandbox.image: "<owner>/mm-sandbox:…" which owner the image lives under
10+# Everything else — comments included — is left byte-for-byte alone, so a
11+# kit that already matches is not changed at all. build.sh and push-kits.sh
12+# call this; CI relies on it so the published kits name the image it pushed.
13+set -euo pipefail
14+
15+if [ $# -ne 2 ]; then
16+ echo "usage: $0 OWNER VERSION" >&2
17+ exit 2
18+fi
19+OWNER="$1"
20+VERSION="$2"
21+
22+cd "$(dirname "$0")/.."
23+
24+for kit in docker-sbx/kits/*/spec.yaml; do
25+ if ! grep -q '^ tag:$' "${kit}" || ! grep -q '^version: ' "${kit}" || ! grep -q '^ image: "' "${kit}"; then
26+ echo "❌ ${kit}: expected a top-level 'version:', an 'args.tag' and a quoted 'sandbox.image' — not updated" >&2
27+ exit 1
28+ fi
29+ # sed -i.bak works on both GNU and BSD sed; the backup is removed at once.
30+ sed -i.bak -E \
31+ -e "s|^(version: )\"[^\"]*\"|\1\"${VERSION}\"|" \
32+ -e "/^ tag:\$/,/^ default:/ s|^( default: )\"[^\"]*\"|\1\"${VERSION}\"|" \
33+ -e "s|^( image: \")[^/\"]+(/mm-sandbox:.*)|\1${OWNER}\2|" \
34+ "${kit}"
35+ rm -f "${kit}.bak"
36+ echo "✅ ${kit} → version \"${VERSION}\", tag default \"${VERSION}\", image ${OWNER}/mm-sandbox:\${{ kit.args.tag }}"
37+done
added docker-sbx/template/Dockerfile +53 -0
new file mode 100644
@@ -0,0 +1,53 @@
1+# syntax=docker/dockerfile:1
2+#
3+# The mm sandbox template: Docker Sandboxes' `shell` image with mm installed.
4+#
5+# Build it from the REPOSITORY ROOT (the context is the mm sources), or run
6+# docker-sbx/build.sh, which does exactly that and stamps mm's tag — the
7+# image tag is that tag without the "v", k33g/mm-sandbox:0.0.2 for v0.0.2:
8+#
9+# docker build -f docker-sbx/template/Dockerfile \
10+# --build-arg MM_VERSION=v0.0.2 -t k33g/mm-sandbox:0.0.2 .
11+#
12+# The two kits under docker-sbx/kits/ name this image.
13+# ENTRYPOINT and CMD are deliberately not set: the sandbox runtime keeps the
14+# shell template's tini entrypoint and replaces CMD with its own, and the kit's
15+# `sandbox.entrypoint` is what starts mm when you attach.
16+
17+ARG GO_VERSION=1.26
18+ARG SHELL_TEMPLATE=docker/sandbox-templates:shell
19+
20+# ---- build stage: cross-compile mm for the target platform -----------------
21+FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-bookworm AS build
22+ARG TARGETOS
23+ARG TARGETARCH
24+# What `mm --version` reports: the tag, as 02-build-releases.sh stamps it.
25+ARG MM_VERSION=dev
26+
27+WORKDIR /src
28+COPY go.mod go.sum ./
29+RUN --mount=type=cache,target=/go/pkg/mod go mod download
30+COPY . .
31+# Same flags as 02-build-releases.sh: no C, no local paths, no symbols, the
32+# version stamped into internal/version.
33+RUN --mount=type=cache,target=/go/pkg/mod \
34+ --mount=type=cache,target=/root/.cache/go-build \
35+ CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
36+ go build -trimpath -ldflags "-s -w -X mm/internal/version.stamped=${MM_VERSION}" -o /out/mm .
37+
38+# ---- template: the shell sandbox plus mm -----------------------------------
39+FROM ${SHELL_TEMPLATE}
40+
41+COPY --from=build --chmod=0755 /out/mm /usr/local/bin/mm
42+# The two kit entry points. mm-tui runs `mm -tui "$@"`; mm-acp-info prints how
43+# an editor reaches this sandbox and opens a shell (see docker-sbx/README.md).
44+COPY --chmod=0755 docker-sbx/template/mm-tui docker-sbx/template/mm-acp-info /usr/local/bin/
45+
46+# tcell (the window mode) needs a terminal type and a UTF-8 locale; the kits
47+# set them too, this is the fallback for a plain `docker run`.
48+ENV TERM=xterm-256color \
49+ COLORTERM=truecolor \
50+ LANG=C.UTF-8
51+
52+# Prove the binary runs on this platform before the image is tagged.
53+RUN mm --version && mm-tui --version
new file mode 100644
@@ -0,0 +1,53 @@
1+# syntax=docker/dockerfile:1
2+#
3+# The mm sandbox template: Docker Sandboxes' `shell` image with mm installed.
4+#
5+# Build it from the REPOSITORY ROOT (the context is the mm sources), or run
6+# docker-sbx/build.sh, which does exactly that and stamps mm's tag — the
7+# image tag is that tag without the "v", k33g/mm-sandbox:0.0.2 for v0.0.2:
8+#
9+# docker build -f docker-sbx/template/Dockerfile \
10+# --build-arg MM_VERSION=v0.0.2 -t k33g/mm-sandbox:0.0.2 .
11+#
12+# The two kits under docker-sbx/kits/ name this image.
13+# ENTRYPOINT and CMD are deliberately not set: the sandbox runtime keeps the
14+# shell template's tini entrypoint and replaces CMD with its own, and the kit's
15+# `sandbox.entrypoint` is what starts mm when you attach.
16+
17+ARG GO_VERSION=1.26
18+ARG SHELL_TEMPLATE=docker/sandbox-templates:shell
19+
20+# ---- build stage: cross-compile mm for the target platform -----------------
21+FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-bookworm AS build
22+ARG TARGETOS
23+ARG TARGETARCH
24+# What `mm --version` reports: the tag, as 02-build-releases.sh stamps it.
25+ARG MM_VERSION=dev
26+
27+WORKDIR /src
28+COPY go.mod go.sum ./
29+RUN --mount=type=cache,target=/go/pkg/mod go mod download
30+COPY . .
31+# Same flags as 02-build-releases.sh: no C, no local paths, no symbols, the
32+# version stamped into internal/version.
33+RUN --mount=type=cache,target=/go/pkg/mod \
34+ --mount=type=cache,target=/root/.cache/go-build \
35+ CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
36+ go build -trimpath -ldflags "-s -w -X mm/internal/version.stamped=${MM_VERSION}" -o /out/mm .
37+
38+# ---- template: the shell sandbox plus mm -----------------------------------
39+FROM ${SHELL_TEMPLATE}
40+
41+COPY --from=build --chmod=0755 /out/mm /usr/local/bin/mm
42+# The two kit entry points. mm-tui runs `mm -tui "$@"`; mm-acp-info prints how
43+# an editor reaches this sandbox and opens a shell (see docker-sbx/README.md).
44+COPY --chmod=0755 docker-sbx/template/mm-tui docker-sbx/template/mm-acp-info /usr/local/bin/
45+
46+# tcell (the window mode) needs a terminal type and a UTF-8 locale; the kits
47+# set them too, this is the fallback for a plain `docker run`.
48+ENV TERM=xterm-256color \
49+ COLORTERM=truecolor \
50+ LANG=C.UTF-8
51+
52+# Prove the binary runs on this platform before the image is tagged.
53+RUN mm --version && mm-tui --version
added docker-sbx/template/mm-acp-info +52 -0
new file mode 100755
@@ -0,0 +1,52 @@
1+#!/bin/bash
2+# Entry point of the mm-acp sandbox kit (docker-sbx/kits/mm-acp).
3+#
4+# An editor never runs this script. It reaches mm with
5+#
6+# sbx exec -i <sandbox> mm -acp
7+#
8+# because an ACP client needs raw stdin/stdout and `sbx run` always allocates
9+# a terminal. So attaching to this sandbox with `sbx run` prints the wiring
10+# for the editor, with this sandbox's real name and paths, then opens a shell.
11+set -u
12+
13+name="${SANDBOX_NAME:-$(hostname)}"
14+workspace="${WORKSPACE_DIR:-$PWD}"
15+config="${AGENT_CONFIG:-}"
16+if [ -z "$config" ]; then
17+ config_note="none set — mm reads ./agent.yaml in the workspace, then its built-in defaults"
18+elif [ "${config#/}" = "$config" ]; then
19+ config_note="$config (relative to the workspace: ${workspace%/}/$config)"
20+else
21+ config_note="$config"
22+fi
23+
24+cat <<INFO
25+
26+ mm $(mm --version 2>/dev/null | awk '{print $2}') in sandbox "$name"
27+ workspace : $workspace
28+ config : $config_note
29+
30+ This sandbox is meant for an editor (Agent Client Protocol). Register it in
31+ Zed's settings.json — the editor starts mm inside the sandbox on every
32+ conversation, and sbx starts the sandbox first when it is stopped:
33+
34+ {
35+ "agent_servers": {
36+ "mini-me (sandbox)": {
37+ "type": "custom",
38+ "command": "sbx",
39+ "args": ["exec", "-i", "$name", "mm", "-acp"]
40+ }
41+ }
42+ }
43+
44+ Use the absolute path of sbx as "command" if the editor cannot find it
45+ (\`which sbx\` on the host). To change the configuration file for one
46+ session, add "-e", "AGENT_CONFIG=/path/in/workspace/agent.yaml" before
47+ "$name" in "args". Full guide: docs/en/how-to/run-in-a-docker-sandbox.md
48+
49+ You are now in a shell inside the sandbox. \`mm agent.yaml\` works here too.
50+
51+INFO
52+exec bash -l
new file mode 100755
@@ -0,0 +1,52 @@
1+#!/bin/bash
2+# Entry point of the mm-acp sandbox kit (docker-sbx/kits/mm-acp).
3+#
4+# An editor never runs this script. It reaches mm with
5+#
6+# sbx exec -i <sandbox> mm -acp
7+#
8+# because an ACP client needs raw stdin/stdout and `sbx run` always allocates
9+# a terminal. So attaching to this sandbox with `sbx run` prints the wiring
10+# for the editor, with this sandbox's real name and paths, then opens a shell.
11+set -u
12+
13+name="${SANDBOX_NAME:-$(hostname)}"
14+workspace="${WORKSPACE_DIR:-$PWD}"
15+config="${AGENT_CONFIG:-}"
16+if [ -z "$config" ]; then
17+ config_note="none set — mm reads ./agent.yaml in the workspace, then its built-in defaults"
18+elif [ "${config#/}" = "$config" ]; then
19+ config_note="$config (relative to the workspace: ${workspace%/}/$config)"
20+else
21+ config_note="$config"
22+fi
23+
24+cat <<INFO
25+
26+ mm $(mm --version 2>/dev/null | awk '{print $2}') in sandbox "$name"
27+ workspace : $workspace
28+ config : $config_note
29+
30+ This sandbox is meant for an editor (Agent Client Protocol). Register it in
31+ Zed's settings.json — the editor starts mm inside the sandbox on every
32+ conversation, and sbx starts the sandbox first when it is stopped:
33+
34+ {
35+ "agent_servers": {
36+ "mini-me (sandbox)": {
37+ "type": "custom",
38+ "command": "sbx",
39+ "args": ["exec", "-i", "$name", "mm", "-acp"]
40+ }
41+ }
42+ }
43+
44+ Use the absolute path of sbx as "command" if the editor cannot find it
45+ (\`which sbx\` on the host). To change the configuration file for one
46+ session, add "-e", "AGENT_CONFIG=/path/in/workspace/agent.yaml" before
47+ "$name" in "args". Full guide: docs/en/how-to/run-in-a-docker-sandbox.md
48+
49+ You are now in a shell inside the sandbox. \`mm agent.yaml\` works here too.
50+
51+INFO
52+exec bash -l
added docker-sbx/template/mm-tui +11 -0
new file mode 100755
@@ -0,0 +1,11 @@
1+#!/bin/bash
2+# Entry point of the mm-tui sandbox kit (docker-sbx/kits/mm-tui).
3+#
4+# `sbx run` forwards whatever follows "--" as this script's arguments, so
5+#
6+# sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
7+#
8+# runs `mm -tui agent.dmr.yaml` in the workspace. Without an argument mm reads
9+# $AGENT_CONFIG (the kit's `config` argument), then ./agent.yaml, then its
10+# built-in defaults. Flags pass through too: `-- -config other.yaml`.
11+exec mm -tui "$@"
new file mode 100755
@@ -0,0 +1,11 @@
1+#!/bin/bash
2+# Entry point of the mm-tui sandbox kit (docker-sbx/kits/mm-tui).
3+#
4+# `sbx run` forwards whatever follows "--" as this script's arguments, so
5+#
6+# sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
7+#
8+# runs `mm -tui agent.dmr.yaml` in the workspace. Without an argument mm reads
9+# $AGENT_CONFIG (the kit's `config` argument), then ./agent.yaml, then its
10+# built-in defaults. Flags pass through too: `-- -config other.yaml`.
11+exec mm -tui "$@"
modified docs/en/README.md +1 -0
@@ -12,6 +12,7 @@ This documentation is organised along the four [Diátaxis](https://diataxis.fr)
1212
1313 - [Run mini-me on llama.cpp instead of Docker Model Runner](how-to/run-with-llama-cpp.md)
1414 - [Use mini-me from an editor (ACP)](how-to/use-from-an-editor.md)
15+- [Run mini-me in a Docker Sandbox](how-to/run-in-a-docker-sandbox.md) — the template and the two kits under `docker-sbx/`, window mode and editor
1516 - [Add a skill](how-to/add-a-skill.md)
1617 - [Measure whether the model picks the right skill](how-to/measure-skill-routing.md) — the routing eval: run it, read its table, use it as a before-and-after
1718 - [Keep a long session inside the context window](how-to/manage-the-context-window.md)
@@ -12,6 +12,7 @@ This documentation is organised along the four [Diátaxis](https://diataxis.fr)
12 12
13 - [Run mini-me on llama.cpp instead of Docker Model Runner](how-to/run-with-llama-cpp.md)13 - [Run mini-me on llama.cpp instead of Docker Model Runner](how-to/run-with-llama-cpp.md)
14 - [Use mini-me from an editor (ACP)](how-to/use-from-an-editor.md)14 - [Use mini-me from an editor (ACP)](how-to/use-from-an-editor.md)
15+- [Run mini-me in a Docker Sandbox](how-to/run-in-a-docker-sandbox.md) — the template and the two kits under `docker-sbx/`, window mode and editor
15 - [Add a skill](how-to/add-a-skill.md)16 - [Add a skill](how-to/add-a-skill.md)
16 - [Measure whether the model picks the right skill](how-to/measure-skill-routing.md) — the routing eval: run it, read its table, use it as a before-and-after17 - [Measure whether the model picks the right skill](how-to/measure-skill-routing.md) — the routing eval: run it, read its table, use it as a before-and-after
17 - [Keep a long session inside the context window](how-to/manage-the-context-window.md)18 - [Keep a long session inside the context window](how-to/manage-the-context-window.md)
added docs/en/how-to/run-in-a-docker-sandbox.md +138 -0
new file mode 100644
@@ -0,0 +1,138 @@
1+# How to run mini-me in a Docker Sandbox
2+
3+This guide shows how to run `mm` inside a [Docker Sandbox](https://docs.docker.com/ai/sandboxes/), 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.
4+
5+Everything lives under [`docker-sbx/`](../../../docker-sbx/README.md) in the repository:
6+
7+| Piece | What it is |
8+|---|---|
9+| `template/Dockerfile` | The **template**: Docker Sandboxes' `shell` image with `mm` built from this checkout, plus the two entry points below. |
10+| `kits/mm-tui/spec.yaml` | A **sandbox kit**: `sbx run` on it opens `mm`'s window mode on the workspace. |
11+| `kits/mm-acp/spec.yaml` | A **sandbox kit** for an editor: created once with `sbx create`, the editor then runs `mm -acp` inside it. |
12+| `build.sh` | Builds the template image, `k33g/mm-sandbox:<version>`; `PUSH=1` builds it for linux/amd64 and linux/arm64 and pushes it. |
13+| `sync-kits.sh`, `push-kits.sh` | Point the kits at one image, and publish them to Docker Hub as OCI kit artifacts. |
14+
15+## Use the published kits
16+
17+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/…`:
18+
19+```bash
20+cd /path/to/your/project
21+sbx run k33g/mm-tui:0.0.2 . -- agent.dmr.yaml
22+```
23+
24+for the window mode, and for an editor:
25+
26+```bash
27+sbx create --name mm-acp k33g/mm-acp:0.0.2 . --kit-arg config=agent.dmr.yaml
28+```
29+
30+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.
31+
32+## Steps
33+
34+### 1. Build the template
35+
36+From the repository root:
37+
38+```bash
39+./docker-sbx/build.sh
40+```
41+
42+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`.
43+
44+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`.
45+
46+### 2. Window mode in the terminal (kit `mm-tui`)
47+
48+From the project you want `mm` to work on:
49+
50+```bash
51+sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
52+```
53+
54+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`.
55+
56+Without anything after `--`, `mm` reads the kit's `config` argument, then `./agent.yaml` in the workspace, then its built-in defaults:
57+
58+```bash
59+sbx run --pull never ./docker-sbx/kits/mm-tui . --kit-arg config=agent.dmr.yaml
60+```
61+
62+| `--kit-arg` | Default | Effect |
63+|---|---|---|
64+| `config=<path>` | empty | The configuration file, as `mm`'s `AGENT_CONFIG`: relative to the workspace, or absolute inside the sandbox. |
65+| `tag=<version>` | the version last built (`0.0.2`) | Which `k33g/mm-sandbox:<version>` image the sandbox is made from. |
66+
67+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](use-the-window-mode.md). Sessions, when `sessions.enabled` is on, are written under the workspace's `.mm/sessions` — that is your host directory, so they survive the sandbox.
68+
69+### 3. From an editor (kit `mm-acp`)
70+
71+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.
72+
73+1. 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):
74+
75+ ```bash
76+ cd /path/to/your/project
77+ sbx create --pull never --name mm-acp /path/to/mini-me/docker-sbx/kits/mm-acp . \
78+ --kit-arg config=agent.dmr.yaml
79+ ```
80+
81+ A 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 `N` and fix the path.
82+
83+ `--kit-arg config` becomes the container's `AGENT_CONFIG`, relative to the workspace because that is where `sbx exec` starts `mm`. The workspace is fixed at creation: one sandbox per project, each with its own `--name`.
84+
85+2. Register it in the editor. In Zed's `settings.json`:
86+
87+ ```json
88+ {
89+ "agent_servers": {
90+ "mini-me (sandbox)": {
91+ "type": "custom",
92+ "command": "sbx",
93+ "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
94+ }
95+ }
96+ }
97+ ```
98+
99+ Compared with [the host-side setup](use-from-an-editor.md), the command is `sbx` and no `env` is needed: `AGENT_CONFIG` is already in the container. If the editor cannot find `sbx`, put the absolute path from `which sbx` in `"command"`.
100+
101+3. Open the agent panel and pick **mini-me (sandbox)**. The editor starts `mm -acp` in the sandbox for every conversation; `sbx exec` starts the sandbox first when it is stopped. Tool calls, permission dialogs, `@file` mentions and the slash-command menu work as they do on the host — the difference is where the commands run.
102+
103+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.
104+
105+## The model server stays on the host
106+
107+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`.
108+
109+- **Docker Model Runner** — nothing to change: `agent.dmr.yaml` already has `fallback: http://host.docker.internal:12434/engines/v1`, and `mm` switches to it when `localhost:12434` does not answer (the banner says which URL won).
110+- **llama-server** — `agent.llamacpp.yaml` has no fallback. Either edit its `baseUrl` to `http://host.docker.internal:8080/v1`, or pass `--env AGENT_BASE_URL=http://host.docker.internal:8080/v1` to `sbx run` / `sbx create` (see [Run with llama.cpp](run-with-llama-cpp.md)).
111+
112+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>`.
113+
114+## Publishing a version
115+
116+The Release workflow (`.github/workflows/release.yml`, job `docker-sandbox`) publishes the image and the kits on every `v*` tag, after the binaries job. It needs two repository secrets, exposed to the job as environment variables: `DOCKER_HANDLE`, the Docker Hub account (also the image owner), and `DOCKER_PAT`, an access token with read/write scope. It then runs the scripts a laptop would run:
117+
118+```bash
119+docker login -u k33g # paste an access token
120+PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, pushed as k33g/mm-sandbox:0.0.2
121+./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + sbx kit push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
122+```
123+
124+`push-kits.sh` needs the `sbx` CLI on the PATH (or `SBX=/path/to/sbx`; the workflow downloads the Linux tarball of `docker/sbx-releases`). `sbx kit push` talks to the registry directly and authenticates from the Docker credential store — no sandbox daemon is involved, which is what makes it usable in CI. Both scripts 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. `IMAGE_OWNER=<handle>` publishes under another account.
125+
126+## Variants
127+
128+- **Another configuration for one editor session.** Add `"-e", "AGENT_CONFIG=agent.lsp.yaml"` before the sandbox name in `"args"`; `sbx exec -e` overrides the baked-in value for that run only.
129+- **Skills.** `skillsDir` is relative to the directory `mm` runs in, which is the workspace in both kits — the same rule as on the host.
130+- **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`.
131+- **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`.
132+- **Remove a sandbox.** `sbx rm mm-acp`. The project directory is a bind mount and is not touched.
133+
134+## See also
135+
136+- The kit format these two files follow: the Docker Sandboxes kit specification (`schemaVersion: "2"`), bundled with the `sbx` sources.
137+- What `mm -acp` exposes to the editor: [ACP reference](../reference/acp.md).
138+- The flags and environment variables `mm` reads: [command line reference](../reference/cli.md).
new file mode 100644
@@ -0,0 +1,138 @@
1+# How to run mini-me in a Docker Sandbox
2+
3+This guide shows how to run `mm` inside a [Docker Sandbox](https://docs.docker.com/ai/sandboxes/), 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.
4+
5+Everything lives under [`docker-sbx/`](../../../docker-sbx/README.md) in the repository:
6+
7+| Piece | What it is |
8+|---|---|
9+| `template/Dockerfile` | The **template**: Docker Sandboxes' `shell` image with `mm` built from this checkout, plus the two entry points below. |
10+| `kits/mm-tui/spec.yaml` | A **sandbox kit**: `sbx run` on it opens `mm`'s window mode on the workspace. |
11+| `kits/mm-acp/spec.yaml` | A **sandbox kit** for an editor: created once with `sbx create`, the editor then runs `mm -acp` inside it. |
12+| `build.sh` | Builds the template image, `k33g/mm-sandbox:<version>`; `PUSH=1` builds it for linux/amd64 and linux/arm64 and pushes it. |
13+| `sync-kits.sh`, `push-kits.sh` | Point the kits at one image, and publish them to Docker Hub as OCI kit artifacts. |
14+
15+## Use the published kits
16+
17+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/…`:
18+
19+```bash
20+cd /path/to/your/project
21+sbx run k33g/mm-tui:0.0.2 . -- agent.dmr.yaml
22+```
23+
24+for the window mode, and for an editor:
25+
26+```bash
27+sbx create --name mm-acp k33g/mm-acp:0.0.2 . --kit-arg config=agent.dmr.yaml
28+```
29+
30+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.
31+
32+## Steps
33+
34+### 1. Build the template
35+
36+From the repository root:
37+
38+```bash
39+./docker-sbx/build.sh
40+```
41+
42+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`.
43+
44+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`.
45+
46+### 2. Window mode in the terminal (kit `mm-tui`)
47+
48+From the project you want `mm` to work on:
49+
50+```bash
51+sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
52+```
53+
54+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`.
55+
56+Without anything after `--`, `mm` reads the kit's `config` argument, then `./agent.yaml` in the workspace, then its built-in defaults:
57+
58+```bash
59+sbx run --pull never ./docker-sbx/kits/mm-tui . --kit-arg config=agent.dmr.yaml
60+```
61+
62+| `--kit-arg` | Default | Effect |
63+|---|---|---|
64+| `config=<path>` | empty | The configuration file, as `mm`'s `AGENT_CONFIG`: relative to the workspace, or absolute inside the sandbox. |
65+| `tag=<version>` | the version last built (`0.0.2`) | Which `k33g/mm-sandbox:<version>` image the sandbox is made from. |
66+
67+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](use-the-window-mode.md). Sessions, when `sessions.enabled` is on, are written under the workspace's `.mm/sessions` — that is your host directory, so they survive the sandbox.
68+
69+### 3. From an editor (kit `mm-acp`)
70+
71+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.
72+
73+1. 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):
74+
75+ ```bash
76+ cd /path/to/your/project
77+ sbx create --pull never --name mm-acp /path/to/mini-me/docker-sbx/kits/mm-acp . \
78+ --kit-arg config=agent.dmr.yaml
79+ ```
80+
81+ A 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 `N` and fix the path.
82+
83+ `--kit-arg config` becomes the container's `AGENT_CONFIG`, relative to the workspace because that is where `sbx exec` starts `mm`. The workspace is fixed at creation: one sandbox per project, each with its own `--name`.
84+
85+2. Register it in the editor. In Zed's `settings.json`:
86+
87+ ```json
88+ {
89+ "agent_servers": {
90+ "mini-me (sandbox)": {
91+ "type": "custom",
92+ "command": "sbx",
93+ "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
94+ }
95+ }
96+ }
97+ ```
98+
99+ Compared with [the host-side setup](use-from-an-editor.md), the command is `sbx` and no `env` is needed: `AGENT_CONFIG` is already in the container. If the editor cannot find `sbx`, put the absolute path from `which sbx` in `"command"`.
100+
101+3. Open the agent panel and pick **mini-me (sandbox)**. The editor starts `mm -acp` in the sandbox for every conversation; `sbx exec` starts the sandbox first when it is stopped. Tool calls, permission dialogs, `@file` mentions and the slash-command menu work as they do on the host — the difference is where the commands run.
102+
103+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.
104+
105+## The model server stays on the host
106+
107+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`.
108+
109+- **Docker Model Runner** — nothing to change: `agent.dmr.yaml` already has `fallback: http://host.docker.internal:12434/engines/v1`, and `mm` switches to it when `localhost:12434` does not answer (the banner says which URL won).
110+- **llama-server** — `agent.llamacpp.yaml` has no fallback. Either edit its `baseUrl` to `http://host.docker.internal:8080/v1`, or pass `--env AGENT_BASE_URL=http://host.docker.internal:8080/v1` to `sbx run` / `sbx create` (see [Run with llama.cpp](run-with-llama-cpp.md)).
111+
112+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>`.
113+
114+## Publishing a version
115+
116+The Release workflow (`.github/workflows/release.yml`, job `docker-sandbox`) publishes the image and the kits on every `v*` tag, after the binaries job. It needs two repository secrets, exposed to the job as environment variables: `DOCKER_HANDLE`, the Docker Hub account (also the image owner), and `DOCKER_PAT`, an access token with read/write scope. It then runs the scripts a laptop would run:
117+
118+```bash
119+docker login -u k33g # paste an access token
120+PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, pushed as k33g/mm-sandbox:0.0.2
121+./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + sbx kit push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
122+```
123+
124+`push-kits.sh` needs the `sbx` CLI on the PATH (or `SBX=/path/to/sbx`; the workflow downloads the Linux tarball of `docker/sbx-releases`). `sbx kit push` talks to the registry directly and authenticates from the Docker credential store — no sandbox daemon is involved, which is what makes it usable in CI. Both scripts 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. `IMAGE_OWNER=<handle>` publishes under another account.
125+
126+## Variants
127+
128+- **Another configuration for one editor session.** Add `"-e", "AGENT_CONFIG=agent.lsp.yaml"` before the sandbox name in `"args"`; `sbx exec -e` overrides the baked-in value for that run only.
129+- **Skills.** `skillsDir` is relative to the directory `mm` runs in, which is the workspace in both kits — the same rule as on the host.
130+- **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`.
131+- **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`.
132+- **Remove a sandbox.** `sbx rm mm-acp`. The project directory is a bind mount and is not touched.
133+
134+## See also
135+
136+- The kit format these two files follow: the Docker Sandboxes kit specification (`schemaVersion: "2"`), bundled with the `sbx` sources.
137+- What `mm -acp` exposes to the editor: [ACP reference](../reference/acp.md).
138+- The flags and environment variables `mm` reads: [command line reference](../reference/cli.md).
modified docs/fr/README.md +1 -0
@@ -12,6 +12,7 @@ Cette documentation est organisée selon les quatre quadrants [Diátaxis](https:
1212
1313 - [Faire tourner mini-me sur llama.cpp plutôt que Docker Model Runner](how-to/run-with-llama-cpp.md)
1414 - [Utiliser mini-me depuis un éditeur (ACP)](how-to/use-from-an-editor.md)
15+- [Faire tourner mini-me dans un Docker Sandbox](how-to/run-in-a-docker-sandbox.md) — le template et les deux kits sous `docker-sbx/`, mode fenêtre et éditeur
1516 - [Ajouter un skill](how-to/add-a-skill.md)
1617 - [Mesurer si le modèle choisit le bon skill](how-to/measure-skill-routing.md) — l'eval de routage : le lancer, lire son tableau, s'en servir en avant/après
1718 - [Garder une longue session dans la fenêtre de contexte](how-to/manage-the-context-window.md)
@@ -12,6 +12,7 @@ Cette documentation est organisée selon les quatre quadrants [Diátaxis](https:
12 12
13 - [Faire tourner mini-me sur llama.cpp plutôt que Docker Model Runner](how-to/run-with-llama-cpp.md)13 - [Faire tourner mini-me sur llama.cpp plutôt que Docker Model Runner](how-to/run-with-llama-cpp.md)
14 - [Utiliser mini-me depuis un éditeur (ACP)](how-to/use-from-an-editor.md)14 - [Utiliser mini-me depuis un éditeur (ACP)](how-to/use-from-an-editor.md)
15+- [Faire tourner mini-me dans un Docker Sandbox](how-to/run-in-a-docker-sandbox.md) — le template et les deux kits sous `docker-sbx/`, mode fenêtre et éditeur
15 - [Ajouter un skill](how-to/add-a-skill.md)16 - [Ajouter un skill](how-to/add-a-skill.md)
16 - [Mesurer si le modèle choisit le bon skill](how-to/measure-skill-routing.md) — l'eval de routage : le lancer, lire son tableau, s'en servir en avant/après17 - [Mesurer si le modèle choisit le bon skill](how-to/measure-skill-routing.md) — l'eval de routage : le lancer, lire son tableau, s'en servir en avant/après
17 - [Garder une longue session dans la fenêtre de contexte](how-to/manage-the-context-window.md)18 - [Garder une longue session dans la fenêtre de contexte](how-to/manage-the-context-window.md)
added docs/fr/how-to/run-in-a-docker-sandbox.md +138 -0
new file mode 100644
@@ -0,0 +1,138 @@
1+# Faire tourner mini-me dans un Docker Sandbox
2+
3+Ce guide montre comment exécuter `mm` dans un [Docker Sandbox](https://docs.docker.com/ai/sandboxes/), pour que chaque commande lancée par le modèle et chaque fichier qu'il modifie le soient dans un conteneur, sur votre projet monté. Il couvre les deux usages : le mode fenêtre dans votre terminal, et depuis un éditeur via l'Agent Client Protocol. Il suppose Docker Desktop avec la commande `sbx`, et un serveur de modèles (Docker Model Runner ou llama-server) qui tourne sur votre machine.
4+
5+Tout est sous [`docker-sbx/`](../../../docker-sbx/README.md) dans le dépôt :
6+
7+| Élément | Ce que c'est |
8+|---|---|
9+| `template/Dockerfile` | Le **template** : l'image `shell` de Docker Sandboxes avec `mm` compilé depuis ce dépôt, plus les deux points d'entrée ci-dessous. |
10+| `kits/mm-tui/spec.yaml` | Un **kit sandbox** : `sbx run` dessus ouvre le mode fenêtre de `mm` sur l'espace de travail. |
11+| `kits/mm-acp/spec.yaml` | Un **kit sandbox** pour un éditeur : créé une fois avec `sbx create`, l'éditeur y lance ensuite `mm -acp`. |
12+| `build.sh` | Construit l'image du template, `k33g/mm-sandbox:<version>` ; `PUSH=1` la construit pour linux/amd64 et linux/arm64 et la pousse. |
13+| `sync-kits.sh`, `push-kits.sh` | Alignent les kits sur une image, et les publient sur Docker Hub comme artefacts OCI de kit. |
14+
15+## Utiliser les kits publiés
16+
17+Chaque release publie l'image et les deux kits sur Docker Hub à la version de mm — `k33g/mm-sandbox:0.0.2`, `k33g/mm-tui:0.0.2`, `k33g/mm-acp:0.0.2` — le chemin le plus court ne demande donc aucune construction. Docker Hub est une source de kits autorisée par défaut (`sbx settings get kit.allowedSources` montre `docker.io/`), et une référence avec un `/` mais sans hôte de registre est lue comme `docker.io/…` :
18+
19+```bash
20+cd /chemin/de/votre/projet
21+sbx run k33g/mm-tui:0.0.2 . -- agent.dmr.yaml
22+```
23+
24+pour le mode fenêtre, et pour un éditeur :
25+
26+```bash
27+sbx create --name mm-acp k33g/mm-acp:0.0.2 . --kit-arg config=agent.dmr.yaml
28+```
29+
30+puis la déclaration dans l'éditeur de l'étape 3 ci-dessous. Pas de `--pull never` : le kit nomme `k33g/mm-sandbox:0.0.2` et sbx la télécharge. `sbx kit inspect k33g/mm-tui:0.0.2` montre ce qu'un kit déclare avant de le lancer. Les étapes qui suivent construisent la même chose en local, pour un mm en cours de travail.
31+
32+## Étapes
33+
34+### 1. Construire le template
35+
36+Depuis la racine du dépôt :
37+
38+```bash
39+./docker-sbx/build.sh
40+```
41+
42+Cela lit le tag de mm dans `release.env` (`v0.0.2`) et construit `k33g/mm-sandbox:0.0.2` : le tag de l'image est la version sans le `v`, comme les binaires de release, et le `mm` à l'intérieur est estampillé avec le tag — `mm --version` est exécuté dans l'image comme preuve. Le script réécrit ensuite la valeur par défaut de l'argument `tag` des kits à `0.0.2`, pour que kits et image avancent ensemble. `./docker-sbx/build.sh v0.0.3` construit une autre version ; une image antérieure reste joignable avec `--kit-arg tag=0.0.1`.
43+
44+L'image est dans votre store d'images Docker local : chaque `sbx run` ou `sbx create` sur ces kits prend `--pull never` tant qu'elle n'est pas poussée (`docker push k33g/mm-sandbox:0.0.2`), sinon `sbx` tente de la télécharger et échoue. Si `sbx` tourne sur une autre machine, `EXPORT=1 ./docker-sbx/build.sh` écrit aussi `tmp/mm-sandbox-0.0.2.tar`, à charger là-bas avec `sbx template load`.
45+
46+### 2. Mode fenêtre dans le terminal (kit `mm-tui`)
47+
48+Depuis le projet sur lequel `mm` doit travailler :
49+
50+```bash
51+sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
52+```
53+
54+La première fois, `sbx` crée le sandbox, monte le répertoire courant comme espace de travail et s'y attache ; puis il lance le point d'entrée du kit avec ce qui suit `--` en arguments — ici `mm -tui agent.dmr.yaml`, dans l'espace de travail. N'importe quel drapeau de `mm` passe de la même façon : `-- -config autre.yaml`.
55+
56+Sans rien après `--`, `mm` lit l'argument `config` du kit, puis `./agent.yaml` dans l'espace de travail, puis ses valeurs par défaut :
57+
58+```bash
59+sbx run --pull never ./docker-sbx/kits/mm-tui . --kit-arg config=agent.dmr.yaml
60+```
61+
62+| `--kit-arg` | Défaut | Effet |
63+|---|---|---|
64+| `config=<chemin>` | vide | Le fichier de configuration, comme `AGENT_CONFIG` de `mm` : relatif à l'espace de travail, ou absolu dans le sandbox. |
65+| `tag=<version>` | la dernière version construite (`0.0.2`) | L'image `k33g/mm-sandbox:<version>` dont le sandbox est fait. |
66+
67+Le sandbox garde son nom (`mm-tui-<répertoire>` sauf `--name`) ; `sbx run --name <nom>` s'y rattache plus tard. À l'intérieur, la fenêtre est celle décrite dans [Utiliser le mode fenêtre](use-the-window-mode.md). Les sessions, quand `sessions.enabled` est actif, sont écrites sous `.mm/sessions` dans l'espace de travail — c'est votre répertoire hôte, elles survivent donc au sandbox.
68+
69+### 3. Depuis un éditeur (kit `mm-acp`)
70+
71+Un éditeur parle à `mm -acp` sur l'entrée et la sortie standard brutes de l'agent. `sbx run` ne peut pas porter cela : il alloue toujours un terminal. Le sandbox est donc créé une fois sans s'y attacher, et l'éditeur y lance `mm` avec `sbx exec -i`, qui transmet stdin et stdout tels quels.
72+
73+1. Depuis le projet que l'éditeur ouvrira, créez le sandbox avec le fichier de configuration intégré (`.` est l'espace de travail, sbx le rend absolu ; le chemin du kit doit être explicite : `./`, `../` ou absolu) :
74+
75+ ```bash
76+ cd /chemin/de/votre/projet
77+ sbx create --pull never --name mm-acp /chemin/de/mini-me/docker-sbx/kits/mm-acp . \
78+ --kit-arg config=agent.dmr.yaml
79+ ```
80+
81+ Un chemin d'espace de travail qui n'existe pas sur votre machine fait demander à sbx « The selected workspace does not exist. Would you like to create it? » — répondez `N` et corrigez le chemin.
82+
83+ `--kit-arg config` devient l'`AGENT_CONFIG` du conteneur, relatif à l'espace de travail parce que c'est là que `sbx exec` démarre `mm`. L'espace de travail est fixé à la création : un sandbox par projet, chacun avec son `--name`.
84+
85+2. Déclarez-le dans l'éditeur. Dans le `settings.json` de Zed :
86+
87+ ```json
88+ {
89+ "agent_servers": {
90+ "mini-me (sandbox)": {
91+ "type": "custom",
92+ "command": "sbx",
93+ "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
94+ }
95+ }
96+ }
97+ ```
98+
99+ Par rapport à [la configuration côté hôte](use-from-an-editor.md), la commande est `sbx` et aucun `env` n'est nécessaire : `AGENT_CONFIG` est déjà dans le conteneur. Si l'éditeur ne trouve pas `sbx`, mettez le chemin absolu donné par `which sbx` dans `"command"`.
100+
101+3. Ouvrez le panneau agent et choisissez **mini-me (sandbox)**. L'éditeur lance `mm -acp` dans le sandbox à chaque conversation ; `sbx exec` démarre d'abord le sandbox s'il est arrêté. Appels d'outils, dialogues de permission, mentions `@fichier` et menu des commandes fonctionnent comme sur l'hôte — la différence est l'endroit où les commandes s'exécutent.
102+
103+S'attacher à ce sandbox avec `sbx run --name mm-acp` ne lance pas `mm` : son point d'entrée affiche le câblage ci-dessus avec le vrai nom et les vrais chemins du sandbox, puis ouvre un shell à l'intérieur. `sbx exec -it mm-acp bash` est le chemin le plus court vers ce shell.
104+
105+## Le serveur de modèles reste sur l'hôte
106+
107+Dans un sandbox, `localhost` est le sandbox lui-même. Votre serveur de modèles continue de tourner sur votre machine et se joint par `host.docker.internal`, que le proxy du sandbox fait pointer vers le `localhost` de l'hôte.
108+
109+- **Docker Model Runner** — rien à changer : `agent.dmr.yaml` a déjà `fallback: http://host.docker.internal:12434/engines/v1`, et `mm` bascule dessus quand `localhost:12434` ne répond pas (la bannière dit quelle URL a gagné).
110+- **llama-server** — `agent.llamacpp.yaml` n'a pas de fallback. Soit vous changez son `baseUrl` en `http://host.docker.internal:8080/v1`, soit vous passez `--env AGENT_BASE_URL=http://host.docker.internal:8080/v1` à `sbx run` / `sbx create` (voir [Faire tourner sur llama.cpp](run-with-llama-cpp.md)).
111+
112+Les deux kits autorisent les ports 12434 et 8080 de l'hôte dans la politique réseau du sandbox. Pour un autre port : `sbx policy allow network host.docker.internal:<port>`.
113+
114+## Publier une version
115+
116+Le workflow Release (`.github/workflows/release.yml`, job `docker-sandbox`) publie l'image et les kits à chaque tag `v*`, après le job des binaires. Il a besoin de deux secrets du dépôt, exposés au job comme variables d'environnement : `DOCKER_HANDLE`, le compte Docker Hub (aussi le propriétaire de l'image), et `DOCKER_PAT`, un jeton d'accès en lecture/écriture. Il lance ensuite les scripts qu'un portable lancerait :
117+
118+```bash
119+docker login -u k33g # coller un jeton d'accès
120+PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, poussée comme k33g/mm-sandbox:0.0.2
121+./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + sbx kit push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
122+```
123+
124+`push-kits.sh` a besoin de la CLI `sbx` sur le PATH (ou `SBX=/chemin/vers/sbx` ; le workflow télécharge l'archive Linux de `docker/sbx-releases`). `sbx kit push` parle directement au registre et s'authentifie depuis le magasin d'identifiants Docker — aucun démon sandbox n'intervient, c'est ce qui le rend utilisable en CI. Les deux scripts appellent d'abord `sync-kits.sh`, qui réécrit `version`, le `tag` par défaut et le propriétaire de l'image des kits, de sorte qu'un kit publié nomme toujours l'image poussée avec lui. `IMAGE_OWNER=<compte>` publie sous un autre compte.
125+
126+## Variantes
127+
128+- **Une autre configuration pour une session d'éditeur.** Ajoutez `"-e", "AGENT_CONFIG=agent.lsp.yaml"` avant le nom du sandbox dans `"args"` ; `sbx exec -e` remplace la valeur intégrée pour cette exécution seulement.
129+- **Skills.** `skillsDir` est relatif au répertoire où `mm` tourne, c'est-à-dire l'espace de travail dans les deux kits — la même règle que sur l'hôte.
130+- **Docker dans le sandbox.** Construisez le template sur le shell Docker-in-Docker : `SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx/build.sh`.
131+- **Lire les logs.** En mode fenêtre ils sont à l'écran ; en ACP ils vont sur stderr, que Zed montre sous `dev: open acp logs`.
132+- **Supprimer un sandbox.** `sbx rm mm-acp`. Le répertoire du projet est un montage et n'est pas touché.
133+
134+## Voir aussi
135+
136+- Le format suivi par ces deux fichiers : la spécification des kits de Docker Sandboxes (`schemaVersion: "2"`), livrée avec les sources de `sbx`.
137+- Ce que `mm -acp` expose à l'éditeur : [référence ACP](../reference/acp.md).
138+- Les drapeaux et variables d'environnement que `mm` lit : [référence de la ligne de commande](../reference/cli.md).
new file mode 100644
@@ -0,0 +1,138 @@
1+# Faire tourner mini-me dans un Docker Sandbox
2+
3+Ce guide montre comment exécuter `mm` dans un [Docker Sandbox](https://docs.docker.com/ai/sandboxes/), pour que chaque commande lancée par le modèle et chaque fichier qu'il modifie le soient dans un conteneur, sur votre projet monté. Il couvre les deux usages : le mode fenêtre dans votre terminal, et depuis un éditeur via l'Agent Client Protocol. Il suppose Docker Desktop avec la commande `sbx`, et un serveur de modèles (Docker Model Runner ou llama-server) qui tourne sur votre machine.
4+
5+Tout est sous [`docker-sbx/`](../../../docker-sbx/README.md) dans le dépôt :
6+
7+| Élément | Ce que c'est |
8+|---|---|
9+| `template/Dockerfile` | Le **template** : l'image `shell` de Docker Sandboxes avec `mm` compilé depuis ce dépôt, plus les deux points d'entrée ci-dessous. |
10+| `kits/mm-tui/spec.yaml` | Un **kit sandbox** : `sbx run` dessus ouvre le mode fenêtre de `mm` sur l'espace de travail. |
11+| `kits/mm-acp/spec.yaml` | Un **kit sandbox** pour un éditeur : créé une fois avec `sbx create`, l'éditeur y lance ensuite `mm -acp`. |
12+| `build.sh` | Construit l'image du template, `k33g/mm-sandbox:<version>` ; `PUSH=1` la construit pour linux/amd64 et linux/arm64 et la pousse. |
13+| `sync-kits.sh`, `push-kits.sh` | Alignent les kits sur une image, et les publient sur Docker Hub comme artefacts OCI de kit. |
14+
15+## Utiliser les kits publiés
16+
17+Chaque release publie l'image et les deux kits sur Docker Hub à la version de mm — `k33g/mm-sandbox:0.0.2`, `k33g/mm-tui:0.0.2`, `k33g/mm-acp:0.0.2` — le chemin le plus court ne demande donc aucune construction. Docker Hub est une source de kits autorisée par défaut (`sbx settings get kit.allowedSources` montre `docker.io/`), et une référence avec un `/` mais sans hôte de registre est lue comme `docker.io/…` :
18+
19+```bash
20+cd /chemin/de/votre/projet
21+sbx run k33g/mm-tui:0.0.2 . -- agent.dmr.yaml
22+```
23+
24+pour le mode fenêtre, et pour un éditeur :
25+
26+```bash
27+sbx create --name mm-acp k33g/mm-acp:0.0.2 . --kit-arg config=agent.dmr.yaml
28+```
29+
30+puis la déclaration dans l'éditeur de l'étape 3 ci-dessous. Pas de `--pull never` : le kit nomme `k33g/mm-sandbox:0.0.2` et sbx la télécharge. `sbx kit inspect k33g/mm-tui:0.0.2` montre ce qu'un kit déclare avant de le lancer. Les étapes qui suivent construisent la même chose en local, pour un mm en cours de travail.
31+
32+## Étapes
33+
34+### 1. Construire le template
35+
36+Depuis la racine du dépôt :
37+
38+```bash
39+./docker-sbx/build.sh
40+```
41+
42+Cela lit le tag de mm dans `release.env` (`v0.0.2`) et construit `k33g/mm-sandbox:0.0.2` : le tag de l'image est la version sans le `v`, comme les binaires de release, et le `mm` à l'intérieur est estampillé avec le tag — `mm --version` est exécuté dans l'image comme preuve. Le script réécrit ensuite la valeur par défaut de l'argument `tag` des kits à `0.0.2`, pour que kits et image avancent ensemble. `./docker-sbx/build.sh v0.0.3` construit une autre version ; une image antérieure reste joignable avec `--kit-arg tag=0.0.1`.
43+
44+L'image est dans votre store d'images Docker local : chaque `sbx run` ou `sbx create` sur ces kits prend `--pull never` tant qu'elle n'est pas poussée (`docker push k33g/mm-sandbox:0.0.2`), sinon `sbx` tente de la télécharger et échoue. Si `sbx` tourne sur une autre machine, `EXPORT=1 ./docker-sbx/build.sh` écrit aussi `tmp/mm-sandbox-0.0.2.tar`, à charger là-bas avec `sbx template load`.
45+
46+### 2. Mode fenêtre dans le terminal (kit `mm-tui`)
47+
48+Depuis le projet sur lequel `mm` doit travailler :
49+
50+```bash
51+sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
52+```
53+
54+La première fois, `sbx` crée le sandbox, monte le répertoire courant comme espace de travail et s'y attache ; puis il lance le point d'entrée du kit avec ce qui suit `--` en arguments — ici `mm -tui agent.dmr.yaml`, dans l'espace de travail. N'importe quel drapeau de `mm` passe de la même façon : `-- -config autre.yaml`.
55+
56+Sans rien après `--`, `mm` lit l'argument `config` du kit, puis `./agent.yaml` dans l'espace de travail, puis ses valeurs par défaut :
57+
58+```bash
59+sbx run --pull never ./docker-sbx/kits/mm-tui . --kit-arg config=agent.dmr.yaml
60+```
61+
62+| `--kit-arg` | Défaut | Effet |
63+|---|---|---|
64+| `config=<chemin>` | vide | Le fichier de configuration, comme `AGENT_CONFIG` de `mm` : relatif à l'espace de travail, ou absolu dans le sandbox. |
65+| `tag=<version>` | la dernière version construite (`0.0.2`) | L'image `k33g/mm-sandbox:<version>` dont le sandbox est fait. |
66+
67+Le sandbox garde son nom (`mm-tui-<répertoire>` sauf `--name`) ; `sbx run --name <nom>` s'y rattache plus tard. À l'intérieur, la fenêtre est celle décrite dans [Utiliser le mode fenêtre](use-the-window-mode.md). Les sessions, quand `sessions.enabled` est actif, sont écrites sous `.mm/sessions` dans l'espace de travail — c'est votre répertoire hôte, elles survivent donc au sandbox.
68+
69+### 3. Depuis un éditeur (kit `mm-acp`)
70+
71+Un éditeur parle à `mm -acp` sur l'entrée et la sortie standard brutes de l'agent. `sbx run` ne peut pas porter cela : il alloue toujours un terminal. Le sandbox est donc créé une fois sans s'y attacher, et l'éditeur y lance `mm` avec `sbx exec -i`, qui transmet stdin et stdout tels quels.
72+
73+1. Depuis le projet que l'éditeur ouvrira, créez le sandbox avec le fichier de configuration intégré (`.` est l'espace de travail, sbx le rend absolu ; le chemin du kit doit être explicite : `./`, `../` ou absolu) :
74+
75+ ```bash
76+ cd /chemin/de/votre/projet
77+ sbx create --pull never --name mm-acp /chemin/de/mini-me/docker-sbx/kits/mm-acp . \
78+ --kit-arg config=agent.dmr.yaml
79+ ```
80+
81+ Un chemin d'espace de travail qui n'existe pas sur votre machine fait demander à sbx « The selected workspace does not exist. Would you like to create it? » — répondez `N` et corrigez le chemin.
82+
83+ `--kit-arg config` devient l'`AGENT_CONFIG` du conteneur, relatif à l'espace de travail parce que c'est là que `sbx exec` démarre `mm`. L'espace de travail est fixé à la création : un sandbox par projet, chacun avec son `--name`.
84+
85+2. Déclarez-le dans l'éditeur. Dans le `settings.json` de Zed :
86+
87+ ```json
88+ {
89+ "agent_servers": {
90+ "mini-me (sandbox)": {
91+ "type": "custom",
92+ "command": "sbx",
93+ "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
94+ }
95+ }
96+ }
97+ ```
98+
99+ Par rapport à [la configuration côté hôte](use-from-an-editor.md), la commande est `sbx` et aucun `env` n'est nécessaire : `AGENT_CONFIG` est déjà dans le conteneur. Si l'éditeur ne trouve pas `sbx`, mettez le chemin absolu donné par `which sbx` dans `"command"`.
100+
101+3. Ouvrez le panneau agent et choisissez **mini-me (sandbox)**. L'éditeur lance `mm -acp` dans le sandbox à chaque conversation ; `sbx exec` démarre d'abord le sandbox s'il est arrêté. Appels d'outils, dialogues de permission, mentions `@fichier` et menu des commandes fonctionnent comme sur l'hôte — la différence est l'endroit où les commandes s'exécutent.
102+
103+S'attacher à ce sandbox avec `sbx run --name mm-acp` ne lance pas `mm` : son point d'entrée affiche le câblage ci-dessus avec le vrai nom et les vrais chemins du sandbox, puis ouvre un shell à l'intérieur. `sbx exec -it mm-acp bash` est le chemin le plus court vers ce shell.
104+
105+## Le serveur de modèles reste sur l'hôte
106+
107+Dans un sandbox, `localhost` est le sandbox lui-même. Votre serveur de modèles continue de tourner sur votre machine et se joint par `host.docker.internal`, que le proxy du sandbox fait pointer vers le `localhost` de l'hôte.
108+
109+- **Docker Model Runner** — rien à changer : `agent.dmr.yaml` a déjà `fallback: http://host.docker.internal:12434/engines/v1`, et `mm` bascule dessus quand `localhost:12434` ne répond pas (la bannière dit quelle URL a gagné).
110+- **llama-server** — `agent.llamacpp.yaml` n'a pas de fallback. Soit vous changez son `baseUrl` en `http://host.docker.internal:8080/v1`, soit vous passez `--env AGENT_BASE_URL=http://host.docker.internal:8080/v1` à `sbx run` / `sbx create` (voir [Faire tourner sur llama.cpp](run-with-llama-cpp.md)).
111+
112+Les deux kits autorisent les ports 12434 et 8080 de l'hôte dans la politique réseau du sandbox. Pour un autre port : `sbx policy allow network host.docker.internal:<port>`.
113+
114+## Publier une version
115+
116+Le workflow Release (`.github/workflows/release.yml`, job `docker-sandbox`) publie l'image et les kits à chaque tag `v*`, après le job des binaires. Il a besoin de deux secrets du dépôt, exposés au job comme variables d'environnement : `DOCKER_HANDLE`, le compte Docker Hub (aussi le propriétaire de l'image), et `DOCKER_PAT`, un jeton d'accès en lecture/écriture. Il lance ensuite les scripts qu'un portable lancerait :
117+
118+```bash
119+docker login -u k33g # coller un jeton d'accès
120+PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, poussée comme k33g/mm-sandbox:0.0.2
121+./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + sbx kit push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
122+```
123+
124+`push-kits.sh` a besoin de la CLI `sbx` sur le PATH (ou `SBX=/chemin/vers/sbx` ; le workflow télécharge l'archive Linux de `docker/sbx-releases`). `sbx kit push` parle directement au registre et s'authentifie depuis le magasin d'identifiants Docker — aucun démon sandbox n'intervient, c'est ce qui le rend utilisable en CI. Les deux scripts appellent d'abord `sync-kits.sh`, qui réécrit `version`, le `tag` par défaut et le propriétaire de l'image des kits, de sorte qu'un kit publié nomme toujours l'image poussée avec lui. `IMAGE_OWNER=<compte>` publie sous un autre compte.
125+
126+## Variantes
127+
128+- **Une autre configuration pour une session d'éditeur.** Ajoutez `"-e", "AGENT_CONFIG=agent.lsp.yaml"` avant le nom du sandbox dans `"args"` ; `sbx exec -e` remplace la valeur intégrée pour cette exécution seulement.
129+- **Skills.** `skillsDir` est relatif au répertoire où `mm` tourne, c'est-à-dire l'espace de travail dans les deux kits — la même règle que sur l'hôte.
130+- **Docker dans le sandbox.** Construisez le template sur le shell Docker-in-Docker : `SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx/build.sh`.
131+- **Lire les logs.** En mode fenêtre ils sont à l'écran ; en ACP ils vont sur stderr, que Zed montre sous `dev: open acp logs`.
132+- **Supprimer un sandbox.** `sbx rm mm-acp`. Le répertoire du projet est un montage et n'est pas touché.
133+
134+## Voir aussi
135+
136+- Le format suivi par ces deux fichiers : la spécification des kits de Docker Sandboxes (`schemaVersion: "2"`), livrée avec les sources de `sbx`.
137+- Ce que `mm -acp` expose à l'éditeur : [référence ACP](../reference/acp.md).
138+- Les drapeaux et variables d'environnement que `mm` lit : [référence de la ligne de commande](../reference/cli.md).