bots-garden/mini-mepublic Fork
⑂ v1.0.5
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. 04a9101 · on v1.0.5 · k33g · yesterday
run-in-a-docker-sandbox.md · 206 lines · 10.6 KBmarkdown
Blame HistoryOpen raw

How to run mini-me in a Docker Sandbox

This guide shows how to run mm inside a Docker Sandbox, so that every command the model runs and every file it edits happens in a container, on a mounted copy of your project. It covers the window mode in your terminal and an editor through the Agent Client Protocol. It assumes Docker Desktop with the sbx command, and a model server running on your machine.

Everything lives under demos/use-with-sbx/ in the repository. The kits follow the kit specification v3 (schemaVersion: "3"): one workload that runs mm, and mixins you add to it with --kit.

Piece Where What it is
mini-me bots-garden/mini-me-kit, directory mini-me/ The workload: Docker's shell template (Ubuntu, user agent) with the mm binary of a release (mm_version, default v0.3.0), downloaded from mini-me's release page. Entry point mm, default arguments -tui. Versioned by its own tags (v0.0.1).
go-toolchain demos/use-with-sbx/kits/go-toolchain/ A mixin: Go (go_version, default 1.27.2), gofmt and gopls (gopls_version, default latest). Allows the module hosts at runtime: proxy.golang.org, sum.golang.org, github.com, golang.org.
cli-tools demos/use-with-sbx/kits/cli-tools/ A mixin: rg, bat and eza as static binaries. No runtime network.
agent.yaml, agent.lucy.yaml demos/use-with-sbx/ Two mm configurations for llmman (Jan-nano, Lucy).
AGENTS.md demos/use-with-sbx/ Instructions for the agent working inside the sandbox (the tools installed, how to run Go): mm adds it to its system prompt when it runs in that directory — see How to give the agent your project's instructions.

Steps

1. Allow the kit's source

The mini-me kit is referenced by git URL, a tag and its directory. Its host must be an allowed kit source, once:

sbx settings set kit.allowedSources '["docker.io/","git.rickub.com/bots-garden/"]'

2. Window mode in the terminal

From the directory you want mm to work on — demos/use-with-sbx/ itself, to use its configurations and its AGENTS.md:

cd demos/use-with-sbx
RELEASE=v0.0.1
REPOSITORY=git+https://git.rickub.com/bots-garden/mini-me-kit.git
sbx run --name mm-demo-remote "${REPOSITORY}#ref=${RELEASE}&dir=mini-me"

The first run builds the kit, creates the sandbox, mounts the current directory as its workspace and runs mm -tui, which reads ./agent.yaml. Add the mixins with --kit; what follows -- replaces the default arguments, so it is mm's whole command line:

sbx run --name mm-demo-remote "${REPOSITORY}#ref=${RELEASE}&dir=mini-me" \
    --kit ./kits/go-toolchain --kit ./kits/cli-tools \
    -- -tui -config agent.lucy.yaml

The sandbox keeps its name; sbx run --name mm-demo-remote attaches to it again later. The window is the one described in Use the window mode. Sessions, when sessions.enabled is on, are written under the workspace's .mm/sessions — your host directory — so they survive the sandbox.

To work on the kit itself, clone mini-me-kit and run it from its demo/ directory: sbx run --name mm-demo ../mini-me.

3. From an editor (ACP)

An editor talks to mm -acp over raw stdin and stdout, which sbx run cannot carry (it always allocates a terminal). Create the sandbox once without attaching, then let the editor start mm inside it with sbx exec -i:

  1. From the project the editor will open, with the kit's remote reference:

    RELEASE=v0.0.1
    REPOSITORY=git+https://git.rickub.com/bots-garden/mini-me-kit.git
    sbx create --name mm-acp "${REPOSITORY}#ref=${RELEASE}&dir=mini-me" . \
        --kit /path/to/mini-me/demos/use-with-sbx/kits/go-toolchain
    

    or with a local clone of mini-me-kit (a kit path must start with ./, ../ or /):

    git clone https://git.rickub.com/bots-garden/mini-me-kit.git /path/to/mini-me-kit
    sbx create --name mm-acp /path/to/mini-me-kit/mini-me . \
        --kit /path/to/mini-me/demos/use-with-sbx/kits/go-toolchain
    

    The workspace (.) is fixed at creation: one sandbox per project, each with its own --name.

  2. Check it by hand:

    sbx exec -i mm-acp mm -acp -config agent.lucy.yaml
    
  3. Register it in Zed's settings.json:

    {
      "agent_servers": {
        "mini-me (sandbox)": {
          "type": "custom",
          "command": "sbx",
          "args": ["exec", "-i", "mm-acp", "mm", "-acp", "-config", "agent.lucy.yaml"]
        }
      }
    }
    

    If the editor cannot find sbx, put the absolute path from which sbx in "command". Tool calls, permission dialogs, @file mentions and the slash-command menu work as on the host; the difference is where the commands run. See Use mini-me from an editor for the host-side setup.

