bots-garden/mini-mepublic Fork
⑂ ddc354c
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.Unverified

k33g committed 2026-10-09T14:52:21+02:00 Browse files
ddc354c parent: 11a9590
modified .vscode/settings.json +1 -1
@@ -1,6 +1,6 @@
11 {
22 "workbench.iconTheme": "material-icon-theme",
3- "workbench.colorTheme": "GitHub Light Colorblind (Beta)",
3+ "workbench.colorTheme": "Light Modern",
44 "editor.fontSize": 14,
55 "terminal.integrated.fontSize": 16,
66 "editor.insertSpaces": true,
@@ -1,6 +1,6 @@
1 {1 {
2 "workbench.iconTheme": "material-icon-theme",2 "workbench.iconTheme": "material-icon-theme",
3- "workbench.colorTheme": "GitHub Light Colorblind (Beta)",3+ "workbench.colorTheme": "Light Modern",
4 "editor.fontSize": 14,4 "editor.fontSize": 14,
5 "terminal.integrated.fontSize": 16,5 "terminal.integrated.fontSize": 16,
6 "editor.insertSpaces": true,6 "editor.insertSpaces": true,
deleted docker-sbx-v3/README.md +0 -154
deleted file mode 100644
@@ -1,154 +0,0 @@
1-# mm in a Docker Sandbox — kits v3
2-
3-The same two kits as [`../docker-sbx`](../docker-sbx/README.md), rewritten for the [kit specification v3](https://github.com/docker/sandbox-kit-spec) (`schemaVersion: "3"`). `docker-sbx/` (v2) is left untouched and keeps working: sbx still loads `spec.yaml` kits.
4-
5-- **mm-tui** — `sbx run` opens mm's window mode (`mm -tui`) on the workspace.
6-- **mm-acp** — `sbx create` once, then an editor that speaks the Agent Client Protocol runs `sbx exec -i … mm -acp`.
7-
8-```
9-docker-sbx-v3/
10-├── publish.sh build + push the image, then build + push the kits — the one command to release
11-├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)
12-├── sync-kits.sh points the kits at one image: owner + version
13-├── check-kits.sh builds the kits locally (no push, no sbx) and checks them with kit-tck if present
14-├── push-kits.sh builds and pushes the kits with buildx: <owner>/sbx-kit-mm-tui, <owner>/sbx-kit-mm-acp
15-├── template/
16-│ ├── Dockerfile docker/sandbox-templates:shell + mm (built from this checkout) — same image as v2
17-│ ├── mm-tui entry point of the mm-tui kit: `mm -tui "$@"`
18-│ └── mm-acp-info entry point of the mm-acp kit: prints the editor wiring, opens a shell
19-└── kits/
20- ├── mm-tui/
21- │ ├── mm-tui.yaml the descriptor: kind: workload, args, capabilities
22- │ └── mm-tui.dockerfile the content: FROM <image>:<tag>, ENV, ENTRYPOINT ["mm-tui"]
23- └── mm-acp/
24- ├── mm-acp.yaml
25- └── mm-acp.dockerfile … ENTRYPOINT ["mm-acp-info"]
26-```
27-
28-## What changed from the v2 kits
29-
30-| | v2 (`docker-sbx/kits/*/spec.yaml`) | v3 (`docker-sbx-v3/kits/*/`) |
31-|---|---|---|
32-| Files | one `spec.yaml` | `<kit>.yaml` (descriptor) + `<kit>.dockerfile` (content) |
33-| Kind | `kind: sandbox` | `kind: workload` |
34-| Name | `name: mm-tui` | none: a kit's identity is the reference it is consumed by |
35-| Image, entry point, env | `sandbox.image`, `sandbox.entrypoint`, `environment.variables` | `FROM`, `ENTRYPOINT`, `ENV` in the Dockerfile — the descriptor restates nothing the image config carries |
36-| Network | `permissions.network.allow` | `capabilities: - type: com.docker.sandbox/network-policy@1` (`runtime.allow`) |
37-| Agent launch | implicit | `capabilities: - type: com.docker.sandbox/sbx@1`: the host runs the ENTRYPOINT under bash, as the image's user (`agent`) |
38-| `tag` arg | substituted into `sandbox.image` at create | **build-phase** (`buildArg: MM_TAG`): baked in when the kit is built; also the kit's `version` and its `provides: mm@<tag>` |
39-| `config` arg | substituted into `environment.variables` | **create-phase** (`env: AGENT_CONFIG`): exported to the container at `sbx run` / `sbx create` |
40-| Owner of the image | rewritten in `sandbox.image` | its own build-phase arg, `image` (`k33g/mm-sandbox`) |
41-| Published as | `sbx kit push` → `k33g/mm-tui`, `k33g/mm-acp` | `docker buildx build --push` → `k33g/sbx-kit-mm-tui`, `k33g/sbx-kit-mm-acp` (an ordinary multi-arch image, with SBOM and provenance) |
42-
43-The repositories differ on purpose: pushing a v3 kit to `k33g/mm-tui:<version>` would replace the v2 kit published under that tag. `sbx-kit-<name>` is the naming Docker's own kits use.
44-
45-## Two things behave differently
46-
47-**The workspace is `/home/agent/workspace`.** The template's base image declares that `WORKDIR`, and `sbx@1` requires the host to mount the workspace at the image's working directory when it is absolute. A relative configuration path (`config=agent.dmr.yaml`) works as before. An absolute **host** path in `AGENT_CONFIG` (`/Users/…/agent.dmr.yaml`) does not: use the path relative to the workspace, or `/home/agent/workspace/…`. (Stated by the specification; not yet observed with sbx.)
48-
49-**The template image must be on a registry to run the kits from source.** A v3 kit is built on top of the template (`FROM k33g/mm-sandbox:<tag>`), and `sbx run ./docker-sbx-v3/kits/…` builds it in sbx's builder sandbox, whose own Docker engine pulls that image from the registry. `--pull never` and `sbx template load` no longer help. Push the image (`PUSH=1 ./docker-sbx-v3/build.sh`) before running a kit from source, or check the kits without sbx with `check-kits.sh`.
50-
51-## 0. Use the published kits (no build)
52-
53-Once `publish.sh` has run for a version:
54-
55-```bash
56-sbx kit inspect k33g/sbx-kit-mm-tui:0.2.1 # look before you run
57-
58-cd /path/to/your/project
59-sbx run k33g/sbx-kit-mm-tui:0.2.1 . -- agent.dmr.yaml
60-sbx run k33g/sbx-kit-mm-tui:0.2.1 . --kit-arg config=agent.dmr.yaml
61-```
62-
63-What follows `--` is mm's own command line. Without it, mm reads the `config` argument, then `./agent.yaml` in the workspace, then its built-in defaults.
64-
65-From an editor, create the sandbox once, from the project the editor will open:
66-
67-```bash
68-cd /path/to/your/project
69-sbx create --name mm-acp k33g/sbx-kit-mm-acp:0.2.1 . --kit-arg config=agent.dmr.yaml
70-```
71-
72-then register it — in Zed's `settings.json`:
73-
74-```json
75-{
76- "agent_servers": {
77- "mini-me (sandbox)": {
78- "type": "custom",
79- "command": "sbx",
80- "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
81- }
82- }
83-}
84-```
85-
86-**Kit arguments.** On a published kit only `config` can be set: `image` and `tag` are build-phase and were fixed when the kit was built, so a published kit always names the image it was built on. To use another mm version, take the kit of that version.
87-
88-| `--kit-arg` | Default | Phase | Effect |
89-|---|---|---|---|
90-| `config=<path>` | empty | create | The file mm reads (its `AGENT_CONFIG`): relative to the workspace, or absolute inside the sandbox. Empty: `./agent.yaml`, then the built-in defaults. |
91-| `tag=<version>` | mm's version (`0.2.1`) | build | Which `<image>:<tag>` the kit is built FROM; also the kit's version. No `v`. |
92-| `image=<repo>` | `k33g/mm-sandbox` | build | Which repository the kit is built FROM. |
93-
94-## 1. Build the template
95-
96-From the repository root:
97-
98-```bash
99-./docker-sbx-v3/build.sh # TAG from release.env: v0.2.1 → k33g/mm-sandbox:0.2.1, local store
100-PUSH=1 ./docker-sbx-v3/build.sh # multi-arch, pushed — needed before running a kit from source
101-```
102-
103-Same image, same rules as v2's `build.sh`; it then rewrites the kits' `image` and `tag` defaults (`sync-kits.sh`), so the kits always name the image just built.
104-
105-## 2. Check the kits without sbx
106-
107-```bash
108-./docker-sbx-v3/check-kits.sh # both kits
109-./docker-sbx-v3/check-kits.sh mm-tui # one
110-```
111-
112-Each kit is built with `docker buildx build -f <kit>.yaml`: the descriptor's first line, `# syntax=docker/sandbox-kit:3`, makes BuildKit pull the kit frontend, which validates the descriptor (unknown keys and arg patterns included), builds the companion Dockerfile and writes the published form to `tmp/kits-v3/<kit>/`. With [`kit-tck`](https://github.com/docker/sandbox-kit-spec) on the `PATH` (or `KIT_TCK=/path/to/kit-tck`), the result is also checked against the specification:
113-
114-```bash
115-git clone https://github.com/docker/sandbox-kit-spec && cd sandbox-kit-spec
116-go build -o ~/.local/bin/kit-tck ./cmd/kit-tck
117-```
118-
119-## 3. Run the kits from source
120-
121-With the template pushed (section 1):
122-
123-```bash
124-cd /path/to/your/project
125-sbx run /path/to/mini-me/docker-sbx-v3/kits/mm-tui . -- agent.dmr.yaml
126-sbx create --name mm-acp /path/to/mini-me/docker-sbx-v3/kits/mm-acp . --kit-arg config=agent.dmr.yaml
127-```
128-
129-sbx recognizes a v3 kit directory by its single `*.yaml` declaring `schemaVersion: "3"` (and no `spec.yaml`), builds it in its builder sandbox (`sbx kit builder status`), and caches the result by the directory's content. From source, the build-phase args can be set too: `--kit-arg tag=0.2.2`.
130-
131-## 4. Publishing a version
132-
133-```bash
134-export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
135-export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
136-./docker-sbx-v3/publish.sh # TAG from release.env: k33g/mm-sandbox:0.2.1, k33g/sbx-kit-mm-tui:0.2.1, k33g/sbx-kit-mm-acp:0.2.1
137-```
138-
139-It is two steps you can also run alone:
140-
141-```bash
142-PUSH=1 ./docker-sbx-v3/build.sh v0.2.1 # the image, multi-arch, pushed
143-./docker-sbx-v3/push-kits.sh v0.2.1 # the kits: buildx build --push, linux/amd64 + linux/arm64
144-```
145-
146-`push-kits.sh` refuses to start when the image is not on the registry yet, runs `sync-kits.sh`, then builds each kit with the `mm-sandbox-builder` buildx instance (created by `build.sh` if needed) with SBOM and provenance attestations, and validates the pushed kits with `kit-tck` when it is available. No `sbx` is needed to publish. `IMAGE_OWNER`, `REGISTRY`, `KIT_PREFIX` and `PLATFORMS` override the defaults. The descriptors end up naming the new version — commit them.
147-
148-## The model server stays on the host
149-
150-Unchanged from v2: inside a sandbox `localhost` is the sandbox itself, and Docker Model Runner or llama-server are reached through `host.docker.internal`. 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>`.
151-
152-## Status
153-
154-Checked here: both kits build with the `docker/sandbox-kit:3` frontend (3.0.0-m.6), single- and multi-arch with attestations, and pass `kit-tck validate` (18/18); the published config is `User: agent`, `Entrypoint: [mm-tui]` (or `[mm-acp-info]`), no `Cmd`, `WorkingDir: /home/agent/workspace`. Not yet checked: running them with `sbx` (`sbx run`, `sbx create`, `sbx exec -i … mm -acp`), and pushing to Docker Hub. The kit specification itself is still marked experimental.
deleted file mode 100644
@@ -1,154 +0,0 @@
1-# mm in a Docker Sandbox — kits v3
2-
3-The same two kits as [`../docker-sbx`](../docker-sbx/README.md), rewritten for the [kit specification v3](https://github.com/docker/sandbox-kit-spec) (`schemaVersion: "3"`). `docker-sbx/` (v2) is left untouched and keeps working: sbx still loads `spec.yaml` kits.
4-
5-- **mm-tui** — `sbx run` opens mm's window mode (`mm -tui`) on the workspace.
6-- **mm-acp** — `sbx create` once, then an editor that speaks the Agent Client Protocol runs `sbx exec -i … mm -acp`.
7-
8-```
9-docker-sbx-v3/
10-├── publish.sh build + push the image, then build + push the kits — the one command to release
11-├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)
12-├── sync-kits.sh points the kits at one image: owner + version
13-├── check-kits.sh builds the kits locally (no push, no sbx) and checks them with kit-tck if present
14-├── push-kits.sh builds and pushes the kits with buildx: <owner>/sbx-kit-mm-tui, <owner>/sbx-kit-mm-acp
15-├── template/
16-│ ├── Dockerfile docker/sandbox-templates:shell + mm (built from this checkout) — same image as v2
17-│ ├── mm-tui entry point of the mm-tui kit: `mm -tui "$@"`
18-│ └── mm-acp-info entry point of the mm-acp kit: prints the editor wiring, opens a shell
19-└── kits/
20- ├── mm-tui/
21- │ ├── mm-tui.yaml the descriptor: kind: workload, args, capabilities
22- │ └── mm-tui.dockerfile the content: FROM <image>:<tag>, ENV, ENTRYPOINT ["mm-tui"]
23- └── mm-acp/
24- ├── mm-acp.yaml
25- └── mm-acp.dockerfile … ENTRYPOINT ["mm-acp-info"]
26-```
27-
28-## What changed from the v2 kits
29-
30-| | v2 (`docker-sbx/kits/*/spec.yaml`) | v3 (`docker-sbx-v3/kits/*/`) |
31-|---|---|---|
32-| Files | one `spec.yaml` | `<kit>.yaml` (descriptor) + `<kit>.dockerfile` (content) |
33-| Kind | `kind: sandbox` | `kind: workload` |
34-| Name | `name: mm-tui` | none: a kit's identity is the reference it is consumed by |
35-| Image, entry point, env | `sandbox.image`, `sandbox.entrypoint`, `environment.variables` | `FROM`, `ENTRYPOINT`, `ENV` in the Dockerfile — the descriptor restates nothing the image config carries |
36-| Network | `permissions.network.allow` | `capabilities: - type: com.docker.sandbox/network-policy@1` (`runtime.allow`) |
37-| Agent launch | implicit | `capabilities: - type: com.docker.sandbox/sbx@1`: the host runs the ENTRYPOINT under bash, as the image's user (`agent`) |
38-| `tag` arg | substituted into `sandbox.image` at create | **build-phase** (`buildArg: MM_TAG`): baked in when the kit is built; also the kit's `version` and its `provides: mm@<tag>` |
39-| `config` arg | substituted into `environment.variables` | **create-phase** (`env: AGENT_CONFIG`): exported to the container at `sbx run` / `sbx create` |
40-| Owner of the image | rewritten in `sandbox.image` | its own build-phase arg, `image` (`k33g/mm-sandbox`) |
41-| Published as | `sbx kit push` → `k33g/mm-tui`, `k33g/mm-acp` | `docker buildx build --push` → `k33g/sbx-kit-mm-tui`, `k33g/sbx-kit-mm-acp` (an ordinary multi-arch image, with SBOM and provenance) |
42-
43-The repositories differ on purpose: pushing a v3 kit to `k33g/mm-tui:<version>` would replace the v2 kit published under that tag. `sbx-kit-<name>` is the naming Docker's own kits use.
44-
45-## Two things behave differently
46-
47-**The workspace is `/home/agent/workspace`.** The template's base image declares that `WORKDIR`, and `sbx@1` requires the host to mount the workspace at the image's working directory when it is absolute. A relative configuration path (`config=agent.dmr.yaml`) works as before. An absolute **host** path in `AGENT_CONFIG` (`/Users/…/agent.dmr.yaml`) does not: use the path relative to the workspace, or `/home/agent/workspace/…`. (Stated by the specification; not yet observed with sbx.)
48-
49-**The template image must be on a registry to run the kits from source.** A v3 kit is built on top of the template (`FROM k33g/mm-sandbox:<tag>`), and `sbx run ./docker-sbx-v3/kits/…` builds it in sbx's builder sandbox, whose own Docker engine pulls that image from the registry. `--pull never` and `sbx template load` no longer help. Push the image (`PUSH=1 ./docker-sbx-v3/build.sh`) before running a kit from source, or check the kits without sbx with `check-kits.sh`.
50-
51-## 0. Use the published kits (no build)
52-
53-Once `publish.sh` has run for a version:
54-
55-```bash
56-sbx kit inspect k33g/sbx-kit-mm-tui:0.2.1 # look before you run
57-
58-cd /path/to/your/project
59-sbx run k33g/sbx-kit-mm-tui:0.2.1 . -- agent.dmr.yaml
60-sbx run k33g/sbx-kit-mm-tui:0.2.1 . --kit-arg config=agent.dmr.yaml
61-```
62-
63-What follows `--` is mm's own command line. Without it, mm reads the `config` argument, then `./agent.yaml` in the workspace, then its built-in defaults.
64-
65-From an editor, create the sandbox once, from the project the editor will open:
66-
67-```bash
68-cd /path/to/your/project
69-sbx create --name mm-acp k33g/sbx-kit-mm-acp:0.2.1 . --kit-arg config=agent.dmr.yaml
70-```
71-
72-then register it — in Zed's `settings.json`:
73-
74-```json
75-{
76- "agent_servers": {
77- "mini-me (sandbox)": {
78- "type": "custom",
79- "command": "sbx",
80- "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
81- }
82- }
83-}
84-```
85-
86-**Kit arguments.** On a published kit only `config` can be set: `image` and `tag` are build-phase and were fixed when the kit was built, so a published kit always names the image it was built on. To use another mm version, take the kit of that version.
87-
88-| `--kit-arg` | Default | Phase | Effect |
89-|---|---|---|---|
90-| `config=<path>` | empty | create | The file mm reads (its `AGENT_CONFIG`): relative to the workspace, or absolute inside the sandbox. Empty: `./agent.yaml`, then the built-in defaults. |
91-| `tag=<version>` | mm's version (`0.2.1`) | build | Which `<image>:<tag>` the kit is built FROM; also the kit's version. No `v`. |
92-| `image=<repo>` | `k33g/mm-sandbox` | build | Which repository the kit is built FROM. |
93-
94-## 1. Build the template
95-
96-From the repository root:
97-
98-```bash
99-./docker-sbx-v3/build.sh # TAG from release.env: v0.2.1 → k33g/mm-sandbox:0.2.1, local store
100-PUSH=1 ./docker-sbx-v3/build.sh # multi-arch, pushed — needed before running a kit from source
101-```
102-
103-Same image, same rules as v2's `build.sh`; it then rewrites the kits' `image` and `tag` defaults (`sync-kits.sh`), so the kits always name the image just built.
104-
105-## 2. Check the kits without sbx
106-
107-```bash
108-./docker-sbx-v3/check-kits.sh # both kits
109-./docker-sbx-v3/check-kits.sh mm-tui # one
110-```
111-
112-Each kit is built with `docker buildx build -f <kit>.yaml`: the descriptor's first line, `# syntax=docker/sandbox-kit:3`, makes BuildKit pull the kit frontend, which validates the descriptor (unknown keys and arg patterns included), builds the companion Dockerfile and writes the published form to `tmp/kits-v3/<kit>/`. With [`kit-tck`](https://github.com/docker/sandbox-kit-spec) on the `PATH` (or `KIT_TCK=/path/to/kit-tck`), the result is also checked against the specification:
113-
114-```bash
115-git clone https://github.com/docker/sandbox-kit-spec && cd sandbox-kit-spec
116-go build -o ~/.local/bin/kit-tck ./cmd/kit-tck
117-```
118-
119-## 3. Run the kits from source
120-
121-With the template pushed (section 1):
122-
123-```bash
124-cd /path/to/your/project
125-sbx run /path/to/mini-me/docker-sbx-v3/kits/mm-tui . -- agent.dmr.yaml
126-sbx create --name mm-acp /path/to/mini-me/docker-sbx-v3/kits/mm-acp . --kit-arg config=agent.dmr.yaml
127-```
128-
129-sbx recognizes a v3 kit directory by its single `*.yaml` declaring `schemaVersion: "3"` (and no `spec.yaml`), builds it in its builder sandbox (`sbx kit builder status`), and caches the result by the directory's content. From source, the build-phase args can be set too: `--kit-arg tag=0.2.2`.
130-
131-## 4. Publishing a version
132-
133-```bash
134-export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
135-export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
136-./docker-sbx-v3/publish.sh # TAG from release.env: k33g/mm-sandbox:0.2.1, k33g/sbx-kit-mm-tui:0.2.1, k33g/sbx-kit-mm-acp:0.2.1
137-```
138-
139-It is two steps you can also run alone:
140-
141-```bash
142-PUSH=1 ./docker-sbx-v3/build.sh v0.2.1 # the image, multi-arch, pushed
143-./docker-sbx-v3/push-kits.sh v0.2.1 # the kits: buildx build --push, linux/amd64 + linux/arm64
144-```
145-
146-`push-kits.sh` refuses to start when the image is not on the registry yet, runs `sync-kits.sh`, then builds each kit with the `mm-sandbox-builder` buildx instance (created by `build.sh` if needed) with SBOM and provenance attestations, and validates the pushed kits with `kit-tck` when it is available. No `sbx` is needed to publish. `IMAGE_OWNER`, `REGISTRY`, `KIT_PREFIX` and `PLATFORMS` override the defaults. The descriptors end up naming the new version — commit them.
147-
148-## The model server stays on the host
149-
150-Unchanged from v2: inside a sandbox `localhost` is the sandbox itself, and Docker Model Runner or llama-server are reached through `host.docker.internal`. 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>`.
151-
152-## Status
153-
154-Checked here: both kits build with the `docker/sandbox-kit:3` frontend (3.0.0-m.6), single- and multi-arch with attestations, and pass `kit-tck validate` (18/18); the published config is `User: agent`, `Entrypoint: [mm-tui]` (or `[mm-acp-info]`), no `Cmd`, `WorkingDir: /home/agent/workspace`. Not yet checked: running them with `sbx` (`sbx run`, `sbx create`, `sbx exec -i … mm -acp`), and pushing to Docker Hub. The kit specification itself is still marked experimental.
deleted docker-sbx-v3/build.sh +0 -105
deleted file mode 100644
@@ -1,105 +0,0 @@
1-#!/usr/bin/env bash
2-# Build the mm sandbox template image, <owner>/mm-sandbox:<version>, from this
3-# checkout — the image both v3 kits are built FROM. The image tag follows mm's
4-# own tag, minus the "v": release.env says TAG="v0.2.1", the image is
5-# k33g/mm-sandbox:0.2.1 and `mm --version` inside it reports v0.2.1 — the
6-# same rule as the release assets.
7-#
8-# Usage:
9-# ./docker-sbx-v3/build.sh # TAG from release.env, image for this machine
10-# ./docker-sbx-v3/build.sh v0.2.2 # override the tag for this run
11-# PUSH=1 ./docker-sbx-v3/build.sh # multi-arch (linux/amd64 + linux/arm64) built
12-# # with buildx and PUSHED to the registry —
13-# # needs `docker login`; publish.sh does this
14-# IMAGE_OWNER=someone ./docker-sbx-v3/build.sh # another image owner (default k33g)
15-# PLATFORMS=linux/amd64 PUSH=1 … # narrower multi-arch set
16-# SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx-v3/build.sh
17-# # base it on the Docker-in-Docker shell
18-#
19-# Whatever the mode, the two kits under docker-sbx-v3/kits/ are then pointed
20-# at the image just built (docker-sbx-v3/sync-kits.sh), so kits and image move
21-# together. Publishing the kits themselves is docker-sbx-v3/push-kits.sh, and
22-# docker-sbx-v3/publish.sh chains the two.
23-#
24-# Unlike v2, a v3 kit is BUILT on top of this image (FROM), and sbx builds a
25-# source-form kit in its builder sandbox, whose Docker engine pulls from a
26-# registry: an image that is only in the local store is not enough for
27-# `sbx run ./docker-sbx-v3/kits/…`. Push it (PUSH=1) first.
28-set -euo pipefail
29-
30-cd "$(dirname "$0")/.."
31-
32-# release.env carries TAG ("v0.2.1"). It is git-ignored, so a checkout without
33-# it names the tag on the command line. A tag given on the command line wins.
34-if [ -f release.env ]; then
35- # shellcheck source=/dev/null
36- source release.env
37-fi
38-TAG="${1:-${TAG:-}}"
39-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
40- echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx-v3/build.sh v1.2.3)"
41- exit 1
42-fi
43-
44-# Not OWNER: release.env uses that name for the git owner (bots-garden), and
45-# the image owner is a different thing — the Docker Hub account, k33g.
46-IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
47-VERSION="${TAG#v}"
48-IMAGE="${IMAGE_OWNER}/mm-sandbox:${VERSION}"
49-PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
50-
51-build_args=(--build-arg "MM_VERSION=${TAG}")
52-if [ -n "${SHELL_TEMPLATE:-}" ]; then
53- build_args+=(--build-arg "SHELL_TEMPLATE=${SHELL_TEMPLATE}")
54-fi
55-
56-if [ -n "${PUSH:-}" ]; then
57- # Multi-arch needs buildx's container driver: the classic builder can
58- # neither assemble a manifest list nor build for a foreign platform. The
59- # Go stage cross-compiles on the build platform; only the final stage's
60- # `RUN mm --version` runs under emulation (Docker Desktop ships QEMU).
61- echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
62- if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
63- docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
64- fi
65- docker buildx build --builder mm-sandbox-builder \
66- --platform "${PLATFORMS}" \
67- -f docker-sbx-v3/template/Dockerfile "${build_args[@]}" \
68- -t "${IMAGE}" --push .
69- # The proof that ships: the registry holds one manifest per platform.
70- docker buildx imagetools inspect "${IMAGE}" | grep -E '^Name:|Platform:' | sed 's/^/ /'
71-else
72- echo "🐳 Building ${IMAGE} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
73- docker build -f docker-sbx-v3/template/Dockerfile "${build_args[@]}" -t "${IMAGE}" .
74-
75- # The one proof that what was built starts: --version needs no config and
76- # no model server. It also confirms the stamp reached the binary.
77- reported="$(docker run --rm "${IMAGE}" mm --version)"
78- if ! grep -q -- "${TAG}" <<<"${reported}"; then
79- echo "❌ the image does not report ${TAG}: ${reported}"
80- exit 1
81- fi
82- echo "✅ ${reported}"
83-fi
84-
85-./docker-sbx-v3/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
86-
87-if [ -n "${PUSH:-}" ]; then
88- cat <<NEXT
89-
90-Image on the registry. Next:
91-
92- try the kits from source sbx run ./docker-sbx-v3/kits/mm-tui . -- agent.dmr.yaml
93- publish them ./docker-sbx-v3/push-kits.sh ${TAG}
94-NEXT
95-else
96- cat <<NEXT
97-
98-${IMAGE} is in the local image store only. That is enough for
99-./docker-sbx-v3/check-kits.sh (which builds the kits with your docker), not
100-for sbx: its builder sandbox pulls the FROM image from the registry. To run
101-the kits from source with sbx, push the image first:
102-
103- PUSH=1 ./docker-sbx-v3/build.sh ${TAG}
104-NEXT
105-fi
deleted file mode 100644
@@ -1,105 +0,0 @@
1-#!/usr/bin/env bash
2-# Build the mm sandbox template image, <owner>/mm-sandbox:<version>, from this
3-# checkout — the image both v3 kits are built FROM. The image tag follows mm's
4-# own tag, minus the "v": release.env says TAG="v0.2.1", the image is
5-# k33g/mm-sandbox:0.2.1 and `mm --version` inside it reports v0.2.1 — the
6-# same rule as the release assets.
7-#
8-# Usage:
9-# ./docker-sbx-v3/build.sh # TAG from release.env, image for this machine
10-# ./docker-sbx-v3/build.sh v0.2.2 # override the tag for this run
11-# PUSH=1 ./docker-sbx-v3/build.sh # multi-arch (linux/amd64 + linux/arm64) built
12-# # with buildx and PUSHED to the registry —
13-# # needs `docker login`; publish.sh does this
14-# IMAGE_OWNER=someone ./docker-sbx-v3/build.sh # another image owner (default k33g)
15-# PLATFORMS=linux/amd64 PUSH=1 … # narrower multi-arch set
16-# SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx-v3/build.sh
17-# # base it on the Docker-in-Docker shell
18-#
19-# Whatever the mode, the two kits under docker-sbx-v3/kits/ are then pointed
20-# at the image just built (docker-sbx-v3/sync-kits.sh), so kits and image move
21-# together. Publishing the kits themselves is docker-sbx-v3/push-kits.sh, and
22-# docker-sbx-v3/publish.sh chains the two.
23-#
24-# Unlike v2, a v3 kit is BUILT on top of this image (FROM), and sbx builds a
25-# source-form kit in its builder sandbox, whose Docker engine pulls from a
26-# registry: an image that is only in the local store is not enough for
27-# `sbx run ./docker-sbx-v3/kits/…`. Push it (PUSH=1) first.
28-set -euo pipefail
29-
30-cd "$(dirname "$0")/.."
31-
32-# release.env carries TAG ("v0.2.1"). It is git-ignored, so a checkout without
33-# it names the tag on the command line. A tag given on the command line wins.
34-if [ -f release.env ]; then
35- # shellcheck source=/dev/null
36- source release.env
37-fi
38-TAG="${1:-${TAG:-}}"
39-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
40- echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx-v3/build.sh v1.2.3)"
41- exit 1
42-fi
43-
44-# Not OWNER: release.env uses that name for the git owner (bots-garden), and
45-# the image owner is a different thing — the Docker Hub account, k33g.
46-IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
47-VERSION="${TAG#v}"
48-IMAGE="${IMAGE_OWNER}/mm-sandbox:${VERSION}"
49-PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
50-
51-build_args=(--build-arg "MM_VERSION=${TAG}")
52-if [ -n "${SHELL_TEMPLATE:-}" ]; then
53- build_args+=(--build-arg "SHELL_TEMPLATE=${SHELL_TEMPLATE}")
54-fi
55-
56-if [ -n "${PUSH:-}" ]; then
57- # Multi-arch needs buildx's container driver: the classic builder can
58- # neither assemble a manifest list nor build for a foreign platform. The
59- # Go stage cross-compiles on the build platform; only the final stage's
60- # `RUN mm --version` runs under emulation (Docker Desktop ships QEMU).
61- echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
62- if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
63- docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
64- fi
65- docker buildx build --builder mm-sandbox-builder \
66- --platform "${PLATFORMS}" \
67- -f docker-sbx-v3/template/Dockerfile "${build_args[@]}" \
68- -t "${IMAGE}" --push .
69- # The proof that ships: the registry holds one manifest per platform.
70- docker buildx imagetools inspect "${IMAGE}" | grep -E '^Name:|Platform:' | sed 's/^/ /'
71-else
72- echo "🐳 Building ${IMAGE} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
73- docker build -f docker-sbx-v3/template/Dockerfile "${build_args[@]}" -t "${IMAGE}" .
74-
75- # The one proof that what was built starts: --version needs no config and
76- # no model server. It also confirms the stamp reached the binary.
77- reported="$(docker run --rm "${IMAGE}" mm --version)"
78- if ! grep -q -- "${TAG}" <<<"${reported}"; then
79- echo "❌ the image does not report ${TAG}: ${reported}"
80- exit 1
81- fi
82- echo "✅ ${reported}"
83-fi
84-
85-./docker-sbx-v3/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
86-
87-if [ -n "${PUSH:-}" ]; then
88- cat <<NEXT
89-
90-Image on the registry. Next:
91-
92- try the kits from source sbx run ./docker-sbx-v3/kits/mm-tui . -- agent.dmr.yaml
93- publish them ./docker-sbx-v3/push-kits.sh ${TAG}
94-NEXT
95-else
96- cat <<NEXT
97-
98-${IMAGE} is in the local image store only. That is enough for
99-./docker-sbx-v3/check-kits.sh (which builds the kits with your docker), not
100-for sbx: its builder sandbox pulls the FROM image from the registry. To run
101-the kits from source with sbx, push the image first:
102-
103- PUSH=1 ./docker-sbx-v3/build.sh ${TAG}
104-NEXT
105-fi
deleted docker-sbx-v3/check-kits.sh +0 -60
deleted file mode 100644
@@ -1,60 +0,0 @@
1-#!/usr/bin/env bash
2-# Build the two v3 kits locally, without pushing and without sbx, and check
3-# them against the kit specification when kit-tck is available.
4-#
5-# Usage:
6-# ./docker-sbx-v3/check-kits.sh # every kit under docker-sbx-v3/kits/
7-# ./docker-sbx-v3/check-kits.sh mm-tui # one kit
8-# KIT_TCK=/path/to/kit-tck … # the conformance tool, if not on the PATH
9-#
10-# Each kit is built with `docker buildx build -f <kit>.yaml`: the descriptor's
11-# first line, `# syntax=docker/sandbox-kit:3`, makes BuildKit pull the kit
12-# frontend, which validates the descriptor (arg patterns included), builds
13-# <kit>.dockerfile and writes the published form — an OCI image whose
14-# manifest annotation carries the descriptor. The result lands in
15-# tmp/kits-v3/<kit>/ as an OCI layout, for the host platform only.
16-#
17-# The args are the descriptors' defaults, so run build.sh (or sync-kits.sh)
18-# first to point them at the image you want. That image is resolved by your
19-# BuildKit: from the local store with Docker Desktop's default builder,
20-# otherwise from the registry.
21-#
22-# kit-tck is the specification's conformance tool
23-# (github.com/docker/sandbox-kit-spec, `go build ./cmd/kit-tck`). Without it
24-# the build itself is the check: the frontend refuses a descriptor that does
25-# not validate.
26-set -euo pipefail
27-
28-cd "$(dirname "$0")/.."
29-
30-KIT_TCK="${KIT_TCK:-kit-tck}"
31-if [ $# -gt 0 ]; then
32- kits=("$@")
33-else
34- kits=()
35- for dir in docker-sbx-v3/kits/*/; do
36- kits+=("$(basename "${dir}")")
37- done
38-fi
39-
40-for kit in "${kits[@]}"; do
41- dir="docker-sbx-v3/kits/${kit}"
42- if [ ! -f "${dir}/${kit}.yaml" ]; then
43- echo "❌ no kit named '${kit}': expected ${dir}/${kit}.yaml" >&2
44- exit 1
45- fi
46- out="tmp/kits-v3/${kit}"
47- rm -rf "${out}"
48- mkdir -p "$(dirname "${out}")"
49-
50- echo "🧰 ${kit}: building ${dir}/${kit}.yaml"
51- docker buildx build "${dir}" -f "${dir}/${kit}.yaml" \
52- --output "type=oci,dest=${out},tar=false,name=${kit}:check"
53-
54- if command -v "${KIT_TCK}" >/dev/null 2>&1; then
55- "${KIT_TCK}" validate --layout "${out}" check
56- else
57- echo " (kit-tck not found: built and validated by the frontend only)"
58- fi
59- echo "✅ ${kit} → ${out}"
60-done
deleted file mode 100644
@@ -1,60 +0,0 @@
1-#!/usr/bin/env bash
2-# Build the two v3 kits locally, without pushing and without sbx, and check
3-# them against the kit specification when kit-tck is available.
4-#
5-# Usage:
6-# ./docker-sbx-v3/check-kits.sh # every kit under docker-sbx-v3/kits/
7-# ./docker-sbx-v3/check-kits.sh mm-tui # one kit
8-# KIT_TCK=/path/to/kit-tck … # the conformance tool, if not on the PATH
9-#
10-# Each kit is built with `docker buildx build -f <kit>.yaml`: the descriptor's
11-# first line, `# syntax=docker/sandbox-kit:3`, makes BuildKit pull the kit
12-# frontend, which validates the descriptor (arg patterns included), builds
13-# <kit>.dockerfile and writes the published form — an OCI image whose
14-# manifest annotation carries the descriptor. The result lands in
15-# tmp/kits-v3/<kit>/ as an OCI layout, for the host platform only.
16-#
17-# The args are the descriptors' defaults, so run build.sh (or sync-kits.sh)
18-# first to point them at the image you want. That image is resolved by your
19-# BuildKit: from the local store with Docker Desktop's default builder,
20-# otherwise from the registry.
21-#
22-# kit-tck is the specification's conformance tool
23-# (github.com/docker/sandbox-kit-spec, `go build ./cmd/kit-tck`). Without it
24-# the build itself is the check: the frontend refuses a descriptor that does
25-# not validate.
26-set -euo pipefail
27-
28-cd "$(dirname "$0")/.."
29-
30-KIT_TCK="${KIT_TCK:-kit-tck}"
31-if [ $# -gt 0 ]; then
32- kits=("$@")
33-else
34- kits=()
35- for dir in docker-sbx-v3/kits/*/; do
36- kits+=("$(basename "${dir}")")
37- done
38-fi
39-
40-for kit in "${kits[@]}"; do
41- dir="docker-sbx-v3/kits/${kit}"
42- if [ ! -f "${dir}/${kit}.yaml" ]; then
43- echo "❌ no kit named '${kit}': expected ${dir}/${kit}.yaml" >&2
44- exit 1
45- fi
46- out="tmp/kits-v3/${kit}"
47- rm -rf "${out}"
48- mkdir -p "$(dirname "${out}")"
49-
50- echo "🧰 ${kit}: building ${dir}/${kit}.yaml"
51- docker buildx build "${dir}" -f "${dir}/${kit}.yaml" \
52- --output "type=oci,dest=${out},tar=false,name=${kit}:check"
53-
54- if command -v "${KIT_TCK}" >/dev/null 2>&1; then
55- "${KIT_TCK}" validate --layout "${out}" check
56- else
57- echo " (kit-tck not found: built and validated by the frontend only)"
58- fi
59- echo "✅ ${kit} → ${out}"
60-done
deleted docker-sbx-v3/kits/mm-acp/mm-acp.dockerfile +0 -20
deleted file mode 100644
@@ -1,20 +0,0 @@
1-# syntax=docker/dockerfile:1
2-# check=skip=InvalidDefaultArgInFrom
3-# Content of the mm-acp kit (descriptor: mm-acp.yaml). Same template image as
4-# mm-tui; only the launch contract differs. No default on purpose (hence the
5-# skipped check above): the frontend always passes the kit's `image` and `tag`
6-# args — see kits/mm-tui/mm-tui.dockerfile.
7-ARG MM_IMAGE
8-ARG MM_TAG
9-FROM ${MM_IMAGE}:${MM_TAG}
10-
11-# v2's environment.variables. `sbx exec` inherits the image environment, so
12-# the editor's settings need not repeat them. AGENT_CONFIG comes from the kit's
13-# `config` arg (env:).
14-ENV LANG=C.UTF-8
15-
16-# v2's sandbox.entrypoint. Not `mm -acp`: nothing useful comes of speaking
17-# JSON-RPC to a terminal. Attaching with `sbx run` prints the editor wiring
18-# with this sandbox's real name, then opens a shell; the editor itself runs
19-# `sbx exec -i <sandbox> mm -acp`.
20-ENTRYPOINT ["mm-acp-info"]
deleted file mode 100644
@@ -1,20 +0,0 @@
1-# syntax=docker/dockerfile:1
2-# check=skip=InvalidDefaultArgInFrom
3-# Content of the mm-acp kit (descriptor: mm-acp.yaml). Same template image as
4-# mm-tui; only the launch contract differs. No default on purpose (hence the
5-# skipped check above): the frontend always passes the kit's `image` and `tag`
6-# args — see kits/mm-tui/mm-tui.dockerfile.
7-ARG MM_IMAGE
8-ARG MM_TAG
9-FROM ${MM_IMAGE}:${MM_TAG}
10-
11-# v2's environment.variables. `sbx exec` inherits the image environment, so
12-# the editor's settings need not repeat them. AGENT_CONFIG comes from the kit's
13-# `config` arg (env:).
14-ENV LANG=C.UTF-8
15-
16-# v2's sandbox.entrypoint. Not `mm -acp`: nothing useful comes of speaking
17-# JSON-RPC to a terminal. Attaching with `sbx run` prints the editor wiring
18-# with this sandbox's real name, then opens a shell; the editor itself runs
19-# `sbx exec -i <sandbox> mm -acp`.
20-ENTRYPOINT ["mm-acp-info"]
deleted docker-sbx-v3/kits/mm-acp/mm-acp.yaml +0 -82
deleted file mode 100644
@@ -1,82 +0,0 @@
1-# syntax=docker/sandbox-kit:3
2-# yaml-language-server: $schema=https://raw.githubusercontent.com/docker/sandbox-kit-spec/main/schema/kit.schema.json
3-#
4-# Docker Sandboxes kit (spec v3): mm as an editor's agent (Agent Client
5-# Protocol), on the mm sandbox template. The v2 twin is
6-# docker-sbx/kits/mm-acp/spec.yaml.
7-#
8-# sbx create --name mm-acp ./docker-sbx-v3/kits/mm-acp . \
9-# --kit-arg config=agent.dmr.yaml
10-#
11-# then, in the editor (Zed settings.json):
12-#
13-# "agent_servers": { "mini-me (sandbox)": { "type": "custom",
14-# "command": "sbx", "args": ["exec", "-i", "mm-acp", "mm", "-acp"] } }
15-#
16-# Why `sbx exec -i` and not `sbx run`: an ACP client speaks JSON-RPC on the
17-# agent's raw stdin/stdout, and `sbx run` always allocates a terminal. So the
18-# sandbox is created without attaching, and the editor starts `mm -acp` inside
19-# it for every conversation (sbx starts a stopped sandbox first). Attaching
20-# with `sbx run` runs the entry point (mm-acp.dockerfile), which prints this
21-# wiring with the sandbox's real name and opens a shell.
22-#
23-# sbx builds this source form in its builder sandbox, whose own Docker engine
24-# PULLS the FROM image: <image>:<tag> must be on a registry, not only in the
25-# local image store (see docker-sbx-v3/README.md).
26-schemaVersion: "3"
27-kind: workload
28-displayName: Mini Me (editor, ACP)
29-description: >
30- Holds mm, a minimal coding agent for local LLMs, for an editor that speaks
31- the Agent Client Protocol (Zed, …). The editor runs `sbx exec -i <sandbox>
32- mm -acp`; every command and file edit the model asks for happens inside the
33- sandbox, on the mounted workspace. The model server stays on the host,
34- reached through host.docker.internal.
35-sourceUrl: https://git.rickub.com/bots-garden/mini-me
36-# The kit's version is mm's: the image tag it is built on. A published kit is
37-# versioned by its OCI tag anyway, which wins over this field.
38-version: "${{ kit.args.tag }}"
39-provides: ["mm@${{ kit.args.tag }}"]
40-
41-args:
42- # Build-phase (buildArg): see kits/mm-tui/mm-tui.yaml.
43- image:
44- default: "k33g/mm-sandbox"
45- description: >-
46- Repository of the mm sandbox template image, without the tag. Kept equal
47- to <owner>/mm-sandbox by docker-sbx-v3/sync-kits.sh.
48- pattern: '^[a-z0-9][a-z0-9._/:-]*$'
49- buildArg: MM_IMAGE
50- tag:
51- default: "0.2.6"
52- description: >-
53- Tag of the template image: mm's version without the "v", as
54- docker-sbx-v3/build.sh tags it (and rewrites this default to). Also the
55- kit's version, hence version-shaped.
56- pattern: '^[0-9]+(\.[0-9A-Za-z-]+)*$'
57- buildArg: MM_TAG
58- # Create-phase (env): baked into the container at `sbx create`, so
59- # `sbx exec` inherits it and the editor's settings need not repeat the path.
60- # `sbx exec -e AGENT_CONFIG=…` overrides it for one session.
61- config:
62- default: ""
63- description: >-
64- Configuration file mm reads (its AGENT_CONFIG): a path relative to the
65- workspace, which is where `sbx exec` starts mm, or an absolute path
66- inside the sandbox. Empty: ./agent.yaml in the workspace, then the
67- built-in defaults.
68- env: AGENT_CONFIG
69-
70-capabilities:
71- # A sandbox-agent workload — see kits/mm-tui/mm-tui.yaml.
72- - type: com.docker.sandbox/sbx@1
73-
74- # The model server on the host — see kits/mm-tui/mm-tui.yaml.
75- - type: com.docker.sandbox/network-policy@1
76- config:
77- runtime:
78- allow:
79- - "host.docker.internal:12434"
80- - "localhost:12434"
81- - "host.docker.internal:8080"
82- - "localhost:8080"
deleted file mode 100644
@@ -1,82 +0,0 @@
1-# syntax=docker/sandbox-kit:3
2-# yaml-language-server: $schema=https://raw.githubusercontent.com/docker/sandbox-kit-spec/main/schema/kit.schema.json
3-#
4-# Docker Sandboxes kit (spec v3): mm as an editor's agent (Agent Client
5-# Protocol), on the mm sandbox template. The v2 twin is
6-# docker-sbx/kits/mm-acp/spec.yaml.
7-#
8-# sbx create --name mm-acp ./docker-sbx-v3/kits/mm-acp . \
9-# --kit-arg config=agent.dmr.yaml
10-#
11-# then, in the editor (Zed settings.json):
12-#
13-# "agent_servers": { "mini-me (sandbox)": { "type": "custom",
14-# "command": "sbx", "args": ["exec", "-i", "mm-acp", "mm", "-acp"] } }
15-#
16-# Why `sbx exec -i` and not `sbx run`: an ACP client speaks JSON-RPC on the
17-# agent's raw stdin/stdout, and `sbx run` always allocates a terminal. So the
18-# sandbox is created without attaching, and the editor starts `mm -acp` inside
19-# it for every conversation (sbx starts a stopped sandbox first). Attaching
20-# with `sbx run` runs the entry point (mm-acp.dockerfile), which prints this
21-# wiring with the sandbox's real name and opens a shell.
22-#
23-# sbx builds this source form in its builder sandbox, whose own Docker engine
24-# PULLS the FROM image: <image>:<tag> must be on a registry, not only in the
25-# local image store (see docker-sbx-v3/README.md).
26-schemaVersion: "3"
27-kind: workload
28-displayName: Mini Me (editor, ACP)
29-description: >
30- Holds mm, a minimal coding agent for local LLMs, for an editor that speaks
31- the Agent Client Protocol (Zed, …). The editor runs `sbx exec -i <sandbox>
32- mm -acp`; every command and file edit the model asks for happens inside the
33- sandbox, on the mounted workspace. The model server stays on the host,
34- reached through host.docker.internal.
35-sourceUrl: https://git.rickub.com/bots-garden/mini-me
36-# The kit's version is mm's: the image tag it is built on. A published kit is
37-# versioned by its OCI tag anyway, which wins over this field.
38-version: "${{ kit.args.tag }}"
39-provides: ["mm@${{ kit.args.tag }}"]
40-
41-args:
42- # Build-phase (buildArg): see kits/mm-tui/mm-tui.yaml.
43- image:
44- default: "k33g/mm-sandbox"
45- description: >-
46- Repository of the mm sandbox template image, without the tag. Kept equal
47- to <owner>/mm-sandbox by docker-sbx-v3/sync-kits.sh.
48- pattern: '^[a-z0-9][a-z0-9._/:-]*$'
49- buildArg: MM_IMAGE
50- tag:
51- default: "0.2.6"
52- description: >-
53- Tag of the template image: mm's version without the "v", as
54- docker-sbx-v3/build.sh tags it (and rewrites this default to). Also the
55- kit's version, hence version-shaped.
56- pattern: '^[0-9]+(\.[0-9A-Za-z-]+)*$'
57- buildArg: MM_TAG
58- # Create-phase (env): baked into the container at `sbx create`, so
59- # `sbx exec` inherits it and the editor's settings need not repeat the path.
60- # `sbx exec -e AGENT_CONFIG=…` overrides it for one session.
61- config:
62- default: ""
63- description: >-
64- Configuration file mm reads (its AGENT_CONFIG): a path relative to the
65- workspace, which is where `sbx exec` starts mm, or an absolute path
66- inside the sandbox. Empty: ./agent.yaml in the workspace, then the
67- built-in defaults.
68- env: AGENT_CONFIG
69-
70-capabilities:
71- # A sandbox-agent workload — see kits/mm-tui/mm-tui.yaml.
72- - type: com.docker.sandbox/sbx@1
73-
74- # The model server on the host — see kits/mm-tui/mm-tui.yaml.
75- - type: com.docker.sandbox/network-policy@1
76- config:
77- runtime:
78- allow:
79- - "host.docker.internal:12434"
80- - "localhost:12434"
81- - "host.docker.internal:8080"
82- - "localhost:8080"
deleted docker-sbx-v3/kits/mm-tui/mm-tui.dockerfile +0 -25
deleted file mode 100644
@@ -1,25 +0,0 @@
1-# syntax=docker/dockerfile:1
2-# check=skip=InvalidDefaultArgInFrom
3-# Content of the mm-tui kit (descriptor: mm-tui.yaml). The kit's build context
4-# is this directory, so mm itself cannot be built here: the template image
5-# (docker-sbx-v3/template/Dockerfile, built from the repository root) carries
6-# mm, its wrappers and the toolchains, and this layer only sets the launch
7-# contract. No default on purpose (hence the skipped check above): the frontend
8-# always passes the kit's `image` and `tag` args, and a default here would be a
9-# second copy of the descriptor's to keep in sync.
10-ARG MM_IMAGE
11-ARG MM_TAG
12-FROM ${MM_IMAGE}:${MM_TAG}
13-
14-# v2's environment.variables. tcell needs a terminal type and a UTF-8 locale
15-# to draw the window. AGENT_CONFIG comes from the kit's `config` arg (env:).
16-ENV TERM=xterm-256color \
17- COLORTERM=truecolor \
18- LANG=C.UTF-8
19-
20-# v2's sandbox.entrypoint. A wrapper, not `mm -tui` directly: it always adds
21-# -tui, whatever the user passes after "--". Setting ENTRYPOINT also drops the
22-# base template's CMD, so the launch argv is exactly mm-tui + the user's args.
23-# USER (agent) and WORKDIR (/home/agent/workspace) are inherited from the
24-# template, which is what sbx@1 reads.
25-ENTRYPOINT ["mm-tui"]
deleted file mode 100644
@@ -1,25 +0,0 @@
1-# syntax=docker/dockerfile:1
2-# check=skip=InvalidDefaultArgInFrom
3-# Content of the mm-tui kit (descriptor: mm-tui.yaml). The kit's build context
4-# is this directory, so mm itself cannot be built here: the template image
5-# (docker-sbx-v3/template/Dockerfile, built from the repository root) carries
6-# mm, its wrappers and the toolchains, and this layer only sets the launch
7-# contract. No default on purpose (hence the skipped check above): the frontend
8-# always passes the kit's `image` and `tag` args, and a default here would be a
9-# second copy of the descriptor's to keep in sync.
10-ARG MM_IMAGE
11-ARG MM_TAG
12-FROM ${MM_IMAGE}:${MM_TAG}
13-
14-# v2's environment.variables. tcell needs a terminal type and a UTF-8 locale
15-# to draw the window. AGENT_CONFIG comes from the kit's `config` arg (env:).
16-ENV TERM=xterm-256color \
17- COLORTERM=truecolor \
18- LANG=C.UTF-8
19-
20-# v2's sandbox.entrypoint. A wrapper, not `mm -tui` directly: it always adds
21-# -tui, whatever the user passes after "--". Setting ENTRYPOINT also drops the
22-# base template's CMD, so the launch argv is exactly mm-tui + the user's args.
23-# USER (agent) and WORKDIR (/home/agent/workspace) are inherited from the
24-# template, which is what sbx@1 reads.
25-ENTRYPOINT ["mm-tui"]
deleted docker-sbx-v3/kits/mm-tui/mm-tui.yaml +0 -86
deleted file mode 100644
@@ -1,86 +0,0 @@
1-# syntax=docker/sandbox-kit:3
2-# yaml-language-server: $schema=https://raw.githubusercontent.com/docker/sandbox-kit-spec/main/schema/kit.schema.json
3-#
4-# Docker Sandboxes kit (spec v3): mm in its window mode, on the mm sandbox
5-# template. The v2 twin is docker-sbx/kits/mm-tui/spec.yaml.
6-#
7-# sbx run ./docker-sbx-v3/kits/mm-tui . -- agent.dmr.yaml
8-#
9-# What follows "--" reaches mm as its own arguments (here the configuration
10-# file, relative to the workspace). Without it, the `config` argument below is
11-# read, then ./agent.yaml, then the built-in defaults:
12-#
13-# sbx run ./docker-sbx-v3/kits/mm-tui . --kit-arg config=agent.dmr.yaml
14-#
15-# v3 layout: this file is the descriptor (declarations only), mm-tui.dockerfile
16-# beside it is the content. What v2 wrote in `sandbox.image`,
17-# `sandbox.entrypoint` and `environment.variables` is now in that Dockerfile's
18-# FROM, ENTRYPOINT and ENV — the descriptor restates nothing the image config
19-# already carries.
20-#
21-# sbx builds this source form in its builder sandbox, whose own Docker engine
22-# PULLS the FROM image: <image>:<tag> must be on a registry, not only in the
23-# local image store (see docker-sbx-v3/README.md).
24-schemaVersion: "3"
25-kind: workload
26-displayName: Mini Me (window mode)
27-description: >
28- Runs mm, a minimal coding agent for local LLMs, in its single-window terminal
29- mode (`mm -tui`) on the workspace. The model server (Docker Model Runner or
30- llama-server) stays on the host: inside the sandbox `localhost` is the sandbox
31- itself, so the configuration file must reach the host through
32- host.docker.internal — agent.dmr.yaml already falls back to it.
33-sourceUrl: https://git.rickub.com/bots-garden/mini-me
34-# The kit's version is mm's: the image tag it is built on. A published kit is
35-# versioned by its OCI tag anyway, which wins over this field.
36-version: "${{ kit.args.tag }}"
37-provides: ["mm@${{ kit.args.tag }}"]
38-
39-args:
40- # Build-phase (buildArg): resolved when the kit is built, handed to
41- # mm-tui.dockerfile as --build-arg, and baked into the published descriptor.
42- # A published kit therefore always names the image it was built on.
43- image:
44- default: "k33g/mm-sandbox"
45- description: >-
46- Repository of the mm sandbox template image, without the tag. Kept equal
47- to <owner>/mm-sandbox by docker-sbx-v3/sync-kits.sh.
48- pattern: '^[a-z0-9][a-z0-9._/:-]*$'
49- buildArg: MM_IMAGE
50- tag:
51- default: "0.2.6"
52- description: >-
53- Tag of the template image: mm's version without the "v", as
54- docker-sbx-v3/build.sh tags it (and rewrites this default to). Also the
55- kit's version, hence version-shaped.
56- pattern: '^[0-9]+(\.[0-9A-Za-z-]+)*$'
57- buildArg: MM_TAG
58- # Create-phase (env): resolved at `sbx run` / `sbx create`, exported to the
59- # container. Private otherwise — an arg without env: never reaches it.
60- config:
61- default: ""
62- description: >-
63- Configuration file mm reads (its AGENT_CONFIG): a path relative to the
64- workspace, or an absolute path inside the sandbox. Empty: ./agent.yaml in
65- the workspace, then the built-in defaults.
66- env: AGENT_CONFIG
67-
68-capabilities:
69- # A sandbox-agent workload: the host launches the image ENTRYPOINT (mm-tui)
70- # under bash as the image's user (agent), and mounts the workspace at the
71- # image's WORKDIR, /home/agent/workspace.
72- - type: com.docker.sandbox/sbx@1
73-
74- # The model server on the host. Requests leave the sandbox through its proxy,
75- # which maps host.docker.internal to the host's localhost; both spellings are
76- # listed so the rule matches whichever one the policy is checked against.
77- # 12434 is Docker Model Runner, 8080 is llama-server's default. Add your own
78- # port with `sbx policy allow network host.docker.internal:<port>`.
79- - type: com.docker.sandbox/network-policy@1
80- config:
81- runtime:
82- allow:
83- - "host.docker.internal:12434"
84- - "localhost:12434"
85- - "host.docker.internal:8080"
86- - "localhost:8080"
deleted file mode 100644
@@ -1,86 +0,0 @@
1-# syntax=docker/sandbox-kit:3
2-# yaml-language-server: $schema=https://raw.githubusercontent.com/docker/sandbox-kit-spec/main/schema/kit.schema.json
3-#
4-# Docker Sandboxes kit (spec v3): mm in its window mode, on the mm sandbox
5-# template. The v2 twin is docker-sbx/kits/mm-tui/spec.yaml.
6-#
7-# sbx run ./docker-sbx-v3/kits/mm-tui . -- agent.dmr.yaml
8-#
9-# What follows "--" reaches mm as its own arguments (here the configuration
10-# file, relative to the workspace). Without it, the `config` argument below is
11-# read, then ./agent.yaml, then the built-in defaults:
12-#
13-# sbx run ./docker-sbx-v3/kits/mm-tui . --kit-arg config=agent.dmr.yaml
14-#
15-# v3 layout: this file is the descriptor (declarations only), mm-tui.dockerfile
16-# beside it is the content. What v2 wrote in `sandbox.image`,
17-# `sandbox.entrypoint` and `environment.variables` is now in that Dockerfile's
18-# FROM, ENTRYPOINT and ENV — the descriptor restates nothing the image config
19-# already carries.
20-#
21-# sbx builds this source form in its builder sandbox, whose own Docker engine
22-# PULLS the FROM image: <image>:<tag> must be on a registry, not only in the
23-# local image store (see docker-sbx-v3/README.md).
24-schemaVersion: "3"
25-kind: workload
26-displayName: Mini Me (window mode)
27-description: >
28- Runs mm, a minimal coding agent for local LLMs, in its single-window terminal
29- mode (`mm -tui`) on the workspace. The model server (Docker Model Runner or
30- llama-server) stays on the host: inside the sandbox `localhost` is the sandbox
31- itself, so the configuration file must reach the host through
32- host.docker.internal — agent.dmr.yaml already falls back to it.
33-sourceUrl: https://git.rickub.com/bots-garden/mini-me
34-# The kit's version is mm's: the image tag it is built on. A published kit is
35-# versioned by its OCI tag anyway, which wins over this field.
36-version: "${{ kit.args.tag }}"
37-provides: ["mm@${{ kit.args.tag }}"]
38-
39-args:
40- # Build-phase (buildArg): resolved when the kit is built, handed to
41- # mm-tui.dockerfile as --build-arg, and baked into the published descriptor.
42- # A published kit therefore always names the image it was built on.
43- image:
44- default: "k33g/mm-sandbox"
45- description: >-
46- Repository of the mm sandbox template image, without the tag. Kept equal
47- to <owner>/mm-sandbox by docker-sbx-v3/sync-kits.sh.
48- pattern: '^[a-z0-9][a-z0-9._/:-]*$'
49- buildArg: MM_IMAGE
50- tag:
51- default: "0.2.6"
52- description: >-
53- Tag of the template image: mm's version without the "v", as
54- docker-sbx-v3/build.sh tags it (and rewrites this default to). Also the
55- kit's version, hence version-shaped.
56- pattern: '^[0-9]+(\.[0-9A-Za-z-]+)*$'
57- buildArg: MM_TAG
58- # Create-phase (env): resolved at `sbx run` / `sbx create`, exported to the
59- # container. Private otherwise — an arg without env: never reaches it.
60- config:
61- default: ""
62- description: >-
63- Configuration file mm reads (its AGENT_CONFIG): a path relative to the
64- workspace, or an absolute path inside the sandbox. Empty: ./agent.yaml in
65- the workspace, then the built-in defaults.
66- env: AGENT_CONFIG
67-
68-capabilities:
69- # A sandbox-agent workload: the host launches the image ENTRYPOINT (mm-tui)
70- # under bash as the image's user (agent), and mounts the workspace at the
71- # image's WORKDIR, /home/agent/workspace.
72- - type: com.docker.sandbox/sbx@1
73-
74- # The model server on the host. Requests leave the sandbox through its proxy,
75- # which maps host.docker.internal to the host's localhost; both spellings are
76- # listed so the rule matches whichever one the policy is checked against.
77- # 12434 is Docker Model Runner, 8080 is llama-server's default. Add your own
78- # port with `sbx policy allow network host.docker.internal:<port>`.
79- - type: com.docker.sandbox/network-policy@1
80- config:
81- runtime:
82- allow:
83- - "host.docker.internal:12434"
84- - "localhost:12434"
85- - "host.docker.internal:8080"
86- - "localhost:8080"
deleted docker-sbx-v3/publish.sh +0 -75
deleted file mode 100644
@@ -1,75 +0,0 @@
1-#!/usr/bin/env bash
2-# Build and publish everything to Docker Hub, by hand, in one go:
3-# <owner>/mm-sandbox:<version> the template image, linux/amd64 + linux/arm64
4-# <owner>/sbx-kit-mm-tui:<version> the window-mode kit (v3)
5-# <owner>/sbx-kit-mm-acp:<version> the editor (ACP) kit (v3)
6-#
7-# Usage:
8-# ./docker-sbx-v3/publish.sh # TAG from release.env (v0.2.1 → 0.2.1)
9-# ./docker-sbx-v3/publish.sh v0.2.2 # another tag
10-#
11-# Credentials, two environment variables:
12-# DOCKER_HANDLE the Docker Hub account — also the image owner (default k33g)
13-# DOCKER_PAT an access token with read/write scope
14-# With both set, the script logs in with them (and out at the end). With
15-# neither, it uses the login you already have (`docker login` done earlier).
16-#
17-# Needs: docker with buildx (Docker Desktop has it). No sbx: v3 kits are
18-# published with buildx. Pieces, runnable alone:
19-# PUSH=1 ./docker-sbx-v3/build.sh TAG image only
20-# ./docker-sbx-v3/push-kits.sh TAG kits only
21-set -euo pipefail
22-
23-cd "$(dirname "$0")/.."
24-
25-if [ -f release.env ]; then
26- # shellcheck source=/dev/null
27- source release.env
28-fi
29-TAG="${1:-${TAG:-}}"
30-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
31- echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx-v3/publish.sh v1.2.3)"
32- exit 1
33-fi
34-
35-# Secrets pasted with a trailing newline or stray spaces are a classic.
36-DOCKER_HANDLE="$(printf '%s' "${DOCKER_HANDLE:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
37-DOCKER_PAT="$(printf '%s' "${DOCKER_PAT:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
38-case "${DOCKER_HANDLE}" in
39-*@* | *:*)
40- echo "❌ DOCKER_HANDLE must be the Docker ID (username), not an e-mail: access tokens only pair with the username"
41- exit 1
42- ;;
43-esac
44-export IMAGE_OWNER="${IMAGE_OWNER:-${DOCKER_HANDLE:-k33g}}"
45-VERSION="${TAG#v}"
46-
47-logged_in_here=""
48-if [ -n "${DOCKER_HANDLE}" ] && [ -n "${DOCKER_PAT}" ]; then
49- echo "🔐 docker login as ${DOCKER_HANDLE}"
50- printf '%s' "${DOCKER_PAT}" | docker login --username "${DOCKER_HANDLE}" --password-stdin
51- logged_in_here=1
52-elif [ -n "${DOCKER_HANDLE}${DOCKER_PAT}" ]; then
53- echo "❌ set both DOCKER_HANDLE and DOCKER_PAT, or neither (to reuse an existing docker login)"
54- exit 1
55-else
56- echo "🔐 no DOCKER_HANDLE/DOCKER_PAT: using the existing docker login, publishing under ${IMAGE_OWNER}"
57-fi
58-# Whatever happens below, a login made here does not outlive the script.
59-cleanup() {
60- if [ -n "${logged_in_here}" ]; then
61- docker logout >/dev/null 2>&1 || true
62- fi
63-}
64-trap cleanup EXIT
65-
66-echo
67-echo "═══ 1/2 image ${IMAGE_OWNER}/mm-sandbox:${VERSION}"
68-PUSH=1 ./docker-sbx-v3/build.sh "${TAG}"
69-
70-echo
71-echo "═══ 2/2 kits ${IMAGE_OWNER}/${KIT_PREFIX:-sbx-kit-}mm-tui:${VERSION} and ${IMAGE_OWNER}/${KIT_PREFIX:-sbx-kit-}mm-acp:${VERSION}"
72-./docker-sbx-v3/push-kits.sh "${TAG}"
73-
74-echo
75-echo "✨ Published ${TAG}. The kits' descriptors now name version ${VERSION} — commit them."
deleted file mode 100644
@@ -1,75 +0,0 @@
1-#!/usr/bin/env bash
2-# Build and publish everything to Docker Hub, by hand, in one go:
3-# <owner>/mm-sandbox:<version> the template image, linux/amd64 + linux/arm64
4-# <owner>/sbx-kit-mm-tui:<version> the window-mode kit (v3)
5-# <owner>/sbx-kit-mm-acp:<version> the editor (ACP) kit (v3)
6-#
7-# Usage:
8-# ./docker-sbx-v3/publish.sh # TAG from release.env (v0.2.1 → 0.2.1)
9-# ./docker-sbx-v3/publish.sh v0.2.2 # another tag
10-#
11-# Credentials, two environment variables:
12-# DOCKER_HANDLE the Docker Hub account — also the image owner (default k33g)
13-# DOCKER_PAT an access token with read/write scope
14-# With both set, the script logs in with them (and out at the end). With
15-# neither, it uses the login you already have (`docker login` done earlier).
16-#
17-# Needs: docker with buildx (Docker Desktop has it). No sbx: v3 kits are
18-# published with buildx. Pieces, runnable alone:
19-# PUSH=1 ./docker-sbx-v3/build.sh TAG image only
20-# ./docker-sbx-v3/push-kits.sh TAG kits only
21-set -euo pipefail
22-
23-cd "$(dirname "$0")/.."
24-
25-if [ -f release.env ]; then
26- # shellcheck source=/dev/null
27- source release.env
28-fi
29-TAG="${1:-${TAG:-}}"
30-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
31- echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx-v3/publish.sh v1.2.3)"
32- exit 1
33-fi
34-
35-# Secrets pasted with a trailing newline or stray spaces are a classic.
36-DOCKER_HANDLE="$(printf '%s' "${DOCKER_HANDLE:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
37-DOCKER_PAT="$(printf '%s' "${DOCKER_PAT:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
38-case "${DOCKER_HANDLE}" in
39-*@* | *:*)
40- echo "❌ DOCKER_HANDLE must be the Docker ID (username), not an e-mail: access tokens only pair with the username"
41- exit 1
42- ;;
43-esac
44-export IMAGE_OWNER="${IMAGE_OWNER:-${DOCKER_HANDLE:-k33g}}"
45-VERSION="${TAG#v}"
46-
47-logged_in_here=""
48-if [ -n "${DOCKER_HANDLE}" ] && [ -n "${DOCKER_PAT}" ]; then
49- echo "🔐 docker login as ${DOCKER_HANDLE}"
50- printf '%s' "${DOCKER_PAT}" | docker login --username "${DOCKER_HANDLE}" --password-stdin
51- logged_in_here=1
52-elif [ -n "${DOCKER_HANDLE}${DOCKER_PAT}" ]; then
53- echo "❌ set both DOCKER_HANDLE and DOCKER_PAT, or neither (to reuse an existing docker login)"
54- exit 1
55-else
56- echo "🔐 no DOCKER_HANDLE/DOCKER_PAT: using the existing docker login, publishing under ${IMAGE_OWNER}"
57-fi
58-# Whatever happens below, a login made here does not outlive the script.
59-cleanup() {
60- if [ -n "${logged_in_here}" ]; then
61- docker logout >/dev/null 2>&1 || true
62- fi
63-}
64-trap cleanup EXIT
65-
66-echo
67-echo "═══ 1/2 image ${IMAGE_OWNER}/mm-sandbox:${VERSION}"
68-PUSH=1 ./docker-sbx-v3/build.sh "${TAG}"
69-
70-echo
71-echo "═══ 2/2 kits ${IMAGE_OWNER}/${KIT_PREFIX:-sbx-kit-}mm-tui:${VERSION} and ${IMAGE_OWNER}/${KIT_PREFIX:-sbx-kit-}mm-acp:${VERSION}"
72-./docker-sbx-v3/push-kits.sh "${TAG}"
73-
74-echo
75-echo "✨ Published ${TAG}. The kits' descriptors now name version ${VERSION} — commit them."
deleted docker-sbx-v3/push-kits.sh +0 -94
deleted file mode 100644
@@ -1,94 +0,0 @@
1-#!/usr/bin/env bash
2-# Build and publish the two v3 kits to Docker Hub:
3-# <owner>/sbx-kit-mm-tui:<version> and <owner>/sbx-kit-mm-acp:<version>
4-#
5-# Usage:
6-# ./docker-sbx-v3/push-kits.sh # TAG from release.env
7-# ./docker-sbx-v3/push-kits.sh v0.2.2 # override the tag
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-# KIT_PREFIX=mm-v3- … # repository prefix (default sbx-kit-)
12-# PLATFORMS=linux/amd64 … # narrower multi-arch set
13-#
14-# A v3 kit is an ordinary OCI image, so publishing is a buildx build: the
15-# descriptor's `# syntax=docker/sandbox-kit:3` line makes BuildKit run the kit
16-# frontend, which validates the descriptor, builds the companion Dockerfile
17-# FROM <owner>/mm-sandbox:<version> and pushes one image per platform with the
18-# descriptor in its manifest annotations. No sbx needed (v2 used
19-# `sbx kit push`, which only knows spec.yaml).
20-#
21-# The repositories are sbx-kit-<kit>, the naming Docker's own kits use, and
22-# NOT the v2 ones (<owner>/mm-tui, <owner>/mm-acp): pushing a v3 kit there at
23-# the same version would replace the published v2 kit.
24-#
25-# Needs a login: `docker login -u <handle>` with a Docker Hub access token.
26-# publish.sh runs this after the image. Push the image first: the kits are
27-# built FROM <owner>/mm-sandbox:<version>, pulled from the registry.
28-set -euo pipefail
29-
30-cd "$(dirname "$0")/.."
31-
32-if [ -f release.env ]; then
33- # shellcheck source=/dev/null
34- source release.env
35-fi
36-TAG="${1:-${TAG:-}}"
37-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
38- echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx-v3/push-kits.sh v1.2.3)"
39- exit 1
40-fi
41-
42-IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
43-REGISTRY="${REGISTRY:-docker.io}"
44-KIT_PREFIX="${KIT_PREFIX:-sbx-kit-}"
45-PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
46-VERSION="${TAG#v}"
47-IMAGE="${IMAGE_OWNER}/mm-sandbox:${VERSION}"
48-
49-# Fail here rather than in the middle of a multi-arch build.
50-if ! docker buildx imagetools inspect "${IMAGE}" >/dev/null 2>&1; then
51- echo "❌ ${IMAGE} is not on the registry: the kits are built FROM it. Push it first: PUSH=1 ./docker-sbx-v3/build.sh ${TAG}"
52- exit 1
53-fi
54-
55-./docker-sbx-v3/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
56-
57-# Same builder as build.sh: multi-arch needs the container driver.
58-if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
59- docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
60-fi
61-
62-refs=()
63-for dir in docker-sbx-v3/kits/*/; do
64- kit="$(basename "${dir}")"
65- ref="${REGISTRY}/${IMAGE_OWNER}/${KIT_PREFIX}${kit}:${VERSION}"
66- echo "🧰 ${kit} → ${ref}"
67- # The build args are the kit's own arg names; the frontend validates them
68- # against the descriptor and hands the Dockerfile the declared buildArg.
69- # They repeat what sync-kits.sh just wrote, so the file and the push agree.
70- docker buildx build --builder mm-sandbox-builder "${dir}" -f "${dir}${kit}.yaml" \
71- --build-arg "image=${IMAGE_OWNER}/mm-sandbox" \
72- --build-arg "tag=${VERSION}" \
73- --platform "${PLATFORMS}" \
74- --provenance=true --sbom=true \
75- -t "${ref}" --push
76- docker buildx imagetools inspect "${ref}" | grep -E '^Name:|Platform:' | sed 's/^/ /'
77- refs+=("${ref}")
78-done
79-
80-# The specification's own check of what was pushed, when available.
81-if command -v "${KIT_TCK:-kit-tck}" >/dev/null 2>&1; then
82- for ref in "${refs[@]}"; do
83- "${KIT_TCK:-kit-tck}" validate "${ref}"
84- done
85-fi
86-
87-cat <<NEXT
88-
89-Published. From any machine with Docker Sandboxes (docker.io is an allowed kit source by default):
90-
91- window mode sbx run ${IMAGE_OWNER}/${KIT_PREFIX}mm-tui:${VERSION} . -- agent.dmr.yaml
92- editor (ACP) sbx create --name mm-acp ${IMAGE_OWNER}/${KIT_PREFIX}mm-acp:${VERSION} . --kit-arg config=agent.dmr.yaml
93- then register sbx exec -i mm-acp mm -acp in the editor
94-NEXT
deleted file mode 100644
@@ -1,94 +0,0 @@
1-#!/usr/bin/env bash
2-# Build and publish the two v3 kits to Docker Hub:
3-# <owner>/sbx-kit-mm-tui:<version> and <owner>/sbx-kit-mm-acp:<version>
4-#
5-# Usage:
6-# ./docker-sbx-v3/push-kits.sh # TAG from release.env
7-# ./docker-sbx-v3/push-kits.sh v0.2.2 # override the tag
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-# KIT_PREFIX=mm-v3- … # repository prefix (default sbx-kit-)
12-# PLATFORMS=linux/amd64 … # narrower multi-arch set
13-#
14-# A v3 kit is an ordinary OCI image, so publishing is a buildx build: the
15-# descriptor's `# syntax=docker/sandbox-kit:3` line makes BuildKit run the kit
16-# frontend, which validates the descriptor, builds the companion Dockerfile
17-# FROM <owner>/mm-sandbox:<version> and pushes one image per platform with the
18-# descriptor in its manifest annotations. No sbx needed (v2 used
19-# `sbx kit push`, which only knows spec.yaml).
20-#
21-# The repositories are sbx-kit-<kit>, the naming Docker's own kits use, and
22-# NOT the v2 ones (<owner>/mm-tui, <owner>/mm-acp): pushing a v3 kit there at
23-# the same version would replace the published v2 kit.
24-#
25-# Needs a login: `docker login -u <handle>` with a Docker Hub access token.
26-# publish.sh runs this after the image. Push the image first: the kits are
27-# built FROM <owner>/mm-sandbox:<version>, pulled from the registry.
28-set -euo pipefail
29-
30-cd "$(dirname "$0")/.."
31-
32-if [ -f release.env ]; then
33- # shellcheck source=/dev/null
34- source release.env
35-fi
36-TAG="${1:-${TAG:-}}"
37-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
38- echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx-v3/push-kits.sh v1.2.3)"
39- exit 1
40-fi
41-
42-IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
43-REGISTRY="${REGISTRY:-docker.io}"
44-KIT_PREFIX="${KIT_PREFIX:-sbx-kit-}"
45-PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
46-VERSION="${TAG#v}"
47-IMAGE="${IMAGE_OWNER}/mm-sandbox:${VERSION}"
48-
49-# Fail here rather than in the middle of a multi-arch build.
50-if ! docker buildx imagetools inspect "${IMAGE}" >/dev/null 2>&1; then
51- echo "❌ ${IMAGE} is not on the registry: the kits are built FROM it. Push it first: PUSH=1 ./docker-sbx-v3/build.sh ${TAG}"
52- exit 1
53-fi
54-
55-./docker-sbx-v3/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
56-
57-# Same builder as build.sh: multi-arch needs the container driver.
58-if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
59- docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
60-fi
61-
62-refs=()
63-for dir in docker-sbx-v3/kits/*/; do
64- kit="$(basename "${dir}")"
65- ref="${REGISTRY}/${IMAGE_OWNER}/${KIT_PREFIX}${kit}:${VERSION}"
66- echo "🧰 ${kit} → ${ref}"
67- # The build args are the kit's own arg names; the frontend validates them
68- # against the descriptor and hands the Dockerfile the declared buildArg.
69- # They repeat what sync-kits.sh just wrote, so the file and the push agree.
70- docker buildx build --builder mm-sandbox-builder "${dir}" -f "${dir}${kit}.yaml" \
71- --build-arg "image=${IMAGE_OWNER}/mm-sandbox" \
72- --build-arg "tag=${VERSION}" \
73- --platform "${PLATFORMS}" \
74- --provenance=true --sbom=true \
75- -t "${ref}" --push
76- docker buildx imagetools inspect "${ref}" | grep -E '^Name:|Platform:' | sed 's/^/ /'
77- refs+=("${ref}")
78-done
79-
80-# The specification's own check of what was pushed, when available.
81-if command -v "${KIT_TCK:-kit-tck}" >/dev/null 2>&1; then
82- for ref in "${refs[@]}"; do
83- "${KIT_TCK:-kit-tck}" validate "${ref}"
84- done
85-fi
86-
87-cat <<NEXT
88-
89-Published. From any machine with Docker Sandboxes (docker.io is an allowed kit source by default):
90-
91- window mode sbx run ${IMAGE_OWNER}/${KIT_PREFIX}mm-tui:${VERSION} . -- agent.dmr.yaml
92- editor (ACP) sbx create --name mm-acp ${IMAGE_OWNER}/${KIT_PREFIX}mm-acp:${VERSION} . --kit-arg config=agent.dmr.yaml
93- then register sbx exec -i mm-acp mm -acp in the editor
94-NEXT
deleted docker-sbx-v3/sync-kits.sh +0 -44
deleted file mode 100644
@@ -1,44 +0,0 @@
1-#!/usr/bin/env bash
2-# Point the two v3 kits at one image: <owner>/mm-sandbox:<version>.
3-#
4-# Usage: ./docker-sbx-v3/sync-kits.sh OWNER VERSION (e.g. k33g 0.2.1)
5-#
6-# Rewrites, in docker-sbx-v3/kits/*/*.yaml (the descriptors), only two values:
7-# args.image.default: "<owner>/mm-sandbox" which repository the kit is built FROM
8-# args.tag.default: "<version>" which tag — and the kit's version,
9-# since `version:` and `provides:`
10-# reference ${{ kit.args.tag }}
11-# Everything else — comments included — is left byte-for-byte alone, so a
12-# kit that already matches is not changed at all. build.sh and push-kits.sh
13-# call this, so the kits always name the image just built or pushed.
14-set -euo pipefail
15-
16-if [ $# -ne 2 ]; then
17- echo "usage: $0 OWNER VERSION" >&2
18- exit 2
19-fi
20-OWNER="$1"
21-VERSION="$2"
22-
23-# The kits' `tag` arg is also their version, so it carries the spec's version
24-# grammar: dotted segments, no "v" (the frontend refuses anything else).
25-if ! [[ "${VERSION}" =~ ^[0-9]+(\.[0-9A-Za-z-]+)*$ ]]; then
26- echo "❌ VERSION must be version-shaped without a \"v\" (0.2.1, 0.2.2-rc.1), got '${VERSION}'" >&2
27- exit 2
28-fi
29-
30-cd "$(dirname "$0")/.."
31-
32-for kit in docker-sbx-v3/kits/*/*.yaml; do
33- if ! grep -q '^ image:$' "${kit}" || ! grep -q '^ tag:$' "${kit}"; then
34- echo "❌ ${kit}: expected an 'args.image' and an 'args.tag' — not updated" >&2
35- exit 1
36- fi
37- # sed -i.bak works on both GNU and BSD sed; the backup is removed at once.
38- sed -i.bak -E \
39- -e "/^ image:\$/,/^ default:/ s|^( default: )\"[^\"/]*(/mm-sandbox)\"|\1\"${OWNER}\2\"|" \
40- -e "/^ tag:\$/,/^ default:/ s|^( default: )\"[^\"]*\"|\1\"${VERSION}\"|" \
41- "${kit}"
42- rm -f "${kit}.bak"
43- echo "✅ ${kit} → image ${OWNER}/mm-sandbox, tag (and version) \"${VERSION}\""
44-done
deleted file mode 100644
@@ -1,44 +0,0 @@
1-#!/usr/bin/env bash
2-# Point the two v3 kits at one image: <owner>/mm-sandbox:<version>.
3-#
4-# Usage: ./docker-sbx-v3/sync-kits.sh OWNER VERSION (e.g. k33g 0.2.1)
5-#
6-# Rewrites, in docker-sbx-v3/kits/*/*.yaml (the descriptors), only two values:
7-# args.image.default: "<owner>/mm-sandbox" which repository the kit is built FROM
8-# args.tag.default: "<version>" which tag — and the kit's version,
9-# since `version:` and `provides:`
10-# reference ${{ kit.args.tag }}
11-# Everything else — comments included — is left byte-for-byte alone, so a
12-# kit that already matches is not changed at all. build.sh and push-kits.sh
13-# call this, so the kits always name the image just built or pushed.
14-set -euo pipefail
15-
16-if [ $# -ne 2 ]; then
17- echo "usage: $0 OWNER VERSION" >&2
18- exit 2
19-fi
20-OWNER="$1"
21-VERSION="$2"
22-
23-# The kits' `tag` arg is also their version, so it carries the spec's version
24-# grammar: dotted segments, no "v" (the frontend refuses anything else).
25-if ! [[ "${VERSION}" =~ ^[0-9]+(\.[0-9A-Za-z-]+)*$ ]]; then
26- echo "❌ VERSION must be version-shaped without a \"v\" (0.2.1, 0.2.2-rc.1), got '${VERSION}'" >&2
27- exit 2
28-fi
29-
30-cd "$(dirname "$0")/.."
31-
32-for kit in docker-sbx-v3/kits/*/*.yaml; do
33- if ! grep -q '^ image:$' "${kit}" || ! grep -q '^ tag:$' "${kit}"; then
34- echo "❌ ${kit}: expected an 'args.image' and an 'args.tag' — not updated" >&2
35- exit 1
36- fi
37- # sed -i.bak works on both GNU and BSD sed; the backup is removed at once.
38- sed -i.bak -E \
39- -e "/^ image:\$/,/^ default:/ s|^( default: )\"[^\"/]*(/mm-sandbox)\"|\1\"${OWNER}\2\"|" \
40- -e "/^ tag:\$/,/^ default:/ s|^( default: )\"[^\"]*\"|\1\"${VERSION}\"|" \
41- "${kit}"
42- rm -f "${kit}.bak"
43- echo "✅ ${kit} → image ${OWNER}/mm-sandbox, tag (and version) \"${VERSION}\""
44-done
deleted docker-sbx-v3/template/Dockerfile +0 -143
deleted file mode 100644
@@ -1,143 +0,0 @@
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-v3/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-v3/template/Dockerfile \
10-# --build-arg MM_VERSION=v0.0.2 -t k33g/mm-sandbox:0.0.2 .
11-#
12-# The two v3 kits under docker-sbx-v3/kits/ are thin workloads built FROM this
13-# image: each one sets its own ENTRYPOINT (mm-tui, mm-acp-info), which the
14-# sandbox runtime reads as the agent's launch command (sbx@1). ENTRYPOINT and
15-# CMD are therefore deliberately not set here: the template stays agnostic.
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-v3/README.md).
44-COPY --chmod=0755 docker-sbx-v3/template/mm-tui docker-sbx-v3/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-# The pinned toolchains (/usr/local/go/bin, /usr/local/node/bin) must come
53-# before /usr/bin so they win over any Go or Node the base image ships.
54-ENV PATH=/usr/local/go/bin:/usr/local/node/bin:/home/agent/go/bin:$PATH
55-
56-# Without this, a go.mod whose `go` directive is newer than GO_VERSION makes the
57-# toolchain download and run a different Go, silently defeating the pin.
58-ENV GOTOOLCHAIN=local
59-
60-# ------------------------------------
61-# Shared curl options for every download below.
62-#
63-# ARG, not ENV: this is build-time only and must not leak into the image.
64-# ------------------------------------
65-ARG CURL_RETRY="--retry 5 --retry-all-errors --retry-delay 3 --connect-timeout 15"
66-
67-USER root
68-
69-# ------------------------------------
70-# Install Go toolchain and Node.js
71-# ------------------------------------
72-ARG GO_VERSION=1.26.0
73-ARG NODE_VERSION=24.21.0
74-ARG TARGETARCH
75-
76-RUN <<EOF
77-set -eux
78-apt-get update
79-apt-get install -y curl build-essential xz-utils
80-rm -rf /var/lib/apt/lists/*
81-EOF
82-
83-RUN <<EOF
84-set -eux
85-apt-get remove -y golang-go golang-doc
86-apt-get autoremove -y
87-curl ${CURL_RETRY} -C - -fsSL -o /tmp/go.tgz "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz"
88-rm -rf /usr/local/go
89-tar -C /usr/local -xzf /tmp/go.tgz
90-rm /tmp/go.tgz
91-/usr/local/go/bin/go version
92-EOF
93-
94-RUN <<EOF
95-set -eux
96-case "${TARGETARCH}" in
97- amd64) node_arch=x64 ;;
98- arm64) node_arch=arm64 ;;
99- *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;;
100-esac
101-curl ${CURL_RETRY} -C - -fsSL -o /tmp/node.tar.xz "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${node_arch}.tar.xz"
102-rm -rf /usr/local/node
103-mkdir -p /usr/local/node
104-tar -C /usr/local/node --strip-components=1 -xJf /tmp/node.tar.xz
105-rm /tmp/node.tar.xz
106-/usr/local/node/bin/node --version
107-/usr/local/node/bin/npm --version
108-EOF
109-
110-# ------------------------------------
111-# Persist the Go and Node environment for sandbox shells.
112-# /etc/sandbox-persistent.sh is sourced before every bash command in the sbx.
113-# ------------------------------------
114-RUN <<EOF
115-{
116- echo 'export PATH=/usr/local/go/bin:/usr/local/node/bin:/home/agent/go/bin:$PATH'
117- echo 'export GOTOOLCHAIN=local'
118-} >> /etc/sandbox-persistent.sh
119-EOF
120-
121-# Switch to agent user for Go tools installation (they go to /home/agent/go/bin)
122-USER agent
123-
124-# ------------------------------------
125-# Install Go developer tools
126-# ------------------------------------
127-ARG GOPLS_VERSION=v0.23.0
128-ARG X_TOOLS_VERSION=v0.49.0
129-ARG STATICCHECK_VERSION=v0.7.0
130-
131-# Retried: parallel multi-arch builds occasionally hit DNS timeouts on
132-# Docker Desktop's resolver. The module cache survives within this RUN,
133-# so a retry only fetches what's still missing.
134-RUN for i in 1 2 3 4 5; do \
135- go install golang.org/x/tools/gopls@${GOPLS_VERSION} \
136- && go install golang.org/x/tools/cmd/goimports@${X_TOOLS_VERSION} \
137- && go install honnef.co/go/tools/cmd/staticcheck@${STATICCHECK_VERSION} \
138- && exit 0; \
139- echo "go install failed (attempt $i), retrying..." >&2; sleep $((i * 5)); \
140- done; exit 1
141-
142-# Prove the binary runs on this platform before the image is tagged.
143-RUN mm --version && mm-tui --version
deleted file mode 100644
@@ -1,143 +0,0 @@
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-v3/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-v3/template/Dockerfile \
10-# --build-arg MM_VERSION=v0.0.2 -t k33g/mm-sandbox:0.0.2 .
11-#
12-# The two v3 kits under docker-sbx-v3/kits/ are thin workloads built FROM this
13-# image: each one sets its own ENTRYPOINT (mm-tui, mm-acp-info), which the
14-# sandbox runtime reads as the agent's launch command (sbx@1). ENTRYPOINT and
15-# CMD are therefore deliberately not set here: the template stays agnostic.
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-v3/README.md).
44-COPY --chmod=0755 docker-sbx-v3/template/mm-tui docker-sbx-v3/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-# The pinned toolchains (/usr/local/go/bin, /usr/local/node/bin) must come
53-# before /usr/bin so they win over any Go or Node the base image ships.
54-ENV PATH=/usr/local/go/bin:/usr/local/node/bin:/home/agent/go/bin:$PATH
55-
56-# Without this, a go.mod whose `go` directive is newer than GO_VERSION makes the
57-# toolchain download and run a different Go, silently defeating the pin.
58-ENV GOTOOLCHAIN=local
59-
60-# ------------------------------------
61-# Shared curl options for every download below.
62-#
63-# ARG, not ENV: this is build-time only and must not leak into the image.
64-# ------------------------------------
65-ARG CURL_RETRY="--retry 5 --retry-all-errors --retry-delay 3 --connect-timeout 15"
66-
67-USER root
68-
69-# ------------------------------------
70-# Install Go toolchain and Node.js
71-# ------------------------------------
72-ARG GO_VERSION=1.26.0
73-ARG NODE_VERSION=24.21.0
74-ARG TARGETARCH
75-
76-RUN <<EOF
77-set -eux
78-apt-get update
79-apt-get install -y curl build-essential xz-utils
80-rm -rf /var/lib/apt/lists/*
81-EOF
82-
83-RUN <<EOF
84-set -eux
85-apt-get remove -y golang-go golang-doc
86-apt-get autoremove -y
87-curl ${CURL_RETRY} -C - -fsSL -o /tmp/go.tgz "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz"
88-rm -rf /usr/local/go
89-tar -C /usr/local -xzf /tmp/go.tgz
90-rm /tmp/go.tgz
91-/usr/local/go/bin/go version
92-EOF
93-
94-RUN <<EOF
95-set -eux
96-case "${TARGETARCH}" in
97- amd64) node_arch=x64 ;;
98- arm64) node_arch=arm64 ;;
99- *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;;
100-esac
101-curl ${CURL_RETRY} -C - -fsSL -o /tmp/node.tar.xz "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${node_arch}.tar.xz"
102-rm -rf /usr/local/node
103-mkdir -p /usr/local/node
104-tar -C /usr/local/node --strip-components=1 -xJf /tmp/node.tar.xz
105-rm /tmp/node.tar.xz
106-/usr/local/node/bin/node --version
107-/usr/local/node/bin/npm --version
108-EOF
109-
110-# ------------------------------------
111-# Persist the Go and Node environment for sandbox shells.
112-# /etc/sandbox-persistent.sh is sourced before every bash command in the sbx.
113-# ------------------------------------
114-RUN <<EOF
115-{
116- echo 'export PATH=/usr/local/go/bin:/usr/local/node/bin:/home/agent/go/bin:$PATH'
117- echo 'export GOTOOLCHAIN=local'
118-} >> /etc/sandbox-persistent.sh
119-EOF
120-
121-# Switch to agent user for Go tools installation (they go to /home/agent/go/bin)
122-USER agent
123-
124-# ------------------------------------
125-# Install Go developer tools
126-# ------------------------------------
127-ARG GOPLS_VERSION=v0.23.0
128-ARG X_TOOLS_VERSION=v0.49.0
129-ARG STATICCHECK_VERSION=v0.7.0
130-
131-# Retried: parallel multi-arch builds occasionally hit DNS timeouts on
132-# Docker Desktop's resolver. The module cache survives within this RUN,
133-# so a retry only fetches what's still missing.
134-RUN for i in 1 2 3 4 5; do \
135- go install golang.org/x/tools/gopls@${GOPLS_VERSION} \
136- && go install golang.org/x/tools/cmd/goimports@${X_TOOLS_VERSION} \
137- && go install honnef.co/go/tools/cmd/staticcheck@${STATICCHECK_VERSION} \
138- && exit 0; \
139- echo "go install failed (attempt $i), retrying..." >&2; sleep $((i * 5)); \
140- done; exit 1
141-
142-# Prove the binary runs on this platform before the image is tagged.
143-RUN mm --version && mm-tui --version
deleted docker-sbx-v3/template/mm-acp-info +0 -52
deleted file mode 100644
@@ -1,52 +0,0 @@
1-#!/bin/bash
2-# Entry point of the mm-acp sandbox kit (docker-sbx-v3/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: docker-sbx-v3/README.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
deleted file mode 100644
@@ -1,52 +0,0 @@
1-#!/bin/bash
2-# Entry point of the mm-acp sandbox kit (docker-sbx-v3/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: docker-sbx-v3/README.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
deleted docker-sbx-v3/template/mm-tui +0 -11
deleted file mode 100644
@@ -1,11 +0,0 @@
1-#!/bin/bash
2-# Entry point of the mm-tui sandbox kit (docker-sbx-v3/kits/mm-tui).
3-#
4-# `sbx run` forwards whatever follows "--" as this script's arguments, so
5-#
6-# sbx run ./docker-sbx-v3/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 "$@"
deleted file mode 100644
@@ -1,11 +0,0 @@
1-#!/bin/bash
2-# Entry point of the mm-tui sandbox kit (docker-sbx-v3/kits/mm-tui).
3-#
4-# `sbx run` forwards whatever follows "--" as this script's arguments, so
5-#
6-# sbx run ./docker-sbx-v3/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 "$@"
deleted docker-sbx/README.md +0 -208
deleted file mode 100644
@@ -1,208 +0,0 @@
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-├── publish.sh build + push the image, then publish the kits — the one command to release
10-├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)
11-├── sync-kits.sh points the kits at one image: owner + version
12-├── push-kits.sh publishes the kits to Docker Hub as OCI artifacts (sbx kit push)
13-├── template/
14-│ ├── Dockerfile docker/sandbox-templates:shell + mm (built from this checkout)
15-│ ├── mm-tui entry point of the mm-tui kit: `mm -tui "$@"`
16-│ └── mm-acp-info entry point of the mm-acp kit: prints the editor wiring, opens a shell
17-└── kits/
18- ├── mm-tui/spec.yaml kind: sandbox — `sbx run` opens mm's window on the workspace
19- └── mm-acp/spec.yaml kind: sandbox — `sbx create` once, the editor runs `sbx exec -i … mm -acp`
20-```
21-
22-## 0. Use the published kits (no build)
23-
24-Every release publishes the image and the two kits to Docker Hub at mm's version:
25-
26-| On Docker Hub | What it is |
27-|---|---|
28-| `k33g/mm-sandbox:0.1.7` | The template image. You never name it yourself: each kit pulls it. |
29-| `k33g/mm-tui:0.1.7` | The window-mode kit, for `sbx run`. |
30-| `k33g/mm-acp:0.1.7` | The editor kit, for `sbx create` + `sbx exec -i … mm -acp`. |
31-
32-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.
33-
34-**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.
35-
36-```bash
37-sbx kit inspect k33g/mm-tui:0.1.7
38-```
39-
40-**Window mode.** From the project you want mm to work on:
41-
42-```bash
43-cd /path/to/your/project
44-sbx run k33g/mm-tui:0.1.7 . -- agent.dmr.yaml
45-```
46-
47-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:
48-
49-```bash
50-sbx run k33g/mm-tui:0.1.7 . --kit-arg config=agent.dmr.yaml
51-```
52-
53-Later, `sbx run --name mm-tui-<directory>` re-attaches to that sandbox; `sbx ls` lists them.
54-
55-**From an editor.** Create the sandbox once, from the project the editor will open, with the configuration file baked in:
56-
57-```bash
58-cd /path/to/your/project
59-sbx create --name mm-acp k33g/mm-acp:0.1.7 . --kit-arg config=agent.dmr.yaml
60-
61-#sbx create k33g/mm-acp:0.1.7 . --name sbx-mm-acp
62-```
63-
64-then register it in the editor — in Zed's `settings.json`:
65-
66-```json
67-{
68- "agent_servers": {
69- "mini-me (sandbox)": {
70- "type": "custom",
71- "command": "sbx",
72- "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
73- }
74- }
75-}
76-```
77-
78-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`).
79-
80-**Kit arguments.** Both kits take the same two, passed with `--kit-arg name=value` (repeatable) to `sbx run` or `sbx create`:
81-
82-| `--kit-arg` | Default | Effect |
83-|---|---|---|
84-| `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. |
85-| `tag=<version>` | the kit's own version (`0.1.7`) | Which `k33g/mm-sandbox:<version>` image to use. Normally left alone: a kit and its image share a version. |
86-
87-**Other versions.** Replace `0.1.7` 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.
88-
89-**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.
90-
91-Sections 1–3 are the same flow with a template and kits built locally, for a work-in-progress mm.
92-
93-## 1. Build the template
94-
95-From the repository root:
96-
97-```bash
98-./docker-sbx/build.sh # TAG from release.env: v0.1.7 → k33g/mm-sandbox:0.1.7
99-./docker-sbx/build.sh v0.1.5 # → k33g/mm-sandbox:0.1.5
100-```
101-
102-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.1.7`. 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`.
103-
104-## 2. Window mode in the terminal — kit `mm-tui`
105-
106-From the project you want `mm` to work on:
107-
108-```bash
109-sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
110-```
111-
112-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:
113-
114-| `--kit-arg` | Default | Effect |
115-|---|---|---|
116-| `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. |
117-| `tag=<version>` | the version last built (`0.1.7`) | Which `k33g/mm-sandbox:<version>` image to use. |
118-
119-`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.
120-
121-## 3. From an editor (ACP) — kit `mm-acp`
122-
123-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.
124-
125-```bash
126-cd /path/to/your/project
127-sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . \
128- --kit-arg config=agent.dmr.yaml
129-
130-# once the image is pushed (docker push k33g/mm-sandbox:0.1.7), --pull never is not needed:
131-sbx create --name mm-acp ./docker-sbx/kits/mm-acp . \
132- --kit-arg config=agent.dmr.yaml
133-```
134-
135-Then register it in the editor. In Zed's `settings.json`:
136-
137-```json
138-{
139- "agent_servers": {
140- "📦 mini-me (dmr sbx)": {
141- "type": "custom",
142- "command": "sbx",
143- "args": ["exec", "-i", "mm-acp", "mm", "-acp"],
144- },
145- }
146-}
147-```
148-
149-Or:
150-
151-```bash
152-sbx create --pull never --name mm-acp-2 ./docker-sbx/kits/mm-acp .
153-```
154-
155-And:
156-
157-```json
158-{
159- "agent_servers": {
160- "😄 mini-me (dmr sbx)": {
161- "type": "custom",
162- "command": "sbx",
163- "args": ["exec", "-i", "mm-acp-2", "mm", "-acp"],
164- "env": { "AGENT_CONFIG": "/Users/k33g/kDrive/Rickub/bots-garden/mini-me/demo/agent.dmr.yaml" }
165- },
166- }
167-}
168-```
169-
170-
171-
172-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.
173-
174-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.
175-
176-- One sandbox per project: the workspace is fixed at creation. Give each one its own `--name` and its own entry in the editor.
177-- Another configuration file for one session: `"args": ["exec", "-i", "-e", "AGENT_CONFIG=agent.lsp.yaml", "mm-acp", "mm", "-acp"]`.
178-- `sbx` not found by the editor: use the absolute path printed by `which sbx` as `"command"`.
179-- Logs: in Zed, `dev: open acp logs` shows `mm`'s banner, warnings and `[acp] …` trail.
180-
181-## 4. Publishing a version
182-
183-Publishing is done by hand, from a laptop with Docker Desktop (buildx and the `sbx` CLI). One command builds the image for linux/amd64 and linux/arm64, pushes it, then validates and pushes the two kits, all at mm's tag:
184-
185-```bash
186-export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
187-export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
188-./docker-sbx/publish.sh # TAG from release.env: v0.1.7 → k33g/mm-sandbox:0.1.7, k33g/mm-tui:0.1.7, k33g/mm-acp:0.1.7
189-./docker-sbx/publish.sh v0.1.5 # another tag
190-```
191-
192-With the two variables set, the script logs in with them and logs out at the end; with neither, it reuses the `docker login` you already have. It is two steps you can also run alone:
193-
194-```bash
195-PUSH=1 ./docker-sbx/build.sh v0.2.3 # buildx multi-arch, pushed; proof: `imagetools inspect` lists both platforms
196-./docker-sbx/push-kits.sh v0.1.7 # sbx kit validate + sbx kit push, for each kit
197-```
198-
199-Both call `sync-kits.sh` first, so the published kits always name the image just pushed, and the kits' `spec.yaml` end up saying the new version — commit them. `sbx kit push` talks to the registry directly and authenticates from the Docker credential store; no sandbox daemon is involved. `IMAGE_OWNER=<handle>` publishes under another account. Nothing in CI publishes to the Hub: the Release workflow only builds the binaries.
200-
201-## The model server stays on the host
202-
203-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`:
204-
205-- `agent.dmr.yaml` already has `fallback: http://host.docker.internal:12434/engines/v1` — nothing to change.
206-- `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`.
207-
208-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>`.
deleted file mode 100644
@@ -1,208 +0,0 @@
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-├── publish.sh build + push the image, then publish the kits — the one command to release
10-├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)
11-├── sync-kits.sh points the kits at one image: owner + version
12-├── push-kits.sh publishes the kits to Docker Hub as OCI artifacts (sbx kit push)
13-├── template/
14-│ ├── Dockerfile docker/sandbox-templates:shell + mm (built from this checkout)
15-│ ├── mm-tui entry point of the mm-tui kit: `mm -tui "$@"`
16-│ └── mm-acp-info entry point of the mm-acp kit: prints the editor wiring, opens a shell
17-└── kits/
18- ├── mm-tui/spec.yaml kind: sandbox — `sbx run` opens mm's window on the workspace
19- └── mm-acp/spec.yaml kind: sandbox — `sbx create` once, the editor runs `sbx exec -i … mm -acp`
20-```
21-
22-## 0. Use the published kits (no build)
23-
24-Every release publishes the image and the two kits to Docker Hub at mm's version:
25-
26-| On Docker Hub | What it is |
27-|---|---|
28-| `k33g/mm-sandbox:0.1.7` | The template image. You never name it yourself: each kit pulls it. |
29-| `k33g/mm-tui:0.1.7` | The window-mode kit, for `sbx run`. |
30-| `k33g/mm-acp:0.1.7` | The editor kit, for `sbx create` + `sbx exec -i … mm -acp`. |
31-
32-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.
33-
34-**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.
35-
36-```bash
37-sbx kit inspect k33g/mm-tui:0.1.7
38-```
39-
40-**Window mode.** From the project you want mm to work on:
41-
42-```bash
43-cd /path/to/your/project
44-sbx run k33g/mm-tui:0.1.7 . -- agent.dmr.yaml
45-```
46-
47-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:
48-
49-```bash
50-sbx run k33g/mm-tui:0.1.7 . --kit-arg config=agent.dmr.yaml
51-```
52-
53-Later, `sbx run --name mm-tui-<directory>` re-attaches to that sandbox; `sbx ls` lists them.
54-
55-**From an editor.** Create the sandbox once, from the project the editor will open, with the configuration file baked in:
56-
57-```bash
58-cd /path/to/your/project
59-sbx create --name mm-acp k33g/mm-acp:0.1.7 . --kit-arg config=agent.dmr.yaml
60-
61-#sbx create k33g/mm-acp:0.1.7 . --name sbx-mm-acp
62-```
63-
64-then register it in the editor — in Zed's `settings.json`:
65-
66-```json
67-{
68- "agent_servers": {
69- "mini-me (sandbox)": {
70- "type": "custom",
71- "command": "sbx",
72- "args": ["exec", "-i", "mm-acp", "mm", "-acp"]
73- }
74- }
75-}
76-```
77-
78-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`).
79-
80-**Kit arguments.** Both kits take the same two, passed with `--kit-arg name=value` (repeatable) to `sbx run` or `sbx create`:
81-
82-| `--kit-arg` | Default | Effect |
83-|---|---|---|
84-| `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. |
85-| `tag=<version>` | the kit's own version (`0.1.7`) | Which `k33g/mm-sandbox:<version>` image to use. Normally left alone: a kit and its image share a version. |
86-
87-**Other versions.** Replace `0.1.7` 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.
88-
89-**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.
90-
91-Sections 1–3 are the same flow with a template and kits built locally, for a work-in-progress mm.
92-
93-## 1. Build the template
94-
95-From the repository root:
96-
97-```bash
98-./docker-sbx/build.sh # TAG from release.env: v0.1.7 → k33g/mm-sandbox:0.1.7
99-./docker-sbx/build.sh v0.1.5 # → k33g/mm-sandbox:0.1.5
100-```
101-
102-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.1.7`. 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`.
103-
104-## 2. Window mode in the terminal — kit `mm-tui`
105-
106-From the project you want `mm` to work on:
107-
108-```bash
109-sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
110-```
111-
112-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:
113-
114-| `--kit-arg` | Default | Effect |
115-|---|---|---|
116-| `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. |
117-| `tag=<version>` | the version last built (`0.1.7`) | Which `k33g/mm-sandbox:<version>` image to use. |
118-
119-`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.
120-
121-## 3. From an editor (ACP) — kit `mm-acp`
122-
123-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.
124-
125-```bash
126-cd /path/to/your/project
127-sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . \
128- --kit-arg config=agent.dmr.yaml
129-
130-# once the image is pushed (docker push k33g/mm-sandbox:0.1.7), --pull never is not needed:
131-sbx create --name mm-acp ./docker-sbx/kits/mm-acp . \
132- --kit-arg config=agent.dmr.yaml
133-```
134-
135-Then register it in the editor. In Zed's `settings.json`:
136-
137-```json
138-{
139- "agent_servers": {
140- "📦 mini-me (dmr sbx)": {
141- "type": "custom",
142- "command": "sbx",
143- "args": ["exec", "-i", "mm-acp", "mm", "-acp"],
144- },
145- }
146-}
147-```
148-
149-Or:
150-
151-```bash
152-sbx create --pull never --name mm-acp-2 ./docker-sbx/kits/mm-acp .
153-```
154-
155-And:
156-
157-```json
158-{
159- "agent_servers": {
160- "😄 mini-me (dmr sbx)": {
161- "type": "custom",
162- "command": "sbx",
163- "args": ["exec", "-i", "mm-acp-2", "mm", "-acp"],
164- "env": { "AGENT_CONFIG": "/Users/k33g/kDrive/Rickub/bots-garden/mini-me/demo/agent.dmr.yaml" }
165- },
166- }
167-}
168-```
169-
170-
171-
172-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.
173-
174-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.
175-
176-- One sandbox per project: the workspace is fixed at creation. Give each one its own `--name` and its own entry in the editor.
177-- Another configuration file for one session: `"args": ["exec", "-i", "-e", "AGENT_CONFIG=agent.lsp.yaml", "mm-acp", "mm", "-acp"]`.
178-- `sbx` not found by the editor: use the absolute path printed by `which sbx` as `"command"`.
179-- Logs: in Zed, `dev: open acp logs` shows `mm`'s banner, warnings and `[acp] …` trail.
180-
181-## 4. Publishing a version
182-
183-Publishing is done by hand, from a laptop with Docker Desktop (buildx and the `sbx` CLI). One command builds the image for linux/amd64 and linux/arm64, pushes it, then validates and pushes the two kits, all at mm's tag:
184-
185-```bash
186-export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
187-export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
188-./docker-sbx/publish.sh # TAG from release.env: v0.1.7 → k33g/mm-sandbox:0.1.7, k33g/mm-tui:0.1.7, k33g/mm-acp:0.1.7
189-./docker-sbx/publish.sh v0.1.5 # another tag
190-```
191-
192-With the two variables set, the script logs in with them and logs out at the end; with neither, it reuses the `docker login` you already have. It is two steps you can also run alone:
193-
194-```bash
195-PUSH=1 ./docker-sbx/build.sh v0.2.3 # buildx multi-arch, pushed; proof: `imagetools inspect` lists both platforms
196-./docker-sbx/push-kits.sh v0.1.7 # sbx kit validate + sbx kit push, for each kit
197-```
198-
199-Both call `sync-kits.sh` first, so the published kits always name the image just pushed, and the kits' `spec.yaml` end up saying the new version — commit them. `sbx kit push` talks to the registry directly and authenticates from the Docker credential store; no sandbox daemon is involved. `IMAGE_OWNER=<handle>` publishes under another account. Nothing in CI publishes to the Hub: the Release workflow only builds the binaries.
200-
201-## The model server stays on the host
202-
203-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`:
204-
205-- `agent.dmr.yaml` already has `fallback: http://host.docker.internal:12434/engines/v1` — nothing to change.
206-- `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`.
207-
208-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>`.
deleted docker-sbx/USE.MM.SBX-WITH.TURBO.EDITORS.md +0 -16
deleted file mode 100644
@@ -1,16 +0,0 @@
1-
2-
3-Start `sbx` in your project directory:
4-```bash
5-sbx create k33g/mm-acp:0.1.7 . --name turbo-acp --kit-arg config=.turbo-go/agent.mm-dmr-gemma.yaml
6-```
7-
8-`acp.toml`:
9-
10-```toml
11-[[agent]]
12-name = "📦 Riker (sbx mm-dmr-gemma)"
13-command = "sbx"
14-args = ["exec", "-i", "turbo-acp", "mm", "-acp"]
15-
16-```
\ No newline at end of file
deleted file mode 100644
@@ -1,16 +0,0 @@
1-
2-
3-Start `sbx` in your project directory:
4-```bash
5-sbx create k33g/mm-acp:0.1.7 . --name turbo-acp --kit-arg config=.turbo-go/agent.mm-dmr-gemma.yaml
6-```
7-
8-`acp.toml`:
9-
10-```toml
11-[[agent]]
12-name = "📦 Riker (sbx mm-dmr-gemma)"
13-command = "sbx"
14-args = ["exec", "-i", "turbo-acp", "mm", "-acp"]
15-
16-```
\ No newline at end of file\ No newline at end of file
deleted docker-sbx/USE.MM.SBX-WITH.ZED.EDITOR.md +0 -18
deleted file mode 100644
@@ -1,18 +0,0 @@
1-
2-
3-Start `sbx` in your project directory:
4-```bash
5-sbx create k33g/mm-acp:0.1.7 . --name zed-acp --kit-arg config=agent.dmr.yaml
6-```
7-
8-Zed settings:
9-
10-```json
11- "agent_servers": {
12- "😄 mini-me (dmr sbx)": {
13- "type": "custom",
14- "command": "sbx",
15- "args": ["exec", "-i", "zed-acp-3", "mm", "-acp"],
16- },
17- }
18-```
\ No newline at end of file
deleted file mode 100644
@@ -1,18 +0,0 @@
1-
2-
3-Start `sbx` in your project directory:
4-```bash
5-sbx create k33g/mm-acp:0.1.7 . --name zed-acp --kit-arg config=agent.dmr.yaml
6-```
7-
8-Zed settings:
9-
10-```json
11- "agent_servers": {
12- "😄 mini-me (dmr sbx)": {
13- "type": "custom",
14- "command": "sbx",
15- "args": ["exec", "-i", "zed-acp-3", "mm", "-acp"],
16- },
17- }
18-```
\ No newline at end of file\ No newline at end of file
deleted docker-sbx/build.sh +0 -106
deleted file mode 100644
@@ -1,106 +0,0 @@
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
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`; publish.sh does this
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, and
23-# docker-sbx/publish.sh chains the two.
24-set -euo pipefail
25-
26-cd "$(dirname "$0")/.."
27-
28-# release.env carries TAG ("v0.0.2"). It is git-ignored, so a checkout without
29-# it names the tag on the command line. A tag given on the command line wins.
30-if [ -f release.env ]; then
31- # shellcheck source=/dev/null
32- source release.env
33-fi
34-TAG="${1:-${TAG:-}}"
35-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
36- 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)"
37- exit 1
38-fi
39-
40-# Not OWNER: release.env uses that name for the git owner (bots-garden), and
41-# the image owner is a different thing — the Docker Hub account, k33g.
42-IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
43-VERSION="${TAG#v}"
44-IMAGE="${IMAGE_OWNER}/mm-sandbox:${VERSION}"
45-PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
46-
47-build_args=(--build-arg "MM_VERSION=${TAG}")
48-if [ -n "${SHELL_TEMPLATE:-}" ]; then
49- build_args+=(--build-arg "SHELL_TEMPLATE=${SHELL_TEMPLATE}")
50-fi
51-
52-if [ -n "${PUSH:-}" ]; then
53- # Multi-arch needs buildx's container driver: the classic builder can
54- # neither assemble a manifest list nor build for a foreign platform. The
55- # Go stage cross-compiles on the build platform; only the final stage's
56- # `RUN mm --version` runs under emulation (Docker Desktop ships QEMU).
57- echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
58- if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
59- docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
60- fi
61- docker buildx build --builder mm-sandbox-builder \
62- --platform "${PLATFORMS}" \
63- -f docker-sbx/template/Dockerfile "${build_args[@]}" \
64- -t "${IMAGE}" --push .
65- # The proof that ships: the registry holds one manifest per platform.
66- docker buildx imagetools inspect "${IMAGE}" | grep -E '^Name:|Platform:' | sed 's/^/ /'
67-else
68- echo "🐳 Building ${IMAGE} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
69- docker build -f docker-sbx/template/Dockerfile "${build_args[@]}" -t "${IMAGE}" .
70-
71- # The one proof that what was built starts: --version needs no config and
72- # no model server. It also confirms the stamp reached the binary.
73- reported="$(docker run --rm "${IMAGE}" mm --version)"
74- if ! grep -q -- "${TAG}" <<<"${reported}"; then
75- echo "❌ the image does not report ${TAG}: ${reported}"
76- exit 1
77- fi
78- echo "✅ ${reported}"
79-fi
80-
81-./docker-sbx/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
82-
83-if [ -n "${EXPORT:-}" ]; then
84- mkdir -p tmp
85- docker save -o "tmp/mm-sandbox-${VERSION}.tar" "${IMAGE}"
86- echo "📦 tmp/mm-sandbox-${VERSION}.tar — load it where sbx runs with: sbx template load tmp/mm-sandbox-${VERSION}.tar"
87-fi
88-
89-if [ -n "${PUSH:-}" ]; then
90- cat <<NEXT
91-
92-Image on the registry. Publish the kits next: ./docker-sbx/push-kits.sh ${TAG}
93-NEXT
94-else
95- cat <<NEXT
96-
97-Next, from the project you want mm to work on:
98-
99- window mode sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
100- editor (ACP) sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . --kit-arg config=agent.dmr.yaml
101- then register sbx exec -i mm-acp mm -acp in the editor (docker-sbx/README.md)
102-
103- --pull never because ${IMAGE} exists only in the local image store;
104- after \`docker push ${IMAGE}\` (or PUSH=1) it is no longer needed.
105-NEXT
106-fi
deleted file mode 100644
@@ -1,106 +0,0 @@
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
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`; publish.sh does this
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, and
23-# docker-sbx/publish.sh chains the two.
24-set -euo pipefail
25-
26-cd "$(dirname "$0")/.."
27-
28-# release.env carries TAG ("v0.0.2"). It is git-ignored, so a checkout without
29-# it names the tag on the command line. A tag given on the command line wins.
30-if [ -f release.env ]; then
31- # shellcheck source=/dev/null
32- source release.env
33-fi
34-TAG="${1:-${TAG:-}}"
35-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
36- 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)"
37- exit 1
38-fi
39-
40-# Not OWNER: release.env uses that name for the git owner (bots-garden), and
41-# the image owner is a different thing — the Docker Hub account, k33g.
42-IMAGE_OWNER="${IMAGE_OWNER:-k33g}"
43-VERSION="${TAG#v}"
44-IMAGE="${IMAGE_OWNER}/mm-sandbox:${VERSION}"
45-PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
46-
47-build_args=(--build-arg "MM_VERSION=${TAG}")
48-if [ -n "${SHELL_TEMPLATE:-}" ]; then
49- build_args+=(--build-arg "SHELL_TEMPLATE=${SHELL_TEMPLATE}")
50-fi
51-
52-if [ -n "${PUSH:-}" ]; then
53- # Multi-arch needs buildx's container driver: the classic builder can
54- # neither assemble a manifest list nor build for a foreign platform. The
55- # Go stage cross-compiles on the build platform; only the final stage's
56- # `RUN mm --version` runs under emulation (Docker Desktop ships QEMU).
57- echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
58- if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
59- docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
60- fi
61- docker buildx build --builder mm-sandbox-builder \
62- --platform "${PLATFORMS}" \
63- -f docker-sbx/template/Dockerfile "${build_args[@]}" \
64- -t "${IMAGE}" --push .
65- # The proof that ships: the registry holds one manifest per platform.
66- docker buildx imagetools inspect "${IMAGE}" | grep -E '^Name:|Platform:' | sed 's/^/ /'
67-else
68- echo "🐳 Building ${IMAGE} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
69- docker build -f docker-sbx/template/Dockerfile "${build_args[@]}" -t "${IMAGE}" .
70-
71- # The one proof that what was built starts: --version needs no config and
72- # no model server. It also confirms the stamp reached the binary.
73- reported="$(docker run --rm "${IMAGE}" mm --version)"
74- if ! grep -q -- "${TAG}" <<<"${reported}"; then
75- echo "❌ the image does not report ${TAG}: ${reported}"
76- exit 1
77- fi
78- echo "✅ ${reported}"
79-fi
80-
81-./docker-sbx/sync-kits.sh "${IMAGE_OWNER}" "${VERSION}"
82-
83-if [ -n "${EXPORT:-}" ]; then
84- mkdir -p tmp
85- docker save -o "tmp/mm-sandbox-${VERSION}.tar" "${IMAGE}"
86- echo "📦 tmp/mm-sandbox-${VERSION}.tar — load it where sbx runs with: sbx template load tmp/mm-sandbox-${VERSION}.tar"
87-fi
88-
89-if [ -n "${PUSH:-}" ]; then
90- cat <<NEXT
91-
92-Image on the registry. Publish the kits next: ./docker-sbx/push-kits.sh ${TAG}
93-NEXT
94-else
95- cat <<NEXT
96-
97-Next, from the project you want mm to work on:
98-
99- window mode sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
100- editor (ACP) sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . --kit-arg config=agent.dmr.yaml
101- then register sbx exec -i mm-acp mm -acp in the editor (docker-sbx/README.md)
102-
103- --pull never because ${IMAGE} exists only in the local image store;
104- after \`docker push ${IMAGE}\` (or PUSH=1) it is no longer needed.
105-NEXT
106-fi
deleted docker-sbx/kits/mm-acp/spec.yaml +0 -69
deleted file mode 100644
@@ -1,69 +0,0 @@
1-# Docker Sandboxes kit: mm as an editor's agent (Agent Client Protocol), inside
2-# the mm sandbox template.
3-#
4-# ./docker-sbx/build.sh # once: k33g/mm-sandbox:<version>
5-# sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . \
6-# --kit-arg config=agent.dmr.yaml
7-#
8-# then, in the editor (Zed settings.json):
9-#
10-# "agent_servers": { "mini-me (sandbox)": { "type": "custom",
11-# "command": "sbx", "args": ["exec", "-i", "mm-acp", "mm", "-acp"] } }
12-#
13-# Why `sbx exec -i` and not `sbx run`: an ACP client speaks JSON-RPC on the
14-# agent's raw stdin/stdout, and `sbx run` always allocates a terminal. So the
15-# sandbox is created without attaching, and the editor starts `mm -acp` inside
16-# it for every conversation (sbx starts a stopped sandbox first). Attaching
17-# with `sbx run` runs the entry point below, which prints this wiring with the
18-# sandbox's real name and opens a shell.
19-schemaVersion: "2"
20-kind: sandbox
21-name: mm-acp
22-displayName: Mini Me (editor, ACP)
23-description: >
24- Holds mm, a minimal coding agent for local LLMs, for an editor that speaks
25- the Agent Client Protocol (Zed, …). The editor runs `sbx exec -i <sandbox>
26- mm -acp`; every command and file edit the model asks for happens inside the
27- sandbox, on the mounted workspace. The model server stays on the host,
28- reached through host.docker.internal.
29-# Kept equal to the image tag by docker-sbx/sync-kits.sh; becomes the
30-# vnd.docker.sandbox.kit.version annotation of the published kit.
31-version: "0.2.1"
32-sourceURL: https://git.rickub.com/bots-garden/mini-me
33-
34-args:
35- tag:
36- default: "0.2.1"
37- description: >-
38- Tag of the k33g/mm-sandbox image: mm's version without the "v", as
39- docker-sbx/build.sh tags it (and rewrites this default to).
40- pattern: '^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$'
41- config:
42- default: ""
43- description: >-
44- Configuration file mm reads (its AGENT_CONFIG): an absolute path inside
45- the sandbox, or a path relative to the workspace, which is where
46- `sbx exec` starts mm. Empty: ./agent.yaml in the workspace, then the
47- built-in defaults.
48-
49-sandbox:
50- image: "k33g/mm-sandbox:${{ kit.args.tag }}"
51- # Not `mm -acp`: nothing useful comes of speaking JSON-RPC to a terminal.
52- entrypoint: [mm-acp-info]
53-
54-environment:
55- variables:
56- # Baked into the container, so `sbx exec` inherits it and the editor's
57- # settings need not repeat the path. `sbx exec -e AGENT_CONFIG=…` overrides
58- # it for one session.
59- AGENT_CONFIG: "${{ kit.args.config }}"
60- LANG: C.UTF-8
61-
62-# The model server on the host — see docker-sbx/kits/mm-tui/spec.yaml.
63-permissions:
64- network:
65- allow:
66- - "host.docker.internal:12434"
67- - "localhost:12434"
68- - "host.docker.internal:8080"
69- - "localhost:8080"
deleted file mode 100644
@@ -1,69 +0,0 @@
1-# Docker Sandboxes kit: mm as an editor's agent (Agent Client Protocol), inside
2-# the mm sandbox template.
3-#
4-# ./docker-sbx/build.sh # once: k33g/mm-sandbox:<version>
5-# sbx create --pull never --name mm-acp ./docker-sbx/kits/mm-acp . \
6-# --kit-arg config=agent.dmr.yaml
7-#
8-# then, in the editor (Zed settings.json):
9-#
10-# "agent_servers": { "mini-me (sandbox)": { "type": "custom",
11-# "command": "sbx", "args": ["exec", "-i", "mm-acp", "mm", "-acp"] } }
12-#
13-# Why `sbx exec -i` and not `sbx run`: an ACP client speaks JSON-RPC on the
14-# agent's raw stdin/stdout, and `sbx run` always allocates a terminal. So the
15-# sandbox is created without attaching, and the editor starts `mm -acp` inside
16-# it for every conversation (sbx starts a stopped sandbox first). Attaching
17-# with `sbx run` runs the entry point below, which prints this wiring with the
18-# sandbox's real name and opens a shell.
19-schemaVersion: "2"
20-kind: sandbox
21-name: mm-acp
22-displayName: Mini Me (editor, ACP)
23-description: >
24- Holds mm, a minimal coding agent for local LLMs, for an editor that speaks
25- the Agent Client Protocol (Zed, …). The editor runs `sbx exec -i <sandbox>
26- mm -acp`; every command and file edit the model asks for happens inside the
27- sandbox, on the mounted workspace. The model server stays on the host,
28- reached through host.docker.internal.
29-# Kept equal to the image tag by docker-sbx/sync-kits.sh; becomes the
30-# vnd.docker.sandbox.kit.version annotation of the published kit.
31-version: "0.2.1"
32-sourceURL: https://git.rickub.com/bots-garden/mini-me
33-
34-args:
35- tag:
36- default: "0.2.1"
37- description: >-
38- Tag of the k33g/mm-sandbox image: mm's version without the "v", as
39- docker-sbx/build.sh tags it (and rewrites this default to).
40- pattern: '^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$'
41- config:
42- default: ""
43- description: >-
44- Configuration file mm reads (its AGENT_CONFIG): an absolute path inside
45- the sandbox, or a path relative to the workspace, which is where
46- `sbx exec` starts mm. Empty: ./agent.yaml in the workspace, then the
47- built-in defaults.
48-
49-sandbox:
50- image: "k33g/mm-sandbox:${{ kit.args.tag }}"
51- # Not `mm -acp`: nothing useful comes of speaking JSON-RPC to a terminal.
52- entrypoint: [mm-acp-info]
53-
54-environment:
55- variables:
56- # Baked into the container, so `sbx exec` inherits it and the editor's
57- # settings need not repeat the path. `sbx exec -e AGENT_CONFIG=…` overrides
58- # it for one session.
59- AGENT_CONFIG: "${{ kit.args.config }}"
60- LANG: C.UTF-8
61-
62-# The model server on the host — see docker-sbx/kits/mm-tui/spec.yaml.
63-permissions:
64- network:
65- allow:
66- - "host.docker.internal:12434"
67- - "localhost:12434"
68- - "host.docker.internal:8080"
69- - "localhost:8080"
deleted docker-sbx/kits/mm-tui/spec.yaml +0 -68
deleted file mode 100644
@@ -1,68 +0,0 @@
1-# Docker Sandboxes kit: mm in its window mode, inside the mm sandbox template.
2-#
3-# ./docker-sbx/build.sh # once: k33g/mm-sandbox:<version>
4-# sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
5-#
6-# What follows "--" reaches mm as its own arguments (here the configuration
7-# file, relative to the workspace). Without it, the `config` argument below is
8-# read, then ./agent.yaml, then the built-in defaults:
9-#
10-# sbx run --pull never ./docker-sbx/kits/mm-tui . --kit-arg config=agent.dmr.yaml
11-#
12-# --pull never: the image is built locally; drop it once it is pushed.
13-schemaVersion: "2"
14-kind: sandbox
15-name: mm-tui
16-displayName: Mini Me (window mode)
17-description: >
18- Runs mm, a minimal coding agent for local LLMs, in its single-window terminal
19- mode (`mm -tui`) on the workspace. The model server (Docker Model Runner or
20- llama-server) stays on the host: inside the sandbox `localhost` is the sandbox
21- itself, so the configuration file must reach the host through
22- host.docker.internal — agent.dmr.yaml already falls back to it.
23-# Kept equal to the image tag by docker-sbx/sync-kits.sh; becomes the
24-# vnd.docker.sandbox.kit.version annotation of the published kit.
25-version: "0.2.1"
26-sourceURL: https://git.rickub.com/bots-garden/mini-me
27-
28-args:
29- tag:
30- default: "0.2.1"
31- description: >-
32- Tag of the k33g/mm-sandbox image: mm's version without the "v", as
33- docker-sbx/build.sh tags it (and rewrites this default to).
34- pattern: '^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$'
35- config:
36- default: ""
37- description: >-
38- Configuration file mm reads (its AGENT_CONFIG): an absolute path inside
39- the sandbox, or a path relative to the workspace. Empty: ./agent.yaml in
40- the workspace, then the built-in defaults.
41-
42-sandbox:
43- image: "k33g/mm-sandbox:${{ kit.args.tag }}"
44- # A wrapper, not `mm -tui` directly: the start script drops the fixed
45- # options when the first user argument is not a flag, so `-- agent.yaml`
46- # would otherwise lose -tui. The wrapper always adds it.
47- entrypoint: [mm-tui]
48-
49-environment:
50- variables:
51- AGENT_CONFIG: "${{ kit.args.config }}"
52- # tcell needs a terminal type and a UTF-8 locale to draw the window.
53- TERM: xterm-256color
54- COLORTERM: truecolor
55- LANG: C.UTF-8
56-
57-# The model server on the host. Requests leave the sandbox through its proxy,
58-# which maps host.docker.internal to the host's localhost; both spellings are
59-# listed so the rule matches whichever one the policy is checked against.
60-# 12434 is Docker Model Runner, 8080 is llama-server's default. Add your own
61-# port with `sbx policy allow network host.docker.internal:<port>`.
62-permissions:
63- network:
64- allow:
65- - "host.docker.internal:12434"
66- - "localhost:12434"
67- - "host.docker.internal:8080"
68- - "localhost:8080"
deleted file mode 100644
@@ -1,68 +0,0 @@
1-# Docker Sandboxes kit: mm in its window mode, inside the mm sandbox template.
2-#
3-# ./docker-sbx/build.sh # once: k33g/mm-sandbox:<version>
4-# sbx run --pull never ./docker-sbx/kits/mm-tui . -- agent.dmr.yaml
5-#
6-# What follows "--" reaches mm as its own arguments (here the configuration
7-# file, relative to the workspace). Without it, the `config` argument below is
8-# read, then ./agent.yaml, then the built-in defaults:
9-#
10-# sbx run --pull never ./docker-sbx/kits/mm-tui . --kit-arg config=agent.dmr.yaml
11-#
12-# --pull never: the image is built locally; drop it once it is pushed.
13-schemaVersion: "2"
14-kind: sandbox
15-name: mm-tui
16-displayName: Mini Me (window mode)
17-description: >
18- Runs mm, a minimal coding agent for local LLMs, in its single-window terminal
19- mode (`mm -tui`) on the workspace. The model server (Docker Model Runner or
20- llama-server) stays on the host: inside the sandbox `localhost` is the sandbox
21- itself, so the configuration file must reach the host through
22- host.docker.internal — agent.dmr.yaml already falls back to it.
23-# Kept equal to the image tag by docker-sbx/sync-kits.sh; becomes the
24-# vnd.docker.sandbox.kit.version annotation of the published kit.
25-version: "0.2.1"
26-sourceURL: https://git.rickub.com/bots-garden/mini-me
27-
28-args:
29- tag:
30- default: "0.2.1"
31- description: >-
32- Tag of the k33g/mm-sandbox image: mm's version without the "v", as
33- docker-sbx/build.sh tags it (and rewrites this default to).
34- pattern: '^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$'
35- config:
36- default: ""
37- description: >-
38- Configuration file mm reads (its AGENT_CONFIG): an absolute path inside
39- the sandbox, or a path relative to the workspace. Empty: ./agent.yaml in
40- the workspace, then the built-in defaults.
41-
42-sandbox:
43- image: "k33g/mm-sandbox:${{ kit.args.tag }}"
44- # A wrapper, not `mm -tui` directly: the start script drops the fixed
45- # options when the first user argument is not a flag, so `-- agent.yaml`
46- # would otherwise lose -tui. The wrapper always adds it.
47- entrypoint: [mm-tui]
48-
49-environment:
50- variables:
51- AGENT_CONFIG: "${{ kit.args.config }}"
52- # tcell needs a terminal type and a UTF-8 locale to draw the window.
53- TERM: xterm-256color
54- COLORTERM: truecolor
55- LANG: C.UTF-8
56-
57-# The model server on the host. Requests leave the sandbox through its proxy,
58-# which maps host.docker.internal to the host's localhost; both spellings are
59-# listed so the rule matches whichever one the policy is checked against.
60-# 12434 is Docker Model Runner, 8080 is llama-server's default. Add your own
61-# port with `sbx policy allow network host.docker.internal:<port>`.
62-permissions:
63- network:
64- allow:
65- - "host.docker.internal:12434"
66- - "localhost:12434"
67- - "host.docker.internal:8080"
68- - "localhost:8080"
deleted docker-sbx/mcp/github-mcp.sh +0 -51
deleted file mode 100644
@@ -1,51 +0,0 @@
1-#!/bin/sh
2-# GitHub's official MCP server (github/github-mcp-server) over stdio, for the
3-# sbx MCP gateway:
4-#
5-# sbx mcp add github-mm --command "$PWD/docker-sbx/mcp/github-mcp.sh"
6-#
7-# sbx runs this ON THE HOST, as a child of sandboxd, never inside the sandbox:
8-# the token stays on your machine and the sandbox only sees the gateway.
9-#
10-# Why a script: in sbx's local mode a catalog image is started as a bare
11-# `docker run -i --rm <image>`, with no environment, so the catalog's
12-# github-official entry would start without a token, and `sbx mcp add` has no
13-# --env flag. A --command server inherits sandboxd's environment instead, and
14-# this script adds the token to it.
15-#
16-# Token, first found: $GITHUB_PERSONAL_ACCESS_TOKEN, $GITHUB_OAUTH_TOKEN, the
17-# macOS keychain item "github-mcp", `gh auth token`.
18-# Tools: read-only and four toolsets by default (25 tools) — a small local
19-# model copes badly with 40+. Override with GITHUB_TOOLSETS / GITHUB_READ_ONLY.
20-set -eu
21-
22-# sandboxd may start with a minimal PATH: add the usual macOS locations of
23-# docker and gh.
24-PATH="/opt/homebrew/bin:/usr/local/bin:/Applications/Docker.app/Contents/Resources/bin:$PATH"
25-export PATH
26-
27-# sandboxd does NOT see the variables of your interactive shell, so on macOS
28-# the reliable place for the token is the login keychain, stored once with:
29-# security add-generic-password -U -a "$USER" -s github-mcp -w
30-# (it prompts for the token; `-w "$GITHUB_OAUTH_TOKEN"` works too).
31-service="${GITHUB_MCP_KEYCHAIN_SERVICE:-github-mcp}"
32-token="${GITHUB_PERSONAL_ACCESS_TOKEN:-${GITHUB_OAUTH_TOKEN:-}}"
33-if [ -z "$token" ] && command -v security >/dev/null 2>&1; then
34- token="$(security find-generic-password -s "$service" -w 2>/dev/null || true)"
35-fi
36-if [ -z "$token" ] && command -v gh >/dev/null 2>&1; then
37- token="$(gh auth token 2>/dev/null || true)"
38-fi
39-if [ -z "$token" ]; then
40- echo "github-mcp: no token: store it with 'security add-generic-password -U -a \"\$USER\" -s $service -w', or run 'gh auth login'" >&2
41- exit 1
42-fi
43-GITHUB_PERSONAL_ACCESS_TOKEN="$token"
44-export GITHUB_PERSONAL_ACCESS_TOKEN
45-
46-# stdout is the MCP channel: nothing but the server may write to it.
47-exec docker run -i --rm \
48- -e GITHUB_PERSONAL_ACCESS_TOKEN \
49- -e GITHUB_TOOLSETS="${GITHUB_TOOLSETS:-context,repos,issues,pull_requests}" \
50- -e GITHUB_READ_ONLY="${GITHUB_READ_ONLY:-1}" \
51- "${GITHUB_MCP_IMAGE:-ghcr.io/github/github-mcp-server}" stdio
deleted file mode 100644
@@ -1,51 +0,0 @@
1-#!/bin/sh
2-# GitHub's official MCP server (github/github-mcp-server) over stdio, for the
3-# sbx MCP gateway:
4-#
5-# sbx mcp add github-mm --command "$PWD/docker-sbx/mcp/github-mcp.sh"
6-#
7-# sbx runs this ON THE HOST, as a child of sandboxd, never inside the sandbox:
8-# the token stays on your machine and the sandbox only sees the gateway.
9-#
10-# Why a script: in sbx's local mode a catalog image is started as a bare
11-# `docker run -i --rm <image>`, with no environment, so the catalog's
12-# github-official entry would start without a token, and `sbx mcp add` has no
13-# --env flag. A --command server inherits sandboxd's environment instead, and
14-# this script adds the token to it.
15-#
16-# Token, first found: $GITHUB_PERSONAL_ACCESS_TOKEN, $GITHUB_OAUTH_TOKEN, the
17-# macOS keychain item "github-mcp", `gh auth token`.
18-# Tools: read-only and four toolsets by default (25 tools) — a small local
19-# model copes badly with 40+. Override with GITHUB_TOOLSETS / GITHUB_READ_ONLY.
20-set -eu
21-
22-# sandboxd may start with a minimal PATH: add the usual macOS locations of
23-# docker and gh.
24-PATH="/opt/homebrew/bin:/usr/local/bin:/Applications/Docker.app/Contents/Resources/bin:$PATH"
25-export PATH
26-
27-# sandboxd does NOT see the variables of your interactive shell, so on macOS
28-# the reliable place for the token is the login keychain, stored once with:
29-# security add-generic-password -U -a "$USER" -s github-mcp -w
30-# (it prompts for the token; `-w "$GITHUB_OAUTH_TOKEN"` works too).
31-service="${GITHUB_MCP_KEYCHAIN_SERVICE:-github-mcp}"
32-token="${GITHUB_PERSONAL_ACCESS_TOKEN:-${GITHUB_OAUTH_TOKEN:-}}"
33-if [ -z "$token" ] && command -v security >/dev/null 2>&1; then
34- token="$(security find-generic-password -s "$service" -w 2>/dev/null || true)"
35-fi
36-if [ -z "$token" ] && command -v gh >/dev/null 2>&1; then
37- token="$(gh auth token 2>/dev/null || true)"
38-fi
39-if [ -z "$token" ]; then
40- echo "github-mcp: no token: store it with 'security add-generic-password -U -a \"\$USER\" -s $service -w', or run 'gh auth login'" >&2
41- exit 1
42-fi
43-GITHUB_PERSONAL_ACCESS_TOKEN="$token"
44-export GITHUB_PERSONAL_ACCESS_TOKEN
45-
46-# stdout is the MCP channel: nothing but the server may write to it.
47-exec docker run -i --rm \
48- -e GITHUB_PERSONAL_ACCESS_TOKEN \
49- -e GITHUB_TOOLSETS="${GITHUB_TOOLSETS:-context,repos,issues,pull_requests}" \
50- -e GITHUB_READ_ONLY="${GITHUB_READ_ONLY:-1}" \
51- "${GITHUB_MCP_IMAGE:-ghcr.io/github/github-mcp-server}" stdio
deleted docker-sbx/publish.sh +0 -82
deleted file mode 100644
@@ -1,82 +0,0 @@
1-#!/usr/bin/env bash
2-# Build and publish everything to Docker Hub, by hand, in one go:
3-# <owner>/mm-sandbox:<version> the template image, linux/amd64 + linux/arm64
4-# <owner>/mm-tui:<version> the window-mode kit
5-# <owner>/mm-acp:<version> the editor (ACP) kit
6-#
7-# Usage:
8-# ./docker-sbx/publish.sh # TAG from release.env (v0.0.3 → 0.0.3)
9-# ./docker-sbx/publish.sh v0.0.4 # another tag
10-#
11-# Credentials, two environment variables:
12-# DOCKER_HANDLE the Docker Hub account — also the image owner (default k33g)
13-# DOCKER_PAT an access token with read/write scope
14-# With both set, the script logs in with them (and out at the end). With
15-# neither, it uses the login you already have (`docker login` done earlier).
16-#
17-# Needs: docker with buildx (Docker Desktop has it), and the sbx CLI for the
18-# kits (`SBX=/path/to/sbx` if it is not on the PATH). Pieces, runnable alone:
19-# PUSH=1 ./docker-sbx/build.sh TAG image only
20-# ./docker-sbx/push-kits.sh TAG kits only
21-set -euo pipefail
22-
23-cd "$(dirname "$0")/.."
24-
25-if [ -f release.env ]; then
26- # shellcheck source=/dev/null
27- source release.env
28-fi
29-TAG="${1:-${TAG:-}}"
30-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
31- echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx/publish.sh v1.2.3)"
32- exit 1
33-fi
34-
35-# Secrets pasted with a trailing newline or stray spaces are a classic.
36-DOCKER_HANDLE="$(printf '%s' "${DOCKER_HANDLE:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
37-DOCKER_PAT="$(printf '%s' "${DOCKER_PAT:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
38-case "${DOCKER_HANDLE}" in
39-*@* | *:*)
40- echo "❌ DOCKER_HANDLE must be the Docker ID (username), not an e-mail: access tokens only pair with the username"
41- exit 1
42- ;;
43-esac
44-export IMAGE_OWNER="${IMAGE_OWNER:-${DOCKER_HANDLE:-k33g}}"
45-VERSION="${TAG#v}"
46-
47-SBX="${SBX:-sbx}"
48-if ! command -v "${SBX}" >/dev/null 2>&1; then
49- echo "❌ sbx not found (${SBX}): install Docker Sandboxes, or SBX=/path/to/sbx"
50- exit 1
51-fi
52-export SBX
53-
54-logged_in_here=""
55-if [ -n "${DOCKER_HANDLE}" ] && [ -n "${DOCKER_PAT}" ]; then
56- echo "🔐 docker login as ${DOCKER_HANDLE}"
57- printf '%s' "${DOCKER_PAT}" | docker login --username "${DOCKER_HANDLE}" --password-stdin
58- logged_in_here=1
59-elif [ -n "${DOCKER_HANDLE}${DOCKER_PAT}" ]; then
60- echo "❌ set both DOCKER_HANDLE and DOCKER_PAT, or neither (to reuse an existing docker login)"
61- exit 1
62-else
63- echo "🔐 no DOCKER_HANDLE/DOCKER_PAT: using the existing docker login, publishing under ${IMAGE_OWNER}"
64-fi
65-# Whatever happens below, a login made here does not outlive the script.
66-cleanup() {
67- if [ -n "${logged_in_here}" ]; then
68- docker logout >/dev/null 2>&1 || true
69- fi
70-}
71-trap cleanup EXIT
72-
73-echo
74-echo "═══ 1/2 image ${IMAGE_OWNER}/mm-sandbox:${VERSION}"
75-PUSH=1 ./docker-sbx/build.sh "${TAG}"
76-
77-echo
78-echo "═══ 2/2 kits ${IMAGE_OWNER}/mm-tui:${VERSION} and ${IMAGE_OWNER}/mm-acp:${VERSION}"
79-./docker-sbx/push-kits.sh "${TAG}"
80-
81-echo
82-echo "✨ Published ${TAG}. The kits' spec.yaml now name version ${VERSION} — commit them."
deleted file mode 100644
@@ -1,82 +0,0 @@
1-#!/usr/bin/env bash
2-# Build and publish everything to Docker Hub, by hand, in one go:
3-# <owner>/mm-sandbox:<version> the template image, linux/amd64 + linux/arm64
4-# <owner>/mm-tui:<version> the window-mode kit
5-# <owner>/mm-acp:<version> the editor (ACP) kit
6-#
7-# Usage:
8-# ./docker-sbx/publish.sh # TAG from release.env (v0.0.3 → 0.0.3)
9-# ./docker-sbx/publish.sh v0.0.4 # another tag
10-#
11-# Credentials, two environment variables:
12-# DOCKER_HANDLE the Docker Hub account — also the image owner (default k33g)
13-# DOCKER_PAT an access token with read/write scope
14-# With both set, the script logs in with them (and out at the end). With
15-# neither, it uses the login you already have (`docker login` done earlier).
16-#
17-# Needs: docker with buildx (Docker Desktop has it), and the sbx CLI for the
18-# kits (`SBX=/path/to/sbx` if it is not on the PATH). Pieces, runnable alone:
19-# PUSH=1 ./docker-sbx/build.sh TAG image only
20-# ./docker-sbx/push-kits.sh TAG kits only
21-set -euo pipefail
22-
23-cd "$(dirname "$0")/.."
24-
25-if [ -f release.env ]; then
26- # shellcheck source=/dev/null
27- source release.env
28-fi
29-TAG="${1:-${TAG:-}}"
30-if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
31- echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx/publish.sh v1.2.3)"
32- exit 1
33-fi
34-
35-# Secrets pasted with a trailing newline or stray spaces are a classic.
36-DOCKER_HANDLE="$(printf '%s' "${DOCKER_HANDLE:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
37-DOCKER_PAT="$(printf '%s' "${DOCKER_PAT:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
38-case "${DOCKER_HANDLE}" in
39-*@* | *:*)
40- echo "❌ DOCKER_HANDLE must be the Docker ID (username), not an e-mail: access tokens only pair with the username"
41- exit 1
42- ;;
43-esac
44-export IMAGE_OWNER="${IMAGE_OWNER:-${DOCKER_HANDLE:-k33g}}"
45-VERSION="${TAG#v}"
46-
47-SBX="${SBX:-sbx}"
48-if ! command -v "${SBX}" >/dev/null 2>&1; then
49- echo "❌ sbx not found (${SBX}): install Docker Sandboxes, or SBX=/path/to/sbx"
50- exit 1
51-fi
52-export SBX
53-
54-logged_in_here=""
55-if [ -n "${DOCKER_HANDLE}" ] && [ -n "${DOCKER_PAT}" ]; then
56- echo "🔐 docker login as ${DOCKER_HANDLE}"
57- printf '%s' "${DOCKER_PAT}" | docker login --username "${DOCKER_HANDLE}" --password-stdin
58- logged_in_here=1
59-elif [ -n "${DOCKER_HANDLE}${DOCKER_PAT}" ]; then
60- echo "❌ set both DOCKER_HANDLE and DOCKER_PAT, or neither (to reuse an existing docker login)"
61- exit 1
62-else
63- echo "🔐 no DOCKER_HANDLE/DOCKER_PAT: using the existing docker login, publishing under ${IMAGE_OWNER}"
64-fi
65-# Whatever happens below, a login made here does not outlive the script.
66-cleanup() {
67- if [ -n "${logged_in_here}" ]; then
68- docker logout >/dev/null 2>&1 || true
69- fi
70-}
71-trap cleanup EXIT
72-
73-echo
74-echo "═══ 1/2 image ${IMAGE_OWNER}/mm-sandbox:${VERSION}"
75-PUSH=1 ./docker-sbx/build.sh "${TAG}"
76-
77-echo
78-echo "═══ 2/2 kits ${IMAGE_OWNER}/mm-tui:${VERSION} and ${IMAGE_OWNER}/mm-acp:${VERSION}"
79-./docker-sbx/push-kits.sh "${TAG}"
80-
81-echo
82-echo "✨ Published ${TAG}. The kits' spec.yaml now name version ${VERSION} — commit them."
deleted docker-sbx/push-kits.sh +0 -59
deleted file mode 100644
@@ -1,59 +0,0 @@
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
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-# publish.sh runs this after the image. Push the image first: 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
deleted file mode 100644
@@ -1,59 +0,0 @@
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
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-# publish.sh runs this after the image. Push the image first: 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
deleted docker-sbx/sync-kits.sh +0 -37
deleted file mode 100644
@@ -1,37 +0,0 @@
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, so the published kits always name the image just 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
deleted file mode 100644
@@ -1,37 +0,0 @@
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, so the published kits always name the image just 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
deleted docker-sbx/template/Dockerfile +0 -143
deleted file mode 100644
@@ -1,143 +0,0 @@
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-# The pinned toolchains (/usr/local/go/bin, /usr/local/node/bin) must come
53-# before /usr/bin so they win over any Go or Node the base image ships.
54-ENV PATH=/usr/local/go/bin:/usr/local/node/bin:/home/agent/go/bin:$PATH
55-
56-# Without this, a go.mod whose `go` directive is newer than GO_VERSION makes the
57-# toolchain download and run a different Go, silently defeating the pin.
58-ENV GOTOOLCHAIN=local
59-
60-# ------------------------------------
61-# Shared curl options for every download below.
62-#
63-# ARG, not ENV: this is build-time only and must not leak into the image.
64-# ------------------------------------
65-ARG CURL_RETRY="--retry 5 --retry-all-errors --retry-delay 3 --connect-timeout 15"
66-
67-USER root
68-
69-# ------------------------------------
70-# Install Go toolchain and Node.js
71-# ------------------------------------
72-ARG GO_VERSION=1.26.0
73-ARG NODE_VERSION=24.21.0
74-ARG TARGETARCH
75-
76-RUN <<EOF
77-set -eux
78-apt-get update
79-apt-get install -y curl build-essential xz-utils
80-rm -rf /var/lib/apt/lists/*
81-EOF
82-
83-RUN <<EOF
84-set -eux
85-apt-get remove -y golang-go golang-doc
86-apt-get autoremove -y
87-curl ${CURL_RETRY} -C - -fsSL -o /tmp/go.tgz "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz"
88-rm -rf /usr/local/go
89-tar -C /usr/local -xzf /tmp/go.tgz
90-rm /tmp/go.tgz
91-/usr/local/go/bin/go version
92-EOF
93-
94-RUN <<EOF
95-set -eux
96-case "${TARGETARCH}" in
97- amd64) node_arch=x64 ;;
98- arm64) node_arch=arm64 ;;
99- *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;;
100-esac
101-curl ${CURL_RETRY} -C - -fsSL -o /tmp/node.tar.xz "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${node_arch}.tar.xz"
102-rm -rf /usr/local/node
103-mkdir -p /usr/local/node
104-tar -C /usr/local/node --strip-components=1 -xJf /tmp/node.tar.xz
105-rm /tmp/node.tar.xz
106-/usr/local/node/bin/node --version
107-/usr/local/node/bin/npm --version
108-EOF
109-
110-# ------------------------------------
111-# Persist the Go and Node environment for sandbox shells.
112-# /etc/sandbox-persistent.sh is sourced before every bash command in the sbx.
113-# ------------------------------------
114-RUN <<EOF
115-{
116- echo 'export PATH=/usr/local/go/bin:/usr/local/node/bin:/home/agent/go/bin:$PATH'
117- echo 'export GOTOOLCHAIN=local'
118-} >> /etc/sandbox-persistent.sh
119-EOF
120-
121-# Switch to agent user for Go tools installation (they go to /home/agent/go/bin)
122-USER agent
123-
124-# ------------------------------------
125-# Install Go developer tools
126-# ------------------------------------
127-ARG GOPLS_VERSION=v0.23.0
128-ARG X_TOOLS_VERSION=v0.49.0
129-ARG STATICCHECK_VERSION=v0.7.0
130-
131-# Retried: parallel multi-arch builds occasionally hit DNS timeouts on
132-# Docker Desktop's resolver. The module cache survives within this RUN,
133-# so a retry only fetches what's still missing.
134-RUN for i in 1 2 3 4 5; do \
135- go install golang.org/x/tools/gopls@${GOPLS_VERSION} \
136- && go install golang.org/x/tools/cmd/goimports@${X_TOOLS_VERSION} \
137- && go install honnef.co/go/tools/cmd/staticcheck@${STATICCHECK_VERSION} \
138- && exit 0; \
139- echo "go install failed (attempt $i), retrying..." >&2; sleep $((i * 5)); \
140- done; exit 1
141-
142-# Prove the binary runs on this platform before the image is tagged.
143-RUN mm --version && mm-tui --version
deleted file mode 100644
@@ -1,143 +0,0 @@
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-# The pinned toolchains (/usr/local/go/bin, /usr/local/node/bin) must come
53-# before /usr/bin so they win over any Go or Node the base image ships.
54-ENV PATH=/usr/local/go/bin:/usr/local/node/bin:/home/agent/go/bin:$PATH
55-
56-# Without this, a go.mod whose `go` directive is newer than GO_VERSION makes the
57-# toolchain download and run a different Go, silently defeating the pin.
58-ENV GOTOOLCHAIN=local
59-
60-# ------------------------------------
61-# Shared curl options for every download below.
62-#
63-# ARG, not ENV: this is build-time only and must not leak into the image.
64-# ------------------------------------
65-ARG CURL_RETRY="--retry 5 --retry-all-errors --retry-delay 3 --connect-timeout 15"
66-
67-USER root
68-
69-# ------------------------------------
70-# Install Go toolchain and Node.js
71-# ------------------------------------
72-ARG GO_VERSION=1.26.0
73-ARG NODE_VERSION=24.21.0
74-ARG TARGETARCH
75-
76-RUN <<EOF
77-set -eux
78-apt-get update
79-apt-get install -y curl build-essential xz-utils
80-rm -rf /var/lib/apt/lists/*
81-EOF
82-
83-RUN <<EOF
84-set -eux
85-apt-get remove -y golang-go golang-doc
86-apt-get autoremove -y
87-curl ${CURL_RETRY} -C - -fsSL -o /tmp/go.tgz "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz"
88-rm -rf /usr/local/go
89-tar -C /usr/local -xzf /tmp/go.tgz
90-rm /tmp/go.tgz
91-/usr/local/go/bin/go version
92-EOF
93-
94-RUN <<EOF
95-set -eux
96-case "${TARGETARCH}" in
97- amd64) node_arch=x64 ;;
98- arm64) node_arch=arm64 ;;
99- *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;;
100-esac
101-curl ${CURL_RETRY} -C - -fsSL -o /tmp/node.tar.xz "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${node_arch}.tar.xz"
102-rm -rf /usr/local/node
103-mkdir -p /usr/local/node
104-tar -C /usr/local/node --strip-components=1 -xJf /tmp/node.tar.xz
105-rm /tmp/node.tar.xz
106-/usr/local/node/bin/node --version
107-/usr/local/node/bin/npm --version
108-EOF
109-
110-# ------------------------------------
111-# Persist the Go and Node environment for sandbox shells.
112-# /etc/sandbox-persistent.sh is sourced before every bash command in the sbx.
113-# ------------------------------------
114-RUN <<EOF
115-{
116- echo 'export PATH=/usr/local/go/bin:/usr/local/node/bin:/home/agent/go/bin:$PATH'
117- echo 'export GOTOOLCHAIN=local'
118-} >> /etc/sandbox-persistent.sh
119-EOF
120-
121-# Switch to agent user for Go tools installation (they go to /home/agent/go/bin)
122-USER agent
123-
124-# ------------------------------------
125-# Install Go developer tools
126-# ------------------------------------
127-ARG GOPLS_VERSION=v0.23.0
128-ARG X_TOOLS_VERSION=v0.49.0
129-ARG STATICCHECK_VERSION=v0.7.0
130-
131-# Retried: parallel multi-arch builds occasionally hit DNS timeouts on
132-# Docker Desktop's resolver. The module cache survives within this RUN,
133-# so a retry only fetches what's still missing.
134-RUN for i in 1 2 3 4 5; do \
135- go install golang.org/x/tools/gopls@${GOPLS_VERSION} \
136- && go install golang.org/x/tools/cmd/goimports@${X_TOOLS_VERSION} \
137- && go install honnef.co/go/tools/cmd/staticcheck@${STATICCHECK_VERSION} \
138- && exit 0; \
139- echo "go install failed (attempt $i), retrying..." >&2; sleep $((i * 5)); \
140- done; exit 1
141-
142-# Prove the binary runs on this platform before the image is tagged.
143-RUN mm --version && mm-tui --version
deleted docker-sbx/template/mm-acp-info +0 -52
deleted file mode 100644
@@ -1,52 +0,0 @@
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
deleted file mode 100644
@@ -1,52 +0,0 @@
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
deleted docker-sbx/template/mm-tui +0 -11
deleted file mode 100644
@@ -1,11 +0,0 @@
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 "$@"
deleted file mode 100644
@@ -1,11 +0,0 @@
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 "$@"
deleted sandboxes/README.md +0 -3
deleted file mode 100644
@@ -1,3 +0,0 @@
1-
2-sbx rm mm-test
3-sbx run --name mm-test ./sbx-kits/mini-me
\ No newline at end of file
deleted file mode 100644
@@ -1,3 +0,0 @@
1-
2-sbx rm mm-test
3-sbx run --name mm-test ./sbx-kits/mini-me
\ No newline at end of file\ No newline at end of file
deleted sandboxes/docker-sbx/AGENTS.md +0 -3
deleted file mode 100644
@@ -1,3 +0,0 @@
1-# AGENTS.md
2-
3-The secret word is agent.
deleted file mode 100644
@@ -1,3 +0,0 @@
1-# AGENTS.md
2-
3-The secret word is agent.
deleted sandboxes/docker-sbx/sbx-kits/cli-tools/cli-context.md +0 -5
deleted file mode 100644
@@ -1,5 +0,0 @@
1-## CLI tools
2-
3-Prefer these installed tools: `rg` (ripgrep) instead of `grep -r`, `eza -la --git`
4-(or `eza --tree -L 2`) instead of `ls`/`tree`, and `bat -n --paging=never <file>`
5-to read a file with line numbers.
deleted file mode 100644
@@ -1,5 +0,0 @@
1-## CLI tools
2-
3-Prefer these installed tools: `rg` (ripgrep) instead of `grep -r`, `eza -la --git`
4-(or `eza --tree -L 2`) instead of `ls`/`tree`, and `bat -n --paging=never <file>`
5-to read a file with line numbers.
deleted sandboxes/docker-sbx/sbx-kits/cli-tools/cli-tools.dockerfile +0 -37
deleted file mode 100644
@@ -1,37 +0,0 @@
1-# syntax=docker/dockerfile:1
2-FROM debian:trixie-slim AS build
3-ARG RG_VERSION
4-ARG BAT_VERSION
5-ARG EZA_VERSION
6-ARG TARGETARCH
7-
8-RUN apt-get update \
9- && apt-get install -y --no-install-recommends curl ca-certificates tar gzip findutils \
10- && rm -rf /var/lib/apt/lists/*
11-
12-# Static (musl) builds where upstream publishes them for the architecture.
13-# eza only ships a musl build for x86_64; on arm64 we use its gnu build,
14-# which runs on the Ubuntu-based sandbox templates (glibc).
15-RUN set -eu; \
16- case "${TARGETARCH}" in \
17- amd64) arch=x86_64; eza_triple=x86_64-unknown-linux-musl ;; \
18- arm64) arch=aarch64; eza_triple=aarch64-unknown-linux-gnu ;; \
19- *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
20- esac; \
21- mkdir -p /out/usr/local/bin /tmp/rg /tmp/bat /tmp/eza; \
22- \
23- curl -fsSL "https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/ripgrep-${RG_VERSION}-${arch}-unknown-linux-musl.tar.gz" \
24- | tar -xz -C /tmp/rg; \
25- install -m 0755 "$(find /tmp/rg -type f -name rg | head -n1)" /out/usr/local/bin/rg; \
26- \
27- curl -fsSL "https://github.com/sharkdp/bat/releases/download/v${BAT_VERSION}/bat-v${BAT_VERSION}-${arch}-unknown-linux-musl.tar.gz" \
28- | tar -xz -C /tmp/bat; \
29- install -m 0755 "$(find /tmp/bat -type f -name bat | head -n1)" /out/usr/local/bin/bat; \
30- \
31- curl -fsSL "https://github.com/eza-community/eza/releases/download/v${EZA_VERSION}/eza_${eza_triple}.tar.gz" \
32- | tar -xz -C /tmp/eza; \
33- install -m 0755 "$(find /tmp/eza -type f -name eza | head -n1)" /out/usr/local/bin/eza
34-
35-# Overlay: only the three binaries land on the workload.
36-FROM scratch
37-COPY --from=build /out/ /
deleted file mode 100644
@@ -1,37 +0,0 @@
1-# syntax=docker/dockerfile:1
2-FROM debian:trixie-slim AS build
3-ARG RG_VERSION
4-ARG BAT_VERSION
5-ARG EZA_VERSION
6-ARG TARGETARCH
7-
8-RUN apt-get update \
9- && apt-get install -y --no-install-recommends curl ca-certificates tar gzip findutils \
10- && rm -rf /var/lib/apt/lists/*
11-
12-# Static (musl) builds where upstream publishes them for the architecture.
13-# eza only ships a musl build for x86_64; on arm64 we use its gnu build,
14-# which runs on the Ubuntu-based sandbox templates (glibc).
15-RUN set -eu; \
16- case "${TARGETARCH}" in \
17- amd64) arch=x86_64; eza_triple=x86_64-unknown-linux-musl ;; \
18- arm64) arch=aarch64; eza_triple=aarch64-unknown-linux-gnu ;; \
19- *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
20- esac; \
21- mkdir -p /out/usr/local/bin /tmp/rg /tmp/bat /tmp/eza; \
22- \
23- curl -fsSL "https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/ripgrep-${RG_VERSION}-${arch}-unknown-linux-musl.tar.gz" \
24- | tar -xz -C /tmp/rg; \
25- install -m 0755 "$(find /tmp/rg -type f -name rg | head -n1)" /out/usr/local/bin/rg; \
26- \
27- curl -fsSL "https://github.com/sharkdp/bat/releases/download/v${BAT_VERSION}/bat-v${BAT_VERSION}-${arch}-unknown-linux-musl.tar.gz" \
28- | tar -xz -C /tmp/bat; \
29- install -m 0755 "$(find /tmp/bat -type f -name bat | head -n1)" /out/usr/local/bin/bat; \
30- \
31- curl -fsSL "https://github.com/eza-community/eza/releases/download/v${EZA_VERSION}/eza_${eza_triple}.tar.gz" \
32- | tar -xz -C /tmp/eza; \
33- install -m 0755 "$(find /tmp/eza -type f -name eza | head -n1)" /out/usr/local/bin/eza
34-
35-# Overlay: only the three binaries land on the workload.
36-FROM scratch
37-COPY --from=build /out/ /
deleted sandboxes/docker-sbx/sbx-kits/go-toolchain/go-context.md +0 -6
deleted file mode 100644
@@ -1,6 +0,0 @@
1-## Go
2-
3-`go`, `gofmt` and `gopls` are installed (`/usr/local/go`). Run `go build ./...`
4-and `go test ./...` before reporting a task complete. Prefer `gopls` for
5-navigation and refactoring (definitions, references, rename) over text search.
6-Module downloads go through `proxy.golang.org`; other hosts may be blocked.
deleted file mode 100644
@@ -1,6 +0,0 @@
1-## Go
2-
3-`go`, `gofmt` and `gopls` are installed (`/usr/local/go`). Run `go build ./...`
4-and `go test ./...` before reporting a task complete. Prefer `gopls` for
5-navigation and refactoring (definitions, references, rename) over text search.
6-Module downloads go through `proxy.golang.org`; other hosts may be blocked.
deleted sandboxes/docker-sbx/sbx-kits/go-toolchain/go-toolchain.dockerfile +0 -29
deleted file mode 100644
@@ -1,29 +0,0 @@
1-# syntax=docker/dockerfile:1
2-
3-# --- build stage: download Go, build gopls with that same Go -----------------
4-FROM debian:trixie-slim AS build
5-ARG GO_VERSION
6-ARG GOPLS_VERSION=latest
7-ARG TARGETARCH
8-
9-RUN apt-get update \
10- && apt-get install -y --no-install-recommends curl ca-certificates \
11- && rm -rf /var/lib/apt/lists/*
12-
13-RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" \
14- | tar -C /usr/local -xz \
15- && rm -rf /usr/local/go/test
16-
17-# Static gopls, installed straight into the overlay tree.
18-ENV PATH=/usr/local/go/bin:${PATH} \
19- CGO_ENABLED=0 \
20- GOBIN=/out/usr/local/bin \
21- GOFLAGS=-trimpath
22-RUN go install golang.org/x/tools/gopls@${GOPLS_VERSION} \
23- && ln -s /usr/local/go/bin/go /out/usr/local/bin/go \
24- && ln -s /usr/local/go/bin/gofmt /out/usr/local/bin/gofmt
25-
26-# --- overlay: only the toolchain and the binaries land on the workload -------
27-FROM scratch
28-COPY --from=build /usr/local/go /usr/local/go
29-COPY --from=build /out/ /
deleted file mode 100644
@@ -1,29 +0,0 @@
1-# syntax=docker/dockerfile:1
2-
3-# --- build stage: download Go, build gopls with that same Go -----------------
4-FROM debian:trixie-slim AS build
5-ARG GO_VERSION
6-ARG GOPLS_VERSION=latest
7-ARG TARGETARCH
8-
9-RUN apt-get update \
10- && apt-get install -y --no-install-recommends curl ca-certificates \
11- && rm -rf /var/lib/apt/lists/*
12-
13-RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" \
14- | tar -C /usr/local -xz \
15- && rm -rf /usr/local/go/test
16-
17-# Static gopls, installed straight into the overlay tree.
18-ENV PATH=/usr/local/go/bin:${PATH} \
19- CGO_ENABLED=0 \
20- GOBIN=/out/usr/local/bin \
21- GOFLAGS=-trimpath
22-RUN go install golang.org/x/tools/gopls@${GOPLS_VERSION} \
23- && ln -s /usr/local/go/bin/go /out/usr/local/bin/go \
24- && ln -s /usr/local/go/bin/gofmt /out/usr/local/bin/gofmt
25-
26-# --- overlay: only the toolchain and the binaries land on the workload -------
27-FROM scratch
28-COPY --from=build /usr/local/go /usr/local/go
29-COPY --from=build /out/ /
deleted sandboxes/docker-sbx/sbx-kits/mini-me/context.md +0 -8
deleted file mode 100644
@@ -1,8 +0,0 @@
1-## Mini Me sandbox
2-
3-You are running inside a Docker sandbox. The project is mounted as the
4-workspace; run commands from its root. Network access is restricted: if a
5-download fails, report the blocked host instead of retrying.
6-
7-the secret word is k33gorg
8-
deleted file mode 100644
@@ -1,8 +0,0 @@
1-## Mini Me sandbox
2-
3-You are running inside a Docker sandbox. The project is mounted as the
4-workspace; run commands from its root. Network access is restricted: if a
5-download fails, report the blocked host instead of retrying.
6-
7-the secret word is k33gorg
8-
deleted sandboxes/docker-sbx/sbx-kits/mini-me/mini-me.dockerfile +0 -32
deleted file mode 100644
@@ -1,32 +0,0 @@
1-# syntax=docker/dockerfile:1
2-#
3-# Base: Docker's shell template = Ubuntu, non-root `agent` user (UID 1000),
4-# bash, git, curl, CA certificates. No agent pre-installed.
5-FROM docker/sandbox-templates:shell
6-
7-USER root
8-
9-# --- mm release v0.2.6 --------------------------------------------------------
10-# rickub release assets are addressed by UUID, so the version cannot be derived
11-# from a template URL: to bump, replace these four values (URLs + SHA-256 from
12-# the release page).
13-ARG TARGETARCH
14-ARG MM_URL_AMD64=https://rickub.com/bots-garden/mini-me/release-assets/d9ffa7b2-1be7-4b92-b892-5e35b35f16a1
15-ARG MM_SHA_AMD64=6a054a2ee31dffd97991c086c5477c0dd7ed60cde37d65926c9bdd1b6393df14
16-ARG MM_URL_ARM64=https://rickub.com/bots-garden/mini-me/release-assets/282bcdb5-65d8-4ce9-92ad-82e8e4283e19
17-ARG MM_SHA_ARM64=d6daa3305ba8fa48dbde06ecac21e3e0cb45ee9555beb52b91f45546f6e7d207
18-
19-RUN set -eu; \
20- case "${TARGETARCH}" in \
21- amd64) url="${MM_URL_AMD64}"; sha="${MM_SHA_AMD64}" ;; \
22- arm64) url="${MM_URL_ARM64}"; sha="${MM_SHA_ARM64}" ;; \
23- *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
24- esac; \
25- curl -fsSL "${url}" -o /usr/local/bin/mm; \
26- echo "${sha} /usr/local/bin/mm" | sha256sum -c -; \
27- chmod 0755 /usr/local/bin/mm
28-
29-# Back to the sandbox user, then declare the launch command.
30-USER agent
31-ENTRYPOINT ["mm"]
32-CMD ["-tui"]
\ No newline at end of file
deleted file mode 100644
@@ -1,32 +0,0 @@
1-# syntax=docker/dockerfile:1
2-#
3-# Base: Docker's shell template = Ubuntu, non-root `agent` user (UID 1000),
4-# bash, git, curl, CA certificates. No agent pre-installed.
5-FROM docker/sandbox-templates:shell
6-
7-USER root
8-
9-# --- mm release v0.2.6 --------------------------------------------------------
10-# rickub release assets are addressed by UUID, so the version cannot be derived
11-# from a template URL: to bump, replace these four values (URLs + SHA-256 from
12-# the release page).
13-ARG TARGETARCH
14-ARG MM_URL_AMD64=https://rickub.com/bots-garden/mini-me/release-assets/d9ffa7b2-1be7-4b92-b892-5e35b35f16a1
15-ARG MM_SHA_AMD64=6a054a2ee31dffd97991c086c5477c0dd7ed60cde37d65926c9bdd1b6393df14
16-ARG MM_URL_ARM64=https://rickub.com/bots-garden/mini-me/release-assets/282bcdb5-65d8-4ce9-92ad-82e8e4283e19
17-ARG MM_SHA_ARM64=d6daa3305ba8fa48dbde06ecac21e3e0cb45ee9555beb52b91f45546f6e7d207
18-
19-RUN set -eu; \
20- case "${TARGETARCH}" in \
21- amd64) url="${MM_URL_AMD64}"; sha="${MM_SHA_AMD64}" ;; \
22- arm64) url="${MM_URL_ARM64}"; sha="${MM_SHA_ARM64}" ;; \
23- *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
24- esac; \
25- curl -fsSL "${url}" -o /usr/local/bin/mm; \
26- echo "${sha} /usr/local/bin/mm" | sha256sum -c -; \
27- chmod 0755 /usr/local/bin/mm
28-
29-# Back to the sandbox user, then declare the launch command.
30-USER agent
31-ENTRYPOINT ["mm"]
32-CMD ["-tui"]
\ No newline at end of file\ No newline at end of file
added sbx/AGENTS.md +22 -0
new file mode 100644
@@ -0,0 +1,22 @@
1+# AGENTS.md
2+
3+## Mini Me sandbox
4+
5+You are running inside a Docker sandbox. The project is mounted as the
6+workspace; run commands from its root. Network access is restricted: if a
7+download fails, report the blocked host instead of retrying.
8+
9+the secret word is k33gorg
10+
11+## CLI tools
12+
13+Prefer these installed tools: `rg` (ripgrep) instead of `grep -r`, `eza -la --git`
14+(or `eza --tree -L 2`) instead of `ls`/`tree`, and `bat -n --paging=never <file>`
15+to read a file with line numbers.
16+
17+## Go
18+
19+`go`, `gofmt` and `gopls` are installed (`/usr/local/go`). Run `go build ./...`
20+and `go test ./...` before reporting a task complete. Prefer `gopls` for
21+navigation and refactoring (definitions, references, rename) over text search.
22+Module downloads go through `proxy.golang.org`; other hosts may be blocked.
new file mode 100644
@@ -0,0 +1,22 @@
1+# AGENTS.md
2+
3+## Mini Me sandbox
4+
5+You are running inside a Docker sandbox. The project is mounted as the
6+workspace; run commands from its root. Network access is restricted: if a
7+download fails, report the blocked host instead of retrying.
8+
9+the secret word is k33gorg
10+
11+## CLI tools
12+
13+Prefer these installed tools: `rg` (ripgrep) instead of `grep -r`, `eza -la --git`
14+(or `eza --tree -L 2`) instead of `ls`/`tree`, and `bat -n --paging=never <file>`
15+to read a file with line numbers.
16+
17+## Go
18+
19+`go`, `gofmt` and `gopls` are installed (`/usr/local/go`). Run `go build ./...`
20+and `go test ./...` before reporting a task complete. Prefer `gopls` for
21+navigation and refactoring (definitions, references, rename) over text search.
22+Module downloads go through `proxy.golang.org`; other hosts may be blocked.
added sbx/README.md +28 -0
new file mode 100644
@@ -0,0 +1,28 @@
1+
2+If the agent config file is name `agent.yaml` (default value), you don't need to specify the name of the config file.
3+
4+sbx run --name mm-0.3.0 ./kits/mini-me
5+
6+sbx run --name mm-0.3.0 ./kits/mini-me -- -tui -config agent.lucy.yaml
7+
8+sbx run --name mm-0.3.0 ./kits/mini-me --kit ./kits/go-toolchain --kit ./kits/cli-tools -- -tui -config agent.yaml
9+
10+
11+## ACP
12+sbx create --name mm-acp ./kits/mini-me . --kit ./kits/go-toolchain
13+
14+sbx exec -i mm-acp mm -acp -config agent.lucy.yaml
15+
16+
17+##
18+
19+sbx run --name mm-0.3.0 ./kits/mini-me
20+
21+$ sbx run "git+https://git.rickub.com/bots-garden/mini-me.git#ref=<REVISION>&dir=sbx-kits/mini-me" \
22+ --kit "git+https://github.com/<ORG>/<REPO>.git#ref=<REVISION>&dir=sbx-kits/go-toolchain"
23+
24+
25+https://rickub.com/bots-garden/mini-me/releases/v0.3.0
26+
27+$ git rev-parse HEAD # commit courant
28+$ git rev-parse v1.0.0^{commit} # commit derrière un tag (annoté ou non)
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,28 @@
1+
2+If the agent config file is name `agent.yaml` (default value), you don't need to specify the name of the config file.
3+
4+sbx run --name mm-0.3.0 ./kits/mini-me
5+
6+sbx run --name mm-0.3.0 ./kits/mini-me -- -tui -config agent.lucy.yaml
7+
8+sbx run --name mm-0.3.0 ./kits/mini-me --kit ./kits/go-toolchain --kit ./kits/cli-tools -- -tui -config agent.yaml
9+
10+
11+## ACP
12+sbx create --name mm-acp ./kits/mini-me . --kit ./kits/go-toolchain
13+
14+sbx exec -i mm-acp mm -acp -config agent.lucy.yaml
15+
16+
17+##
18+
19+sbx run --name mm-0.3.0 ./kits/mini-me
20+
21+$ sbx run "git+https://git.rickub.com/bots-garden/mini-me.git#ref=<REVISION>&dir=sbx-kits/mini-me" \
22+ --kit "git+https://github.com/<ORG>/<REPO>.git#ref=<REVISION>&dir=sbx-kits/go-toolchain"
23+
24+
25+https://rickub.com/bots-garden/mini-me/releases/v0.3.0
26+
27+$ git rev-parse HEAD # commit courant
28+$ git rev-parse v1.0.0^{commit} # commit derrière un tag (annoté ou non)
\ No newline at end of file\ No newline at end of file
added sbx/agent.lucy.yaml +210 -0
new file mode 100644
@@ -0,0 +1,210 @@
1+# Agent settings — Lucy: mini-me on hf.co/Menlo/Lucy-gguf:Q4_K_M, served by llmman (https://github.com/llmmanorg/llmman)
2+# through its OpenAI-compatible endpoint (/v1/chat/completions).
3+#
4+# llmman pull hf.co/Menlo/Lucy-gguf:Q4_K_M # optional: the first question pulls it otherwise
5+# llmman serve # 127.0.0.1:17434
6+#
7+# llmman loads the model on the first request (in its own llama-server) and
8+# unloads it after five idle minutes.
9+provider: llmman
10+
11+# The model id exactly as `llmman list` / GET /v1/models spells it.
12+model: hf.co/Menlo/Lucy-gguf:Q4_K_M
13+
14+# `llmman serve`'s default bind; the OpenAI routes sit under /v1.
15+baseUrl: http://127.0.0.1:17434/v1
16+
17+# From a Docker sandbox, the daemon runs on the host.
18+fallback: http://host.docker.internal:17434/v1
19+
20+# Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it
21+# listens beyond loopback); unset otherwise. The key never goes in this file.
22+# apiKeyEnv: LLMMAN_API_KEY
23+
24+# Yolo mode. `true` (default): the tools run without asking.
25+# `false`: every bash call, file write/edit, fetch_content save, lsp rename and plan change
26+# waits for your answer — [a] once, [s] for the session, [r] reject, [n] never — in the
27+# terminal, the window and the editor; MCP tools ask too.
28+# bashTool / editTools still decide which tools EXIST. Called through /ask (mmConfigs),
29+# an agent follows its asker's yolo, not this one. Override for one run: AGENT_YOLO=false.
30+yolo: true
31+
32+# The `bash` tool.
33+# `false` removes it: the model can still read and edit files (editTools) and load skills,
34+# but never runs a command. If you turn it off, reword the system prompt below — it says "You have a bash tool".
35+bashTool: true
36+
37+# The built-in file tools: read_file, write_file, edit_file.
38+editTools: true
39+
40+# The built-in plan tool for managing multi-step plans.
41+# Set to false to disable plan creation and tracking via the `plan` tool.
42+planTool: true
43+
44+# Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename).
45+# The file extension picks the server. A server missing from the PATH is skipped with a warning.
46+# No server listed = no `lsp` tool. Examples (uncomment what you have installed):
47+# lsp:
48+# servers:
49+# - name: gopls
50+# command: gopls
51+# extensions: [".go"]
52+# - name: typescript
53+# command: typescript-language-server
54+# args: ["--stdio"]
55+# extensions: [".ts", ".tsx", ".js", ".jsx"]
56+# - name: python
57+# command: pyright-langserver
58+# args: ["--stdio"]
59+# extensions: [".py"]
60+# - name: rust
61+# command: rust-analyzer
62+# extensions: [".rs"]
63+
64+# How many tokens the server actually serves.
65+# 0 = ask llmman: /api/ps tells it once the model is loaded, so the window is
66+# learned before the second question. Set it here if you want it from the start
67+# — and to the same value as LLMMAN_CONTEXT_LENGTH if you set that variable.
68+contextWindow: 0
69+
70+# Max number of characters a tool returns to the model.
71+# Context safeguard: beyond that, the output is truncated (beginning + end kept).
72+maxOutput: 16000
73+
74+# Max number of model <-> tools round trips for a single question.
75+# Raise it for tasks that need long chains of commands.
76+maxTurns: 40
77+
78+# Where the `read_skill` tool looks for its markdown procedures.
79+# The path is relative to the CURRENT DIRECTORY: run the agent from demo-llmman/.
80+skillsDir: ../skills
81+
82+# Persistent sessions, per project.
83+# When enabled, every conversation is saved as one JSON file under `dir`.
84+# `/sessions` lists them, `/resume` continues one; in an editor, "Reload Agent" replays the thread.
85+sessions:
86+ enabled: true
87+ dir: .mm/sessions
88+
89+# How many lines of a command's output are echoed to the terminal.
90+# 0 disables it.
91+previewLines: 20
92+
93+displayCommands: true
94+# Show what a thinking model reasons about before it answers (dim italic in the
95+# terminal, its own style in the window, a thought chunk in an editor).
96+# The reasoning is always READ — it is what keeps the watchdog alive while the
97+# model thinks — this only says whether to show it.
98+showThinking: true
99+
100+acp:
101+ name: lucy
102+ title: Lucy (coding agent)
103+
104+# The system prompt: what the agent is, and what it is allowed to do.
105+# This is the knob to play with — it is the shortest path to changing behaviour.
106+system: |
107+ Your name is Lucy.
108+ You are a coding agent working in a terminal.
109+ You have a "bash" tool to run shell commands.
110+ Use it to explore files, run tests, inspect the repository, etc.
111+ Chain several commands if needed, then answer clearly in English.
112+
113+ A request often mixes things you answer from yourself ("say hello") with
114+ things only a command can answer ("list the files"). Handle every part, in
115+ the order asked, and run a command for each part that needs one.
116+ Never state the contents of a file, the output of a command, or the state of
117+ the repository unless a command in THIS answer returned it. What you did not
118+ read, you do not know: run the command instead of recalling it.
119+
120+ SKILLS
121+ You have a second tool, `read_skill`. Its description lists the procedures
122+ available for this project — one per kind of task.
123+
124+ Any request to DO something to a Go project is a skill, not a shell command
125+ you invent. Match the request against that list, call `read_skill` FIRST,
126+ before any bash command, and then follow what it says step by step.
127+
128+ FILE EDITING
129+ You have three tools for files: `read_file`, `edit_file` and `write_file`.
130+ They are how a file gets read and changed here: each change is exact,
131+ checked before it is written, and comes back as a diff with line numbers.
132+ bash is for running things — building, testing, listing, searching.
133+
134+ - Read before you write: call `read_file` on the file (numbered=true when
135+ you need line numbers). You cannot target text you have not seen; never
136+ rely on what you think you remember about a file.
137+ - To change an existing file, call `edit_file` with one or more {old, new}
138+ pairs. `old` is copied from the file character for character — same
139+ spaces, same indentation, same line breaks — and appears exactly once:
140+ add the surrounding lines until it is unique. Several pairs are applied
141+ together, against the original file. An empty `new` deletes the text.
142+ - Call `write_file` only to create a file, or to rewrite one entirely and
143+ on purpose. On an existing file it replaces everything, including what
144+ you did not intend to touch.
145+ - Read the diff the tool returns: it says exactly what changed and on which
146+ line. If `edit_file` refuses — text not found, ambiguous, overlapping
147+ edits — read the file again and fix `old`. Do not fall back to
148+ `write_file` to force the change through.
149+ - After editing code, run the narrowest check with bash: the formatter, the
150+ compiler, or the test covering that file.
151+
152+ RULES
153+ - Keep everything the file already does, unless the user asked to remove it.
154+ - Touch only the files the request is about. Do not add tests, files or
155+ features that were not asked for.
156+ - Never run a git command unless the user says git, commit or push.
157+ - Never move, rename or delete a file unless the user asked for it.
158+ - Then answer in English, in a few lines.
159+ - If you don't know how to use a <cli>, run `<cli> --help` (or `<cli> help`)
160+ to understand the options, then run the command.
161+
162+ BACKGROUND JOBS
163+ Never let a command block the answer. Anything that serves, watches or runs
164+ long goes to the background, with BOTH streams redirected and its pid kept:
165+
166+ nohup <command> > /tmp/<job>.log 2>&1 & echo $! > /tmp/<job>.pid
167+
168+ Redirecting only stdout still blocks until the process exits. Read the
169+ `bg-jobs` skill before you wait on, inspect or stop such a job — each has a
170+ rule you cannot guess. Stop every job you started before you finish, and say
171+ which ones you left running.
172+
173+# Generation settings (OpenAI API keys). Low temperature for a coding agent:
174+# we want precise and reproducible answers, not creativity.
175+sampling:
176+ temperature: 0.0
177+ parallel_tool_calls: false
178+ top_p: 0.9
179+ max_tokens: 4096
180+
181+# Silence allowed between two tokens once the answer has started.
182+watchdogTimeout: 30s
183+
184+# Silence allowed while the model reads the prompt, before the first token:
185+# on a laptop a 25k-token prompt can take minutes. llama-server reports its
186+# progress meanwhile, through llmman ("Reading the prompt 12.0k/25.3k tokens"), and each report
187+# restarts this clock, so it only has to cover one batch of the prompt.
188+firstTokenTimeout: 3m
189+
190+# Context compression.
191+# ON here: the agent learns the window from /api/ps, so `threshold` has a number to apply to.
192+context:
193+ enabled: true
194+
195+ # Compress when the history reaches this share of the window.
196+ threshold: 75
197+
198+ # Fallback on the message count, for when the window is unknown.
199+ # One command costs 2 messages (call + response), so 80 is roughly 30 commands of history.
200+ maxMessages: 80
201+
202+ # How many recent questions (with their commands and answers) are kept as-is instead of being summarised.
203+ # The model works on the last few turns, so summarising them would make it redo what it just did.
204+ keepLastTurns: 3
205+
206+ # max_tokens of the summary request. Reasoning is turned off for it on this provider
207+ # (a thinking model would otherwise spend the budget thinking and write nothing).
208+ summaryMaxTokens: 1200
209+
210+ showStats: true
new file mode 100644
@@ -0,0 +1,210 @@
1+# Agent settings — Lucy: mini-me on hf.co/Menlo/Lucy-gguf:Q4_K_M, served by llmman (https://github.com/llmmanorg/llmman)
2+# through its OpenAI-compatible endpoint (/v1/chat/completions).
3+#
4+# llmman pull hf.co/Menlo/Lucy-gguf:Q4_K_M # optional: the first question pulls it otherwise
5+# llmman serve # 127.0.0.1:17434
6+#
7+# llmman loads the model on the first request (in its own llama-server) and
8+# unloads it after five idle minutes.
9+provider: llmman
10+
11+# The model id exactly as `llmman list` / GET /v1/models spells it.
12+model: hf.co/Menlo/Lucy-gguf:Q4_K_M
13+
14+# `llmman serve`'s default bind; the OpenAI routes sit under /v1.
15+baseUrl: http://127.0.0.1:17434/v1
16+
17+# From a Docker sandbox, the daemon runs on the host.
18+fallback: http://host.docker.internal:17434/v1
19+
20+# Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it
21+# listens beyond loopback); unset otherwise. The key never goes in this file.
22+# apiKeyEnv: LLMMAN_API_KEY
23+
24+# Yolo mode. `true` (default): the tools run without asking.
25+# `false`: every bash call, file write/edit, fetch_content save, lsp rename and plan change
26+# waits for your answer — [a] once, [s] for the session, [r] reject, [n] never — in the
27+# terminal, the window and the editor; MCP tools ask too.
28+# bashTool / editTools still decide which tools EXIST. Called through /ask (mmConfigs),
29+# an agent follows its asker's yolo, not this one. Override for one run: AGENT_YOLO=false.
30+yolo: true
31+
32+# The `bash` tool.
33+# `false` removes it: the model can still read and edit files (editTools) and load skills,
34+# but never runs a command. If you turn it off, reword the system prompt below — it says "You have a bash tool".
35+bashTool: true
36+
37+# The built-in file tools: read_file, write_file, edit_file.
38+editTools: true
39+
40+# The built-in plan tool for managing multi-step plans.
41+# Set to false to disable plan creation and tracking via the `plan` tool.
42+planTool: true
43+
44+# Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename).
45+# The file extension picks the server. A server missing from the PATH is skipped with a warning.
46+# No server listed = no `lsp` tool. Examples (uncomment what you have installed):
47+# lsp:
48+# servers:
49+# - name: gopls
50+# command: gopls
51+# extensions: [".go"]
52+# - name: typescript
53+# command: typescript-language-server
54+# args: ["--stdio"]
55+# extensions: [".ts", ".tsx", ".js", ".jsx"]
56+# - name: python
57+# command: pyright-langserver
58+# args: ["--stdio"]
59+# extensions: [".py"]
60+# - name: rust
61+# command: rust-analyzer
62+# extensions: [".rs"]
63+
64+# How many tokens the server actually serves.
65+# 0 = ask llmman: /api/ps tells it once the model is loaded, so the window is
66+# learned before the second question. Set it here if you want it from the start
67+# — and to the same value as LLMMAN_CONTEXT_LENGTH if you set that variable.
68+contextWindow: 0
69+
70+# Max number of characters a tool returns to the model.
71+# Context safeguard: beyond that, the output is truncated (beginning + end kept).
72+maxOutput: 16000
73+
74+# Max number of model <-> tools round trips for a single question.
75+# Raise it for tasks that need long chains of commands.
76+maxTurns: 40
77+
78+# Where the `read_skill` tool looks for its markdown procedures.
79+# The path is relative to the CURRENT DIRECTORY: run the agent from demo-llmman/.
80+skillsDir: ../skills
81+
82+# Persistent sessions, per project.
83+# When enabled, every conversation is saved as one JSON file under `dir`.
84+# `/sessions` lists them, `/resume` continues one; in an editor, "Reload Agent" replays the thread.
85+sessions:
86+ enabled: true
87+ dir: .mm/sessions
88+
89+# How many lines of a command's output are echoed to the terminal.
90+# 0 disables it.
91+previewLines: 20
92+
93+displayCommands: true
94+# Show what a thinking model reasons about before it answers (dim italic in the
95+# terminal, its own style in the window, a thought chunk in an editor).
96+# The reasoning is always READ — it is what keeps the watchdog alive while the
97+# model thinks — this only says whether to show it.
98+showThinking: true
99+
100+acp:
101+ name: lucy
102+ title: Lucy (coding agent)
103+
104+# The system prompt: what the agent is, and what it is allowed to do.
105+# This is the knob to play with — it is the shortest path to changing behaviour.
106+system: |
107+ Your name is Lucy.
108+ You are a coding agent working in a terminal.
109+ You have a "bash" tool to run shell commands.
110+ Use it to explore files, run tests, inspect the repository, etc.
111+ Chain several commands if needed, then answer clearly in English.
112+
113+ A request often mixes things you answer from yourself ("say hello") with
114+ things only a command can answer ("list the files"). Handle every part, in
115+ the order asked, and run a command for each part that needs one.
116+ Never state the contents of a file, the output of a command, or the state of
117+ the repository unless a command in THIS answer returned it. What you did not
118+ read, you do not know: run the command instead of recalling it.
119+
120+ SKILLS
121+ You have a second tool, `read_skill`. Its description lists the procedures
122+ available for this project — one per kind of task.
123+
124+ Any request to DO something to a Go project is a skill, not a shell command
125+ you invent. Match the request against that list, call `read_skill` FIRST,
126+ before any bash command, and then follow what it says step by step.
127+
128+ FILE EDITING
129+ You have three tools for files: `read_file`, `edit_file` and `write_file`.
130+ They are how a file gets read and changed here: each change is exact,
131+ checked before it is written, and comes back as a diff with line numbers.
132+ bash is for running things — building, testing, listing, searching.
133+
134+ - Read before you write: call `read_file` on the file (numbered=true when
135+ you need line numbers). You cannot target text you have not seen; never
136+ rely on what you think you remember about a file.
137+ - To change an existing file, call `edit_file` with one or more {old, new}
138+ pairs. `old` is copied from the file character for character — same
139+ spaces, same indentation, same line breaks — and appears exactly once:
140+ add the surrounding lines until it is unique. Several pairs are applied
141+ together, against the original file. An empty `new` deletes the text.
142+ - Call `write_file` only to create a file, or to rewrite one entirely and
143+ on purpose. On an existing file it replaces everything, including what
144+ you did not intend to touch.
145+ - Read the diff the tool returns: it says exactly what changed and on which
146+ line. If `edit_file` refuses — text not found, ambiguous, overlapping
147+ edits — read the file again and fix `old`. Do not fall back to
148+ `write_file` to force the change through.
149+ - After editing code, run the narrowest check with bash: the formatter, the
150+ compiler, or the test covering that file.
151+
152+ RULES
153+ - Keep everything the file already does, unless the user asked to remove it.
154+ - Touch only the files the request is about. Do not add tests, files or
155+ features that were not asked for.
156+ - Never run a git command unless the user says git, commit or push.
157+ - Never move, rename or delete a file unless the user asked for it.
158+ - Then answer in English, in a few lines.
159+ - If you don't know how to use a <cli>, run `<cli> --help` (or `<cli> help`)
160+ to understand the options, then run the command.
161+
162+ BACKGROUND JOBS
163+ Never let a command block the answer. Anything that serves, watches or runs
164+ long goes to the background, with BOTH streams redirected and its pid kept:
165+
166+ nohup <command> > /tmp/<job>.log 2>&1 & echo $! > /tmp/<job>.pid
167+
168+ Redirecting only stdout still blocks until the process exits. Read the
169+ `bg-jobs` skill before you wait on, inspect or stop such a job — each has a
170+ rule you cannot guess. Stop every job you started before you finish, and say
171+ which ones you left running.
172+
173+# Generation settings (OpenAI API keys). Low temperature for a coding agent:
174+# we want precise and reproducible answers, not creativity.
175+sampling:
176+ temperature: 0.0
177+ parallel_tool_calls: false
178+ top_p: 0.9
179+ max_tokens: 4096
180+
181+# Silence allowed between two tokens once the answer has started.
182+watchdogTimeout: 30s
183+
184+# Silence allowed while the model reads the prompt, before the first token:
185+# on a laptop a 25k-token prompt can take minutes. llama-server reports its
186+# progress meanwhile, through llmman ("Reading the prompt 12.0k/25.3k tokens"), and each report
187+# restarts this clock, so it only has to cover one batch of the prompt.
188+firstTokenTimeout: 3m
189+
190+# Context compression.
191+# ON here: the agent learns the window from /api/ps, so `threshold` has a number to apply to.
192+context:
193+ enabled: true
194+
195+ # Compress when the history reaches this share of the window.
196+ threshold: 75
197+
198+ # Fallback on the message count, for when the window is unknown.
199+ # One command costs 2 messages (call + response), so 80 is roughly 30 commands of history.
200+ maxMessages: 80
201+
202+ # How many recent questions (with their commands and answers) are kept as-is instead of being summarised.
203+ # The model works on the last few turns, so summarising them would make it redo what it just did.
204+ keepLastTurns: 3
205+
206+ # max_tokens of the summary request. Reasoning is turned off for it on this provider
207+ # (a thinking model would otherwise spend the budget thinking and write nothing).
208+ summaryMaxTokens: 1200
209+
210+ showStats: true
added sbx/agent.yaml +211 -0
new file mode 100644
@@ -0,0 +1,211 @@
1+# Agent settings — Jan: mini-me on hf.co/Menlo/Jan-nano-gguf:Q4_K_M, served by llmman (https://github.com/llmmanorg/llmman)
2+# through its OpenAI-compatible endpoint (/v1/chat/completions).
3+#
4+# llmman pull hf.co/Menlo/Jan-nano-gguf:Q4_K_M # optional: the first question pulls it otherwise
5+# llmman serve # 127.0.0.1:17434
6+#
7+# llmman loads the model on the first request (in its own llama-server) and
8+# unloads it after five idle minutes.
9+provider: llmman
10+
11+# The model id exactly as `llmman list` / GET /v1/models spells it.
12+model: hf.co/Menlo/Jan-nano-gguf:Q4_K_M
13+
14+# `llmman serve`'s default bind; the OpenAI routes sit under /v1.
15+baseUrl: http://127.0.0.1:17434/v1
16+
17+# From a Docker sandbox, the daemon runs on the host.
18+fallback: http://host.docker.internal:17434/v1
19+
20+# Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it
21+# listens beyond loopback); unset otherwise. The key never goes in this file.
22+# apiKeyEnv: LLMMAN_API_KEY
23+
24+# Yolo mode. `true` (default): the tools run without asking.
25+# `false`: every bash call, file write/edit, fetch_content save, lsp rename and plan change
26+# waits for your answer — [a] once, [s] for the session, [r] reject, [n] never — in the
27+# terminal, the window and the editor; MCP tools ask too.
28+# bashTool / editTools still decide which tools EXIST. Called through /ask (mmConfigs),
29+# an agent follows its asker's yolo, not this one. Override for one run: AGENT_YOLO=false.
30+yolo: true
31+
32+# The `bash` tool.
33+# `false` removes it: the model can still read and edit files (editTools) and load skills,
34+# but never runs a command. If you turn it off, reword the system prompt below — it says "You have a bash tool".
35+bashTool: true
36+
37+# The built-in file tools: read_file, write_file, edit_file.
38+editTools: true
39+
40+# The built-in plan tool for managing multi-step plans.
41+# Set to false to disable plan creation and tracking via the `plan` tool.
42+planTool: true
43+
44+# Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename).
45+# The file extension picks the server. A server missing from the PATH is skipped with a warning.
46+# No server listed = no `lsp` tool. Examples (uncomment what you have installed):
47+# lsp:
48+# servers:
49+# - name: gopls
50+# command: gopls
51+# extensions: [".go"]
52+# - name: typescript
53+# command: typescript-language-server
54+# args: ["--stdio"]
55+# extensions: [".ts", ".tsx", ".js", ".jsx"]
56+# - name: python
57+# command: pyright-langserver
58+# args: ["--stdio"]
59+# extensions: [".py"]
60+# - name: rust
61+# command: rust-analyzer
62+# extensions: [".rs"]
63+
64+# How many tokens the server actually serves.
65+# 0 = ask llmman: /api/ps tells it once the model is loaded, so the window is
66+# learned before the second question. Set it here if you want it from the start
67+# — and to the same value as LLMMAN_CONTEXT_LENGTH if you set that variable.
68+contextWindow: 0
69+
70+# Max number of characters a tool returns to the model.
71+# Context safeguard: beyond that, the output is truncated (beginning + end kept).
72+maxOutput: 16000
73+
74+# Max number of model <-> tools round trips for a single question.
75+# Raise it for tasks that need long chains of commands.
76+maxTurns: 40
77+
78+# Where the `read_skill` tool looks for its markdown procedures.
79+# The path is relative to the CURRENT DIRECTORY: run the agent from demo-llmman/.
80+skillsDir: ../skills
81+
82+# Persistent sessions, per project.
83+# When enabled, every conversation is saved as one JSON file under `dir`.
84+# `/sessions` lists them, `/resume` continues one; in an editor, "Reload Agent" replays the thread.
85+sessions:
86+ enabled: true
87+ dir: .mm/sessions
88+
89+# How many lines of a command's output are echoed to the terminal.
90+# 0 disables it.
91+previewLines: 20
92+
93+displayCommands: true
94+# Show what a thinking model reasons about before it answers (dim italic in the
95+# terminal, its own style in the window, a thought chunk in an editor).
96+# The reasoning is always READ — it is what keeps the watchdog alive while the
97+# model thinks — this only says whether to show it.
98+showThinking: true
99+
100+
101+acp:
102+ name: jan
103+ title: Jan (coding agent)
104+
105+# The system prompt: what the agent is, and what it is allowed to do.
106+# This is the knob to play with — it is the shortest path to changing behaviour.
107+system: |
108+ Your name is Jan.
109+ You are a coding agent working in a terminal.
110+ You have a "bash" tool to run shell commands.
111+ Use it to explore files, run tests, inspect the repository, etc.
112+ Chain several commands if needed, then answer clearly in English.
113+
114+ A request often mixes things you answer from yourself ("say hello") with
115+ things only a command can answer ("list the files"). Handle every part, in
116+ the order asked, and run a command for each part that needs one.
117+ Never state the contents of a file, the output of a command, or the state of
118+ the repository unless a command in THIS answer returned it. What you did not
119+ read, you do not know: run the command instead of recalling it.
120+
121+ SKILLS
122+ You have a second tool, `read_skill`. Its description lists the procedures
123+ available for this project — one per kind of task.
124+
125+ Any request to DO something to a Go project is a skill, not a shell command
126+ you invent. Match the request against that list, call `read_skill` FIRST,
127+ before any bash command, and then follow what it says step by step.
128+
129+ FILE EDITING
130+ You have three tools for files: `read_file`, `edit_file` and `write_file`.
131+ They are how a file gets read and changed here: each change is exact,
132+ checked before it is written, and comes back as a diff with line numbers.
133+ bash is for running things — building, testing, listing, searching.
134+
135+ - Read before you write: call `read_file` on the file (numbered=true when
136+ you need line numbers). You cannot target text you have not seen; never
137+ rely on what you think you remember about a file.
138+ - To change an existing file, call `edit_file` with one or more {old, new}
139+ pairs. `old` is copied from the file character for character — same
140+ spaces, same indentation, same line breaks — and appears exactly once:
141+ add the surrounding lines until it is unique. Several pairs are applied
142+ together, against the original file. An empty `new` deletes the text.
143+ - Call `write_file` only to create a file, or to rewrite one entirely and
144+ on purpose. On an existing file it replaces everything, including what
145+ you did not intend to touch.
146+ - Read the diff the tool returns: it says exactly what changed and on which
147+ line. If `edit_file` refuses — text not found, ambiguous, overlapping
148+ edits — read the file again and fix `old`. Do not fall back to
149+ `write_file` to force the change through.
150+ - After editing code, run the narrowest check with bash: the formatter, the
151+ compiler, or the test covering that file.
152+
153+ RULES
154+ - Keep everything the file already does, unless the user asked to remove it.
155+ - Touch only the files the request is about. Do not add tests, files or
156+ features that were not asked for.
157+ - Never run a git command unless the user says git, commit or push.
158+ - Never move, rename or delete a file unless the user asked for it.
159+ - Then answer in English, in a few lines.
160+ - If you don't know how to use a <cli>, run `<cli> --help` (or `<cli> help`)
161+ to understand the options, then run the command.
162+
163+ BACKGROUND JOBS
164+ Never let a command block the answer. Anything that serves, watches or runs
165+ long goes to the background, with BOTH streams redirected and its pid kept:
166+
167+ nohup <command> > /tmp/<job>.log 2>&1 & echo $! > /tmp/<job>.pid
168+
169+ Redirecting only stdout still blocks until the process exits. Read the
170+ `bg-jobs` skill before you wait on, inspect or stop such a job — each has a
171+ rule you cannot guess. Stop every job you started before you finish, and say
172+ which ones you left running.
173+
174+# Generation settings (OpenAI API keys). Low temperature for a coding agent:
175+# we want precise and reproducible answers, not creativity.
176+sampling:
177+ temperature: 0.0
178+ parallel_tool_calls: false
179+ top_p: 0.9
180+ max_tokens: 4096
181+
182+# Silence allowed between two tokens once the answer has started.
183+watchdogTimeout: 30s
184+
185+# Silence allowed while the model reads the prompt, before the first token:
186+# on a laptop a 25k-token prompt can take minutes. llama-server reports its
187+# progress meanwhile, through llmman ("Reading the prompt 12.0k/25.3k tokens"), and each report
188+# restarts this clock, so it only has to cover one batch of the prompt.
189+firstTokenTimeout: 3m
190+
191+# Context compression.
192+# ON here: the agent learns the window from /api/ps, so `threshold` has a number to apply to.
193+context:
194+ enabled: true
195+
196+ # Compress when the history reaches this share of the window.
197+ threshold: 75
198+
199+ # Fallback on the message count, for when the window is unknown.
200+ # One command costs 2 messages (call + response), so 80 is roughly 30 commands of history.
201+ maxMessages: 80
202+
203+ # How many recent questions (with their commands and answers) are kept as-is instead of being summarised.
204+ # The model works on the last few turns, so summarising them would make it redo what it just did.
205+ keepLastTurns: 3
206+
207+ # max_tokens of the summary request. Reasoning is turned off for it on this provider
208+ # (a thinking model would otherwise spend the budget thinking and write nothing).
209+ summaryMaxTokens: 1200
210+
211+ showStats: true
new file mode 100644
@@ -0,0 +1,211 @@
1+# Agent settings — Jan: mini-me on hf.co/Menlo/Jan-nano-gguf:Q4_K_M, served by llmman (https://github.com/llmmanorg/llmman)
2+# through its OpenAI-compatible endpoint (/v1/chat/completions).
3+#
4+# llmman pull hf.co/Menlo/Jan-nano-gguf:Q4_K_M # optional: the first question pulls it otherwise
5+# llmman serve # 127.0.0.1:17434
6+#
7+# llmman loads the model on the first request (in its own llama-server) and
8+# unloads it after five idle minutes.
9+provider: llmman
10+
11+# The model id exactly as `llmman list` / GET /v1/models spells it.
12+model: hf.co/Menlo/Jan-nano-gguf:Q4_K_M
13+
14+# `llmman serve`'s default bind; the OpenAI routes sit under /v1.
15+baseUrl: http://127.0.0.1:17434/v1
16+
17+# From a Docker sandbox, the daemon runs on the host.
18+fallback: http://host.docker.internal:17434/v1
19+
20+# Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it
21+# listens beyond loopback); unset otherwise. The key never goes in this file.
22+# apiKeyEnv: LLMMAN_API_KEY
23+
24+# Yolo mode. `true` (default): the tools run without asking.
25+# `false`: every bash call, file write/edit, fetch_content save, lsp rename and plan change
26+# waits for your answer — [a] once, [s] for the session, [r] reject, [n] never — in the
27+# terminal, the window and the editor; MCP tools ask too.
28+# bashTool / editTools still decide which tools EXIST. Called through /ask (mmConfigs),
29+# an agent follows its asker's yolo, not this one. Override for one run: AGENT_YOLO=false.
30+yolo: true
31+
32+# The `bash` tool.
33+# `false` removes it: the model can still read and edit files (editTools) and load skills,
34+# but never runs a command. If you turn it off, reword the system prompt below — it says "You have a bash tool".
35+bashTool: true
36+
37+# The built-in file tools: read_file, write_file, edit_file.
38+editTools: true
39+
40+# The built-in plan tool for managing multi-step plans.
41+# Set to false to disable plan creation and tracking via the `plan` tool.
42+planTool: true
43+
44+# Language servers for the `lsp` tool (definition, references, hover, symbols, diagnostics, rename).
45+# The file extension picks the server. A server missing from the PATH is skipped with a warning.
46+# No server listed = no `lsp` tool. Examples (uncomment what you have installed):
47+# lsp:
48+# servers:
49+# - name: gopls
50+# command: gopls
51+# extensions: [".go"]
52+# - name: typescript
53+# command: typescript-language-server
54+# args: ["--stdio"]
55+# extensions: [".ts", ".tsx", ".js", ".jsx"]
56+# - name: python
57+# command: pyright-langserver
58+# args: ["--stdio"]
59+# extensions: [".py"]
60+# - name: rust
61+# command: rust-analyzer
62+# extensions: [".rs"]
63+
64+# How many tokens the server actually serves.
65+# 0 = ask llmman: /api/ps tells it once the model is loaded, so the window is
66+# learned before the second question. Set it here if you want it from the start
67+# — and to the same value as LLMMAN_CONTEXT_LENGTH if you set that variable.
68+contextWindow: 0
69+
70+# Max number of characters a tool returns to the model.
71+# Context safeguard: beyond that, the output is truncated (beginning + end kept).
72+maxOutput: 16000
73+
74+# Max number of model <-> tools round trips for a single question.
75+# Raise it for tasks that need long chains of commands.
76+maxTurns: 40
77+
78+# Where the `read_skill` tool looks for its markdown procedures.
79+# The path is relative to the CURRENT DIRECTORY: run the agent from demo-llmman/.
80+skillsDir: ../skills
81+
82+# Persistent sessions, per project.
83+# When enabled, every conversation is saved as one JSON file under `dir`.
84+# `/sessions` lists them, `/resume` continues one; in an editor, "Reload Agent" replays the thread.
85+sessions:
86+ enabled: true
87+ dir: .mm/sessions
88+
89+# How many lines of a command's output are echoed to the terminal.
90+# 0 disables it.
91+previewLines: 20
92+
93+displayCommands: true
94+# Show what a thinking model reasons about before it answers (dim italic in the
95+# terminal, its own style in the window, a thought chunk in an editor).
96+# The reasoning is always READ — it is what keeps the watchdog alive while the
97+# model thinks — this only says whether to show it.
98+showThinking: true
99+
100+
101+acp:
102+ name: jan
103+ title: Jan (coding agent)
104+
105+# The system prompt: what the agent is, and what it is allowed to do.
106+# This is the knob to play with — it is the shortest path to changing behaviour.
107+system: |
108+ Your name is Jan.
109+ You are a coding agent working in a terminal.
110+ You have a "bash" tool to run shell commands.
111+ Use it to explore files, run tests, inspect the repository, etc.
112+ Chain several commands if needed, then answer clearly in English.
113+
114+ A request often mixes things you answer from yourself ("say hello") with
115+ things only a command can answer ("list the files"). Handle every part, in
116+ the order asked, and run a command for each part that needs one.
117+ Never state the contents of a file, the output of a command, or the state of
118+ the repository unless a command in THIS answer returned it. What you did not
119+ read, you do not know: run the command instead of recalling it.
120+
121+ SKILLS
122+ You have a second tool, `read_skill`. Its description lists the procedures
123+ available for this project — one per kind of task.
124+
125+ Any request to DO something to a Go project is a skill, not a shell command
126+ you invent. Match the request against that list, call `read_skill` FIRST,
127+ before any bash command, and then follow what it says step by step.
128+
129+ FILE EDITING
130+ You have three tools for files: `read_file`, `edit_file` and `write_file`.
131+ They are how a file gets read and changed here: each change is exact,
132+ checked before it is written, and comes back as a diff with line numbers.
133+ bash is for running things — building, testing, listing, searching.
134+
135+ - Read before you write: call `read_file` on the file (numbered=true when
136+ you need line numbers). You cannot target text you have not seen; never
137+ rely on what you think you remember about a file.
138+ - To change an existing file, call `edit_file` with one or more {old, new}
139+ pairs. `old` is copied from the file character for character — same
140+ spaces, same indentation, same line breaks — and appears exactly once:
141+ add the surrounding lines until it is unique. Several pairs are applied
142+ together, against the original file. An empty `new` deletes the text.
143+ - Call `write_file` only to create a file, or to rewrite one entirely and
144+ on purpose. On an existing file it replaces everything, including what
145+ you did not intend to touch.
146+ - Read the diff the tool returns: it says exactly what changed and on which
147+ line. If `edit_file` refuses — text not found, ambiguous, overlapping
148+ edits — read the file again and fix `old`. Do not fall back to
149+ `write_file` to force the change through.
150+ - After editing code, run the narrowest check with bash: the formatter, the
151+ compiler, or the test covering that file.
152+
153+ RULES
154+ - Keep everything the file already does, unless the user asked to remove it.
155+ - Touch only the files the request is about. Do not add tests, files or
156+ features that were not asked for.
157+ - Never run a git command unless the user says git, commit or push.
158+ - Never move, rename or delete a file unless the user asked for it.
159+ - Then answer in English, in a few lines.
160+ - If you don't know how to use a <cli>, run `<cli> --help` (or `<cli> help`)
161+ to understand the options, then run the command.
162+
163+ BACKGROUND JOBS
164+ Never let a command block the answer. Anything that serves, watches or runs
165+ long goes to the background, with BOTH streams redirected and its pid kept:
166+
167+ nohup <command> > /tmp/<job>.log 2>&1 & echo $! > /tmp/<job>.pid
168+
169+ Redirecting only stdout still blocks until the process exits. Read the
170+ `bg-jobs` skill before you wait on, inspect or stop such a job — each has a
171+ rule you cannot guess. Stop every job you started before you finish, and say
172+ which ones you left running.
173+
174+# Generation settings (OpenAI API keys). Low temperature for a coding agent:
175+# we want precise and reproducible answers, not creativity.
176+sampling:
177+ temperature: 0.0
178+ parallel_tool_calls: false
179+ top_p: 0.9
180+ max_tokens: 4096
181+
182+# Silence allowed between two tokens once the answer has started.
183+watchdogTimeout: 30s
184+
185+# Silence allowed while the model reads the prompt, before the first token:
186+# on a laptop a 25k-token prompt can take minutes. llama-server reports its
187+# progress meanwhile, through llmman ("Reading the prompt 12.0k/25.3k tokens"), and each report
188+# restarts this clock, so it only has to cover one batch of the prompt.
189+firstTokenTimeout: 3m
190+
191+# Context compression.
192+# ON here: the agent learns the window from /api/ps, so `threshold` has a number to apply to.
193+context:
194+ enabled: true
195+
196+ # Compress when the history reaches this share of the window.
197+ threshold: 75
198+
199+ # Fallback on the message count, for when the window is unknown.
200+ # One command costs 2 messages (call + response), so 80 is roughly 30 commands of history.
201+ maxMessages: 80
202+
203+ # How many recent questions (with their commands and answers) are kept as-is instead of being summarised.
204+ # The model works on the last few turns, so summarising them would make it redo what it just did.
205+ keepLastTurns: 3
206+
207+ # max_tokens of the summary request. Reasoning is turned off for it on this provider
208+ # (a thinking model would otherwise spend the budget thinking and write nothing).
209+ summaryMaxTokens: 1200
210+
211+ showStats: true
added sbx/kits/cli-tools/cli-tools.dockerfile +44 -0
new file mode 100644
@@ -0,0 +1,44 @@
1+# syntax=docker/dockerfile:1
2+FROM debian:trixie-slim AS build
3+ARG RG_VERSION
4+ARG BAT_VERSION
5+ARG EZA_VERSION
6+ARG TARGETARCH
7+
8+# A heredoc RUN does not stop at the first failing line by itself: every
9+# script starts with `set -eu`.
10+RUN <<EOF
11+set -eu
12+apt-get update
13+apt-get install -y --no-install-recommends curl ca-certificates tar gzip findutils
14+rm -rf /var/lib/apt/lists/*
15+EOF
16+
17+# Static (musl) builds where upstream publishes them for the architecture.
18+# eza only ships a musl build for x86_64; on arm64 we use its gnu build,
19+# which runs on the Ubuntu-based sandbox templates (glibc).
20+RUN <<EOF
21+set -eu
22+case "${TARGETARCH}" in
23+ amd64) arch=x86_64; eza_triple=x86_64-unknown-linux-musl ;;
24+ arm64) arch=aarch64; eza_triple=aarch64-unknown-linux-gnu ;;
25+ *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;;
26+esac
27+mkdir -p /out/usr/local/bin /tmp/rg /tmp/bat /tmp/eza
28+
29+curl -fsSL "https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/ripgrep-${RG_VERSION}-${arch}-unknown-linux-musl.tar.gz" \
30+ | tar -xz -C /tmp/rg
31+install -m 0755 "$(find /tmp/rg -type f -name rg | head -n1)" /out/usr/local/bin/rg
32+
33+curl -fsSL "https://github.com/sharkdp/bat/releases/download/v${BAT_VERSION}/bat-v${BAT_VERSION}-${arch}-unknown-linux-musl.tar.gz" \
34+ | tar -xz -C /tmp/bat
35+install -m 0755 "$(find /tmp/bat -type f -name bat | head -n1)" /out/usr/local/bin/bat
36+
37+curl -fsSL "https://github.com/eza-community/eza/releases/download/v${EZA_VERSION}/eza_${eza_triple}.tar.gz" \
38+ | tar -xz -C /tmp/eza
39+install -m 0755 "$(find /tmp/eza -type f -name eza | head -n1)" /out/usr/local/bin/eza
40+EOF
41+
42+# Overlay: only the three binaries land on the workload.
43+FROM scratch
44+COPY --from=build /out/ /
new file mode 100644
@@ -0,0 +1,44 @@
1+# syntax=docker/dockerfile:1
2+FROM debian:trixie-slim AS build
3+ARG RG_VERSION
4+ARG BAT_VERSION
5+ARG EZA_VERSION
6+ARG TARGETARCH
7+
8+# A heredoc RUN does not stop at the first failing line by itself: every
9+# script starts with `set -eu`.
10+RUN <<EOF
11+set -eu
12+apt-get update
13+apt-get install -y --no-install-recommends curl ca-certificates tar gzip findutils
14+rm -rf /var/lib/apt/lists/*
15+EOF
16+
17+# Static (musl) builds where upstream publishes them for the architecture.
18+# eza only ships a musl build for x86_64; on arm64 we use its gnu build,
19+# which runs on the Ubuntu-based sandbox templates (glibc).
20+RUN <<EOF
21+set -eu
22+case "${TARGETARCH}" in
23+ amd64) arch=x86_64; eza_triple=x86_64-unknown-linux-musl ;;
24+ arm64) arch=aarch64; eza_triple=aarch64-unknown-linux-gnu ;;
25+ *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;;
26+esac
27+mkdir -p /out/usr/local/bin /tmp/rg /tmp/bat /tmp/eza
28+
29+curl -fsSL "https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/ripgrep-${RG_VERSION}-${arch}-unknown-linux-musl.tar.gz" \
30+ | tar -xz -C /tmp/rg
31+install -m 0755 "$(find /tmp/rg -type f -name rg | head -n1)" /out/usr/local/bin/rg
32+
33+curl -fsSL "https://github.com/sharkdp/bat/releases/download/v${BAT_VERSION}/bat-v${BAT_VERSION}-${arch}-unknown-linux-musl.tar.gz" \
34+ | tar -xz -C /tmp/bat
35+install -m 0755 "$(find /tmp/bat -type f -name bat | head -n1)" /out/usr/local/bin/bat
36+
37+curl -fsSL "https://github.com/eza-community/eza/releases/download/v${EZA_VERSION}/eza_${eza_triple}.tar.gz" \
38+ | tar -xz -C /tmp/eza
39+install -m 0755 "$(find /tmp/eza -type f -name eza | head -n1)" /out/usr/local/bin/eza
40+EOF
41+
42+# Overlay: only the three binaries land on the workload.
43+FROM scratch
44+COPY --from=build /out/ /
renamed sbx/kits/cli-tools/cli-tools.yaml +4 -4
similarity index 87%
rename from sandboxes/docker-sbx/sbx-kits/cli-tools/cli-tools.yaml
rename to sbx/kits/cli-tools/cli-tools.yaml
@@ -26,7 +26,7 @@ provides:
2626
2727 # No runtime network: the tools are local. The downloads in the Dockerfile
2828 # use the builder's network, not the sandbox policy.
29-capabilities:
30- - type: com.docker.sandbox/agent-context@1
31- config:
32- contentFile: ./cli-context.md
29+# capabilities:
30+# - type: com.docker.sandbox/agent-context@1
31+# config:
32+# contentFile: ./cli-context.md
similarity index 87%
rename from sandboxes/docker-sbx/sbx-kits/cli-tools/cli-tools.yaml
rename to sbx/kits/cli-tools/cli-tools.yaml
@@ -26,7 +26,7 @@ provides:
26 26
27 # No runtime network: the tools are local. The downloads in the Dockerfile27 # No runtime network: the tools are local. The downloads in the Dockerfile
28 # use the builder's network, not the sandbox policy.28 # use the builder's network, not the sandbox policy.
29-capabilities:29+# capabilities:
30- - type: com.docker.sandbox/agent-context@130+# - type: com.docker.sandbox/agent-context@1
31- config:31+# config:
32- contentFile: ./cli-context.md32+# contentFile: ./cli-context.md
added sbx/kits/go-toolchain/go-toolchain.dockerfile +40 -0
new file mode 100644
@@ -0,0 +1,40 @@
1+# syntax=docker/dockerfile:1
2+
3+# --- build stage: download Go, build gopls with that same Go -----------------
4+FROM debian:trixie-slim AS build
5+ARG GO_VERSION
6+ARG GOPLS_VERSION=latest
7+ARG TARGETARCH
8+
9+# A heredoc RUN does not stop at the first failing line by itself: every
10+# script starts with `set -eu`.
11+RUN <<EOF
12+set -eu
13+apt-get update
14+apt-get install -y --no-install-recommends curl ca-certificates
15+rm -rf /var/lib/apt/lists/*
16+EOF
17+
18+RUN <<EOF
19+set -eu
20+curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" \
21+ | tar -C /usr/local -xz
22+rm -rf /usr/local/go/test
23+EOF
24+
25+# Static gopls, installed straight into the overlay tree.
26+ENV PATH=/usr/local/go/bin:${PATH} \
27+ CGO_ENABLED=0 \
28+ GOBIN=/out/usr/local/bin \
29+ GOFLAGS=-trimpath
30+RUN <<EOF
31+set -eu
32+go install "golang.org/x/tools/gopls@${GOPLS_VERSION}"
33+ln -s /usr/local/go/bin/go /out/usr/local/bin/go
34+ln -s /usr/local/go/bin/gofmt /out/usr/local/bin/gofmt
35+EOF
36+
37+# --- overlay: only the toolchain and the binaries land on the workload -------
38+FROM scratch
39+COPY --from=build /usr/local/go /usr/local/go
40+COPY --from=build /out/ /
new file mode 100644
@@ -0,0 +1,40 @@
1+# syntax=docker/dockerfile:1
2+
3+# --- build stage: download Go, build gopls with that same Go -----------------
4+FROM debian:trixie-slim AS build
5+ARG GO_VERSION
6+ARG GOPLS_VERSION=latest
7+ARG TARGETARCH
8+
9+# A heredoc RUN does not stop at the first failing line by itself: every
10+# script starts with `set -eu`.
11+RUN <<EOF
12+set -eu
13+apt-get update
14+apt-get install -y --no-install-recommends curl ca-certificates
15+rm -rf /var/lib/apt/lists/*
16+EOF
17+
18+RUN <<EOF
19+set -eu
20+curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" \
21+ | tar -C /usr/local -xz
22+rm -rf /usr/local/go/test
23+EOF
24+
25+# Static gopls, installed straight into the overlay tree.
26+ENV PATH=/usr/local/go/bin:${PATH} \
27+ CGO_ENABLED=0 \
28+ GOBIN=/out/usr/local/bin \
29+ GOFLAGS=-trimpath
30+RUN <<EOF
31+set -eu
32+go install "golang.org/x/tools/gopls@${GOPLS_VERSION}"
33+ln -s /usr/local/go/bin/go /out/usr/local/bin/go
34+ln -s /usr/local/go/bin/gofmt /out/usr/local/bin/gofmt
35+EOF
36+
37+# --- overlay: only the toolchain and the binaries land on the workload -------
38+FROM scratch
39+COPY --from=build /usr/local/go /usr/local/go
40+COPY --from=build /out/ /
renamed sbx/kits/go-toolchain/go-toolchain.yaml +3 -3
similarity index 89%
rename from sandboxes/docker-sbx/sbx-kits/go-toolchain/go-toolchain.yaml
rename to sbx/kits/go-toolchain/go-toolchain.yaml
@@ -28,6 +28,6 @@ capabilities:
2828 - sum.golang.org
2929 - github.com
3030 - golang.org
31- - type: com.docker.sandbox/agent-context@1
32- config:
33- contentFile: ./go-context.md
31+ # - type: com.docker.sandbox/agent-context@1
32+ # config:
33+ # contentFile: ./go-context.md
similarity index 89%
rename from sandboxes/docker-sbx/sbx-kits/go-toolchain/go-toolchain.yaml
rename to sbx/kits/go-toolchain/go-toolchain.yaml
@@ -28,6 +28,6 @@ capabilities:
28 - sum.golang.org28 - sum.golang.org
29 - github.com29 - github.com
30 - golang.org30 - golang.org
31- - type: com.docker.sandbox/agent-context@131+ # - type: com.docker.sandbox/agent-context@1
32- config:32+ # config:
33- contentFile: ./go-context.md33+ # contentFile: ./go-context.md
added sbx/kits/mini-me/mini-me.dockerfile +36 -0
new file mode 100644
@@ -0,0 +1,36 @@
1+# syntax=docker/dockerfile:1
2+#
3+# Base: Docker's shell template = Ubuntu, non-root `agent` user (UID 1000),
4+# bash, git, curl, CA certificates. No agent pre-installed.
5+FROM docker/sandbox-templates:shell
6+
7+USER root
8+
9+# --- mm release v0.3.0 --------------------------------------------------------
10+# rickub release assets are addressed by UUID, so the version cannot be derived
11+# from a template URL: to bump, replace these four values (URLs + SHA-256 from
12+# the release page).
13+ARG TARGETARCH
14+ARG MM_URL_AMD64=https://rickub.com/bots-garden/mini-me/release-assets/33d3bc3f-9195-487a-ab72-d55308f27e58
15+ARG MM_SHA_AMD64=9743c634a53bfaf7dd817fbf61a27e8492464576d0223c920988025deea3732b
16+ARG MM_URL_ARM64=https://rickub.com/bots-garden/mini-me/release-assets/75b8fe40-a4f5-41bf-8f8d-f70ac445acd4
17+ARG MM_SHA_ARM64=5557dd60d31cafa76c8c35f0eb02b0cf4ca110f11d226cbd2f9d1e2e5c429dfc
18+
19+# A heredoc RUN does not stop at the first failing line by itself: the
20+# script starts with `set -eu`, so a bad checksum fails the build.
21+RUN <<EOF
22+set -eu
23+case "${TARGETARCH}" in
24+ amd64) url="${MM_URL_AMD64}"; sha="${MM_SHA_AMD64}" ;;
25+ arm64) url="${MM_URL_ARM64}"; sha="${MM_SHA_ARM64}" ;;
26+ *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;;
27+esac
28+curl -fsSL "${url}" -o /usr/local/bin/mm
29+echo "${sha} /usr/local/bin/mm" | sha256sum -c -
30+chmod 0755 /usr/local/bin/mm
31+EOF
32+
33+# Back to the sandbox user, then declare the launch command.
34+USER agent
35+ENTRYPOINT ["mm"]
36+CMD ["-tui"]
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,36 @@
1+# syntax=docker/dockerfile:1
2+#
3+# Base: Docker's shell template = Ubuntu, non-root `agent` user (UID 1000),
4+# bash, git, curl, CA certificates. No agent pre-installed.
5+FROM docker/sandbox-templates:shell
6+
7+USER root
8+
9+# --- mm release v0.3.0 --------------------------------------------------------
10+# rickub release assets are addressed by UUID, so the version cannot be derived
11+# from a template URL: to bump, replace these four values (URLs + SHA-256 from
12+# the release page).
13+ARG TARGETARCH
14+ARG MM_URL_AMD64=https://rickub.com/bots-garden/mini-me/release-assets/33d3bc3f-9195-487a-ab72-d55308f27e58
15+ARG MM_SHA_AMD64=9743c634a53bfaf7dd817fbf61a27e8492464576d0223c920988025deea3732b
16+ARG MM_URL_ARM64=https://rickub.com/bots-garden/mini-me/release-assets/75b8fe40-a4f5-41bf-8f8d-f70ac445acd4
17+ARG MM_SHA_ARM64=5557dd60d31cafa76c8c35f0eb02b0cf4ca110f11d226cbd2f9d1e2e5c429dfc
18+
19+# A heredoc RUN does not stop at the first failing line by itself: the
20+# script starts with `set -eu`, so a bad checksum fails the build.
21+RUN <<EOF
22+set -eu
23+case "${TARGETARCH}" in
24+ amd64) url="${MM_URL_AMD64}"; sha="${MM_SHA_AMD64}" ;;
25+ arm64) url="${MM_URL_ARM64}"; sha="${MM_SHA_ARM64}" ;;
26+ *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;;
27+esac
28+curl -fsSL "${url}" -o /usr/local/bin/mm
29+echo "${sha} /usr/local/bin/mm" | sha256sum -c -
30+chmod 0755 /usr/local/bin/mm
31+EOF
32+
33+# Back to the sandbox user, then declare the launch command.
34+USER agent
35+ENTRYPOINT ["mm"]
36+CMD ["-tui"]
\ No newline at end of file\ No newline at end of file
renamed sbx/kits/mini-me/mini-me.yaml +11 -11
similarity index 63%
rename from sandboxes/docker-sbx/sbx-kits/mini-me/mini-me.yaml
rename to sbx/kits/mini-me/mini-me.yaml
@@ -7,7 +7,7 @@ sourceUrl: https://rickub.com/bots-garden/mini-me
77
88 # Lets other kits declare `requires: [mini-me]`.
99 # Two kits that provide the same feature cannot be combined.
10-provides: ["mini-me@0.2.6"]
10+provides: ["mini-me@0.3.0"]
1111
1212 capabilities:
1313 # The workload is prepared for sbx to launch it (agent user, bash, ...).
@@ -22,14 +22,14 @@ capabilities:
2222 allow:
2323 - host.docker.internal:12434
2424
25- # Instructions for the agent. The workload picks the file name,
26- # mixins (go-toolchain, cli-tools) append their own guidance to it.
27- - type: com.docker.sandbox/agent-context@1
28- config:
29- filename: AGENTS.md
30- contentFile: ./context.md
25+ # # Instructions for the agent. The workload picks the file name,
26+ # # mixins (go-toolchain, cli-tools) append their own guidance to it.
27+ # - type: com.docker.sandbox/agent-context@1
28+ # config:
29+ # filename: AGENTS.md
30+ # contentFile: ./context.md
3131
32- # `sbx run` (TTY) => `mm -tui`. Headless runs use ENTRYPOINT + CMD as-is.
33- - type: com.docker.sandbox/lifecycle@1
34- config:
35- interactive: ["-tui"]
32+ # # `sbx run` (TTY) => `mm -tui`. Headless runs use ENTRYPOINT + CMD as-is.
33+ # - type: com.docker.sandbox/lifecycle@1
34+ # config:
35+ # interactive: ["-tui"]
similarity index 63%
rename from sandboxes/docker-sbx/sbx-kits/mini-me/mini-me.yaml
rename to sbx/kits/mini-me/mini-me.yaml
@@ -7,7 +7,7 @@ sourceUrl: https://rickub.com/bots-garden/mini-me
7 7
8 # Lets other kits declare `requires: [mini-me]`.8 # Lets other kits declare `requires: [mini-me]`.
9 # Two kits that provide the same feature cannot be combined.9 # Two kits that provide the same feature cannot be combined.
10-provides: ["mini-me@0.2.6"]10+provides: ["mini-me@0.3.0"]
11 11
12 capabilities:12 capabilities:
13 # The workload is prepared for sbx to launch it (agent user, bash, ...).13 # The workload is prepared for sbx to launch it (agent user, bash, ...).
@@ -22,14 +22,14 @@ capabilities:
22 allow:22 allow:
23 - host.docker.internal:1243423 - host.docker.internal:12434
24 24
25- # Instructions for the agent. The workload picks the file name,25+ # # Instructions for the agent. The workload picks the file name,
26- # mixins (go-toolchain, cli-tools) append their own guidance to it.26+ # # mixins (go-toolchain, cli-tools) append their own guidance to it.
27- - type: com.docker.sandbox/agent-context@127+ # - type: com.docker.sandbox/agent-context@1
28- config:28+ # config:
29- filename: AGENTS.md29+ # filename: AGENTS.md
30- contentFile: ./context.md30+ # contentFile: ./context.md
31 31
32- # `sbx run` (TTY) => `mm -tui`. Headless runs use ENTRYPOINT + CMD as-is.32+ # # `sbx run` (TTY) => `mm -tui`. Headless runs use ENTRYPOINT + CMD as-is.
33- - type: com.docker.sandbox/lifecycle@133+ # - type: com.docker.sandbox/lifecycle@1
34- config:34+ # config:
35- interactive: ["-tui"]35+ # interactive: ["-tui"]