Generate a sbxenv.yaml with mm sbxinit

To describe the sandbox in a file, run this in your project's directory:

mm sbxinit
sbx env create --force

sbx env needs sbx 0.39.0 or newer, and docker.io/ among the allowed kit sources (step 1). The file names the latest mini-me-kit, and pullPolicy: always makes the sandbox fetch it at each creation. If that version cannot be read, for instance without network, mm says so and uses the tag latest. The sandbox is named after acp.name in agent.yaml, followed by -sbx; --name chooses another one.

To mount a sub-folder rather than the current directory:

mm sbxinit --workspace ./workspace

The file then holds the folder's absolute path. Create the folder yourself: mm warns you if it does not exist. To remove the sandbox, run sbx env rm --force.

All the flags are in the CLI reference.

When the agent file is outside the workspace

The sandbox only sees what is mounted. With --workspace ./workspace and an agent.yaml in the parent folder, mm in the sandbox cannot read that file. mm sbxinit warns you (agent.yaml is outside the workspace) and changes nothing else: the generated file only mounts the workspace.

You have two ways to solve it.

Put the agent file in the workspace. This is the simple way, and the file needs no change:

mv agent.yaml workspace/

The agent can then rewrite its own file, because the workspace is writable.

Mount the agent file's folder read-only. Choose this when the agent must not be able to change its own settings. Keep the agent file in its own folder, not in the parent of the workspace:

project/
├── sbxenv.yaml      not mounted
├── agents/          agent.yaml, mounted read-only
└── workspace/       the code, mounted read-write

Then add this to sbxenv.yaml by hand:

additionalWorkspaces:
  - path: ./agents
    readOnly: true

# The folder of this file, as the sandbox sees it.
args:
  PROJECT_DIR:
    required: true

env:
  # mm reads this agent file instead of ./agent.yaml.
  AGENT_CONFIG: ${{ env.args.PROJECT_DIR }}/agents/agent.yaml

Every sbx env command now needs the argument:

sbx env create --force --env-arg PROJECT_DIR="$PWD"
sbx env rm --force --env-arg PROJECT_DIR="$PWD"

mm sbxinit does not generate this form, because it makes the file longer for a case most projects do not have. Running mm sbxinit again and answering yes replaces these additions. demos/dev.team/sbxenv.yaml is a complete example.

The model server stays on the host

Inside a sandbox localhost is the sandbox itself. Your model server keeps running on your machine and is reached through host.docker.internal, which the sandbox proxy maps to your host.

  • The mini-me kit's network policy allows host.docker.internal:12434 (Docker Model Runner), :11434 (Ollama) and :17434 (llmman). agent.dmr.yaml already falls back to http://host.docker.internal:12434/engines/v1; the configurations shipped in demos/use-with-sbx/ use llmman (fallback: http://host.docker.internal:17434/v1).

  • For another port — llama-server's 8080, for instance — add it to the kit's network-policy capability, or allow it for one sandbox:

    sbx policy allow network host.docker.internal:8080
    

    sbx policy log shows what was blocked.

Change a version

  • mm: the default of mm_version in mini-me/mini-me.yaml of the mini-me-kit repository — a release tag such as v0.3.0; the kit's own tag (RELEASE above) then names the new kit. The build downloads https://rickub.com/bots-garden/mini-me/releases/download/<tag>/mm-<version>-linux-<arch>; a tag with no such release fails the build.
  • Go, gopls, rg, bat, eza: the default of the matching argument in the mixin's YAML (go_version, gopls_version, rg_version, bat_version, eza_version); each one has a pattern that refuses a malformed version.

MCP servers through the sbx gateway

Inside a sandbox, mm does not talk to MCP servers itself and holds no token. sbx runs one MCP gateway per sandbox, on the host, and bakes MCP_GATEWAY_URL into the container. When mm finds MCP_GATEWAY_URL and mcp.enabled: true, it adds a server called sbx-gateway, and its tools show up as sbx-gateway_<tool>:

mcp:
  enabled: true
  permissions: ask
  discoveryTimeout: 10s
  servers: []        # the gateway is added by mm when MCP_GATEWAY_URL is set

Register the server on the host (sbx mcp add <name> --command <script>), then create a new sandbox with it in its fixed set — --static-mcp <name> is an sbx flag and goes before --. If no sbx-gateway_* tool appears in the banner, sbx mcp inspect <name> and sbx's mcp/mcp.log say why.

Variants

  • Skills. skillsDir is relative to the directory mm runs in — the workspace — as on the host.
  • Read the logs. In the window mode they are on screen; over ACP they go to stderr, which Zed shows under dev: open acp logs.
  • A shell in the sandbox. sbx exec -it mm-acp bash.
  • Remove a sandbox. sbx rm mm-acp. The project directory is a bind mount and is not touched.

See also

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# How to run mini-me in a Docker Sandbox

This guide shows how to run `mm` inside a [Docker Sandbox](https://docs.docker.com/ai/sandboxes/), so that every command the model runs and every file it edits happens in a container, on a mounted copy of your project. It covers the window mode in your terminal and an editor through the Agent Client Protocol. It assumes Docker Desktop with the `sbx` command, and a model server running on your machine.

Everything lives under [`demos/use-with-sbx/`](../../../demos/use-with-sbx/README.md) in the repository. The kits follow the [kit specification v3](https://github.com/docker/sandbox-kit-spec) (`schemaVersion: "3"`): one **workload** that runs `mm`, and **mixins** you add to it with `--kit`.

| Piece | Where | What it is |
|---|---|---|
| `mini-me` | [bots-garden/mini-me-kit](https://rickub.com/bots-garden/mini-me-kit), directory `mini-me/` | The **workload**: Docker's `shell` template (Ubuntu, user `agent`) with the `mm` binary of a release (`mm_version`, default `v0.3.0`), downloaded from mini-me's release page. Entry point `mm`, default arguments `-tui`. Versioned by its own tags (`v0.0.1`). |
| `go-toolchain` | `demos/use-with-sbx/kits/go-toolchain/` | A **mixin**: Go (`go_version`, default `1.27.2`), `gofmt` and `gopls` (`gopls_version`, default `latest`). Allows the module hosts at runtime: `proxy.golang.org`, `sum.golang.org`, `github.com`, `golang.org`. |
| `cli-tools` | `demos/use-with-sbx/kits/cli-tools/` | A **mixin**: `rg`, `bat` and `eza` as static binaries. No runtime network. |
| `agent.yaml`, `agent.lucy.yaml` | `demos/use-with-sbx/` | Two `mm` configurations for llmman (Jan-nano, Lucy). |
| `AGENTS.md` | `demos/use-with-sbx/` | Instructions for the agent working inside the sandbox (the tools installed, how to run Go): `mm` adds it to its system prompt when it runs in that directory — see [How to give the agent your project's instructions](give-project-instructions.md). |

## Steps

### 1. Allow the kit's source

The `mini-me` kit is referenced by git URL, a tag and its directory. Its host must be an allowed kit source, once:

```bash
sbx settings set kit.allowedSources '["docker.io/","git.rickub.com/bots-garden/"]'
```

### 2. Window mode in the terminal

From the directory you want `mm` to work on — `demos/use-with-sbx/` itself, to use its configurations and its `AGENTS.md`:

```bash
cd demos/use-with-sbx
RELEASE=v0.0.1
REPOSITORY=git+https://git.rickub.com/bots-garden/mini-me-kit.git
sbx run --name mm-demo-remote "${REPOSITORY}#ref=${RELEASE}&dir=mini-me"
```

The first run builds the kit, creates the sandbox, mounts the current directory as its workspace and runs `mm -tui`, which reads `./agent.yaml`. Add the mixins with `--kit`; what follows `--` replaces the default arguments, so it is `mm`'s whole command line:

```bash
sbx run --name mm-demo-remote "${REPOSITORY}#ref=${RELEASE}&dir=mini-me" \
    --kit ./kits/go-toolchain --kit ./kits/cli-tools \
    -- -tui -config agent.lucy.yaml
```

The sandbox keeps its name; `sbx run --name mm-demo-remote` attaches to it again later. The window is the one described in [Use the window mode](use-the-window-mode.md). Sessions, when `sessions.enabled` is on, are written under the workspace's `.mm/sessions` — your host directory — so they survive the sandbox.

To work on the kit itself, clone [mini-me-kit](https://rickub.com/bots-garden/mini-me-kit) and run it from its `demo/` directory: `sbx run --name mm-demo ../mini-me`.

### 3. From an editor (ACP)

An editor talks to `mm -acp` over raw stdin and stdout, which `sbx run` cannot carry (it always allocates a terminal). Create the sandbox once without attaching, then let the editor start `mm` inside it with `sbx exec -i`:

1. From the project the editor will open, with the kit's remote reference:

   ```bash
   RELEASE=v0.0.1
   REPOSITORY=git+https://git.rickub.com/bots-garden/mini-me-kit.git
   sbx create --name mm-acp "${REPOSITORY}#ref=${RELEASE}&dir=mini-me" . \
       --kit /path/to/mini-me/demos/use-with-sbx/kits/go-toolchain
   ```

   or with a local clone of [mini-me-kit](https://rickub.com/bots-garden/mini-me-kit) (a kit path must start with `./`, `../` or `/`):

   ```bash
   git clone https://git.rickub.com/bots-garden/mini-me-kit.git /path/to/mini-me-kit
   sbx create --name mm-acp /path/to/mini-me-kit/mini-me . \
       --kit /path/to/mini-me/demos/use-with-sbx/kits/go-toolchain
   ```

   The workspace (`.`) is fixed at creation: one sandbox per project, each with its own `--name`.

2. Check it by hand:

   ```bash
   sbx exec -i mm-acp mm -acp -config agent.lucy.yaml
   ```

3. Register it in Zed's `settings.json`:

   ```json
   {
     "agent_servers": {
       "mini-me (sandbox)": {
         "type": "custom",
         "command": "sbx",
         "args": ["exec", "-i", "mm-acp", "mm", "-acp", "-config", "agent.lucy.yaml"]
       }
     }
   }
   ```

   If the editor cannot find `sbx`, put the absolute path from `which sbx` in `"command"`. Tool calls, permission dialogs, `@file` mentions and the slash-command menu work as on the host; the difference is where the commands run. See [Use mini-me from an editor](use-from-an-editor.md) for the host-side setup.

## Generate a sbxenv.yaml with `mm sbxinit`

To describe the sandbox in a file, run this in your project's directory:

```bash
mm sbxinit
sbx env create --force
```

`sbx env` needs sbx 0.39.0 or newer, and `docker.io/` among the allowed kit sources (step 1). The file names the latest `mini-me-kit`, and `pullPolicy: always` makes the sandbox fetch it at each creation. If that version cannot be read, for instance without network, mm says so and uses the tag `latest`. The sandbox is named after `acp.name` in `agent.yaml`, followed by `-sbx`; `--name` chooses another one.

To mount a sub-folder rather than the current directory:

```bash
mm sbxinit --workspace ./workspace
```

The file then holds the folder's absolute path. Create the folder yourself: mm warns you if it does not exist. To remove the sandbox, run `sbx env rm --force`.

All the flags are in the [CLI reference](../reference/cli.md#mm-sbxinit--the-sandbox-file).

### When the agent file is outside the workspace

The sandbox only sees what is mounted. With `--workspace ./workspace` and an `agent.yaml` in the parent folder, mm in the sandbox cannot read that file. `mm sbxinit` warns you (`agent.yaml is outside the workspace`) and changes nothing else: the generated file only mounts the workspace.

You have two ways to solve it.

**Put the agent file in the workspace.** This is the simple way, and the file needs no change:

```bash
mv agent.yaml workspace/
```

The agent can then rewrite its own file, because the workspace is writable.

**Mount the agent file's folder read-only.** Choose this when the agent must not be able to change its own settings. Keep the agent file in its own folder, not in the parent of the workspace:

```
project/
├── sbxenv.yaml      not mounted
├── agents/          agent.yaml, mounted read-only
└── workspace/       the code, mounted read-write
```

Then add this to `sbxenv.yaml` by hand:

```yaml
additionalWorkspaces:
  - path: ./agents
    readOnly: true

# The folder of this file, as the sandbox sees it.
args:
  PROJECT_DIR:
    required: true

env:
  # mm reads this agent file instead of ./agent.yaml.
  AGENT_CONFIG: ${{ env.args.PROJECT_DIR }}/agents/agent.yaml
```

Every `sbx env` command now needs the argument:

```bash
sbx env create --force --env-arg PROJECT_DIR="$PWD"
sbx env rm --force --env-arg PROJECT_DIR="$PWD"
```

`mm sbxinit` does not generate this form, because it makes the file longer for a case most projects do not have. Running `mm sbxinit` again and answering `yes` replaces these additions. [`demos/dev.team/sbxenv.yaml`](../../../demos/dev.team/sbxenv.yaml) is a complete example.

## The model server stays on the host

Inside a sandbox `localhost` is the sandbox itself. Your model server keeps running on your machine and is reached through `host.docker.internal`, which the sandbox proxy maps to your host.

- The `mini-me` kit's network policy allows **`host.docker.internal:12434`** (Docker Model Runner), **`:11434`** (Ollama) and **`:17434`** (llmman). `agent.dmr.yaml` already falls back to `http://host.docker.internal:12434/engines/v1`; the configurations shipped in `demos/use-with-sbx/` use llmman (`fallback: http://host.docker.internal:17434/v1`).
- For another port — llama-server's `8080`, for instance — add it to the kit's `network-policy` capability, or allow it for one sandbox:

  ```bash
  sbx policy allow network host.docker.internal:8080
  ```

  `sbx policy log` shows what was blocked.

## Change a version

- **mm**: the `default` of `mm_version` in `mini-me/mini-me.yaml` of the [mini-me-kit](https://rickub.com/bots-garden/mini-me-kit) repository — a release tag such as `v0.3.0`; the kit's own tag (`RELEASE` above) then names the new kit. The build downloads `https://rickub.com/bots-garden/mini-me/releases/download/<tag>/mm-<version>-linux-<arch>`; a tag with no such release fails the build.
- **Go, gopls, rg, bat, eza**: the `default` of the matching argument in the mixin's YAML (`go_version`, `gopls_version`, `rg_version`, `bat_version`, `eza_version`); each one has a `pattern` that refuses a malformed version.

## MCP servers through the sbx gateway

Inside a sandbox, `mm` does not talk to MCP servers itself and holds no token. `sbx` runs one MCP gateway per sandbox, on the host, and bakes `MCP_GATEWAY_URL` into the container. When `mm` finds `MCP_GATEWAY_URL` and `mcp.enabled: true`, it adds a server called `sbx-gateway`, and its tools show up as `sbx-gateway_<tool>`:

```yaml
mcp:
  enabled: true
  permissions: ask
  discoveryTimeout: 10s
  servers: []        # the gateway is added by mm when MCP_GATEWAY_URL is set
```

Register the server on the host (`sbx mcp add <name> --command <script>`), then create a **new** sandbox with it in its fixed set — `--static-mcp <name>` is an `sbx` flag and goes before `--`. If no `sbx-gateway_*` tool appears in the banner, `sbx mcp inspect <name>` and sbx's `mcp/mcp.log` say why.

## Variants

- **Skills.** `skillsDir` is relative to the directory `mm` runs in — the workspace — as on the host.
- **Read the logs.** In the window mode they are on screen; over ACP they go to stderr, which Zed shows under `dev: open acp logs`.
- **A shell in the sandbox.** `sbx exec -it mm-acp bash`.
- **Remove a sandbox.** `sbx rm mm-acp`. The project directory is a bind mount and is not touched.

## See also

- The kit format: [specification v3](https://github.com/docker/sandbox-kit-spec).
- What `mm -acp` exposes to the editor: [ACP reference](../reference/acp.md).
- The flags and environment variables `mm` reads: [command line reference](../reference/cli.md).