bots-garden/mini-mepublic Fork
⑂ v1.1.0
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. 86f68f8 · on v1.1.0 · k33g · 11h ago
run-in-a-container.md · 117 lines · 6.3 KBmarkdown
Blame HistoryOpen raw

How to run mini-me in a container

mm dockerinit writes a Dockerfile and a compose.yaml in the current directory. The image holds the latest released mm and the tools of its bash tool; compose mounts your project and runs the agent as you, not as root.

For Docker's microVM sandboxes rather than a plain container, see how to run mini-me in a Docker Sandbox.

Before you start

  • Docker with Compose.
  • An agent file in the project. If you have none, run mm init first (see create an agent).
  • A model server on your machine that the container can reach: see Reach the model.

Write the files

In your project's directory:

mm dockerinit

The service is named after acp.name in agent.yaml, or mm if there is none. To choose, use mm dockerinit --name bob. The rest of this guide calls it bob.

If a file already exists, mm asks Overwrite Dockerfile?, and no is the default. With --yes, or when the input ends, nothing at all is written.

A project with a .mm folder

When the agent is .mm/agent.yaml (made with mm init --project yes, see keep a project's mini-me files in a .mm folder), mm dockerinit finds it with no flag — it looks for agent.yaml, then .mm/agent.yaml, as mm does — and names the service after it. compose.yaml then:

  • mounts .mm/ read-only over the project: the agent cannot change its own settings, skills or hooks;
  • mounts the folders mm writes in — the agent file's sessions.dir and trace.dir, when they are on and under .mm/ — writable again, and creates them now if they do not exist (Docker would create them as root, and the agent never runs as root);
  • starts mm tui with no file: mm finds .mm/agent.yaml from the project.
    volumes:
      - .:${PWD:-/workspace}
      - ./.mm:${PWD:-/workspace}/.mm:ro
      - ./.mm/sessions:${PWD:-/workspace}/.mm/sessions    # sessions.dir

Anything else written under .mm/ — a hook that keeps a log there — needs a line of its own. After turning sessions or the trace on or off, run mm dockerinit again (answer yes to replace compose.yaml).

Run the agent

Either keep a container running, which also serves an editor:

docker compose up -d --wait
docker compose exec bob mm tui agent.yaml

Or run one session, in a container that goes away with it:

docker compose run --rm bob mm tui agent.yaml

Both open the single-window mode (mm tui) and can be used at the same time. The first run builds the image.

Connect an editor (ACP)

Start the container with docker compose up -d --wait, then give your editor this command, with the project's absolute path:

docker exec -i bob-box mm --acp --config /path/to/project/agent.yaml

The project is mounted at the same path as on your machine, so the paths the editor sends mean the same thing inside the container. For a .mm project, docker exec -i bob-box mm --acp is enough: the container starts in the project, where mm finds .mm/agent.yaml.

Reach the model

From the container, localhost is the container. dmr, llmman, ollama, kronk and llamacpp fall back on host.docker.internal by themselves when their default address does not answer, as long as the agent file sets no baseUrl. The compose file makes that name known on Linux too.

  • llamacpp: on Linux, start llama-server with --host 0.0.0.0, as it listens on the loopback only by default (see the last point). Files written before v1.1.0 may say fallback: "": remove that line.
  • An agent file with a baseUrl on localhost or 127.0.0.1: replace the host with host.docker.internal, or add a fallback.
  • A server on Linux that only listens on 127.0.0.1: make it listen on an address the container can reach. host.docker.internal is then the host's gateway, not its loopback.

Update to the latest release

docker compose build
docker compose up -d --wait

Docker reads the release's SHA256SUMS at each build: when it has changed, the steps that install mm run again.

Build for both architectures

docker compose builds for your machine's architecture. To publish an image for linux/amd64 and linux/arm64:

docker buildx build --platform linux/amd64,linux/arm64 -t <registry>/mm-bob:latest --push .

Building for the other architecture needs emulation (QEMU, included in Docker Desktop). Without it, the build stops with exec format error.

An image built this way, outside compose, gives its mm account the uid and gid 1000. Whoever runs it with other numbers gets a user with no name in the container: add --build-arg MM_UID=… --build-arg MM_GID=… to build it for them.

Use the files on another machine

compose.yaml records the uid and gid of the machine that ran mm dockerinit. The container runs as that user, so that the files the agent creates belong to you, and the image's mm account is built with the same numbers, so that every program in the container knows who it runs as — whoami, the shell's prompt, ssh. On a machine where yours differ, set them, then rebuild the image:

export MM_UID=$(id -u) MM_GID=$(id -g)
docker compose up -d --build

Without the rebuild, the container runs as your uid while the image's account keeps the old one: the shell's prompt then reads I have no name! and whoami fails.

Files written by mm dockerinit before v1.1.0 always built the account with uid 1000 — on a Mac, whose user is uid 501, the shell said I have no name!. Run mm dockerinit again (answer yes to replace both files), then docker compose up -d --build.

git in the container still needs an identity to commit: the account has a name, but git does not make one up from it. Set user.name and user.email in the project (git config user.name …), or pass GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL to the container.

What the container protects

The agent does not run as root, but it can still change and delete everything in the mounted project, and it has network access. Keep the project under version control, and use yolo: false if you want to approve each command: see confirm tool calls.

All the flags are in the CLI reference.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# How to run mini-me in a container

`mm dockerinit` writes a `Dockerfile` and a `compose.yaml` in the current directory. The image holds the latest released `mm` and the tools of its `bash` tool; compose mounts your project and runs the agent as you, not as root.

For Docker's microVM sandboxes rather than a plain container, see [how to run mini-me in a Docker Sandbox](run-in-a-docker-sandbox.md).

## Before you start

- Docker with Compose.
- An agent file in the project. If you have none, run `mm init` first (see [create an agent](create-an-agent.md)).
- A model server on your machine that the container can reach: see [Reach the model](#reach-the-model).

## Write the files

In your project's directory:

```bash
mm dockerinit
```

The service is named after `acp.name` in `agent.yaml`, or `mm` if there is none. To choose, use `mm dockerinit --name bob`. The rest of this guide calls it `bob`.

If a file already exists, mm asks `Overwrite Dockerfile?`, and `no` is the default. With `--yes`, or when the input ends, nothing at all is written.

### A project with a `.mm` folder

When the agent is `.mm/agent.yaml` (made with `mm init --project yes`, see [keep a project's mini-me files in a `.mm` folder](keep-the-config-in-a-mm-folder.md)), `mm dockerinit` finds it with no flag — it looks for `agent.yaml`, then `.mm/agent.yaml`, as mm does — and names the service after it. `compose.yaml` then:

- mounts `.mm/` **read-only** over the project: the agent cannot change its own settings, skills or hooks;
- mounts the folders mm writes in — the agent file's `sessions.dir` and `trace.dir`, when they are on and under `.mm/` — writable again, and creates them now if they do not exist (Docker would create them as root, and the agent never runs as root);
- starts `mm tui` with no file: mm finds `.mm/agent.yaml` from the project.

```yaml
    volumes:
      - .:${PWD:-/workspace}
      - ./.mm:${PWD:-/workspace}/.mm:ro
      - ./.mm/sessions:${PWD:-/workspace}/.mm/sessions    # sessions.dir
```

Anything else written under `.mm/` — a hook that keeps a log there — needs a line of its own. After turning sessions or the trace on or off, run `mm dockerinit` again (answer `yes` to replace `compose.yaml`).

## Run the agent

Either keep a container running, which also serves an editor:

```bash
docker compose up -d --wait
docker compose exec bob mm tui agent.yaml
```

Or run one session, in a container that goes away with it:

```bash
docker compose run --rm bob mm tui agent.yaml
```

Both open the [single-window mode](../reference/cli.md) (`mm tui`) and can be used at the same time. The first run builds the image.

## Connect an editor (ACP)

Start the container with `docker compose up -d --wait`, then give your editor this command, with the project's absolute path:

```bash
docker exec -i bob-box mm --acp --config /path/to/project/agent.yaml
```

The project is mounted at the same path as on your machine, so the paths the editor sends mean the same thing inside the container. For a `.mm` project, `docker exec -i bob-box mm --acp` is enough: the container starts in the project, where mm finds `.mm/agent.yaml`.

## Reach the model

From the container, `localhost` is the container. `dmr`, `llmman`, `ollama`, `kronk` and `llamacpp` fall back on `host.docker.internal` by themselves when their default address does not answer, as long as the agent file sets no `baseUrl`. The compose file makes that name known on Linux too.

- **`llamacpp`**: on Linux, start llama-server with `--host 0.0.0.0`, as it listens on the loopback only by default (see the last point). Files written before v1.1.0 may say `fallback: ""`: remove that line.
- **An agent file with a `baseUrl` on `localhost` or `127.0.0.1`:** replace the host with `host.docker.internal`, or add a `fallback`.
- **A server on Linux that only listens on `127.0.0.1`:** make it listen on an address the container can reach. `host.docker.internal` is then the host's gateway, not its loopback.

## Update to the latest release

```bash
docker compose build
docker compose up -d --wait
```

Docker reads the release's `SHA256SUMS` at each build: when it has changed, the steps that install `mm` run again.

## Build for both architectures

`docker compose` builds for your machine's architecture. To publish an image for `linux/amd64` and `linux/arm64`:

```bash
docker buildx build --platform linux/amd64,linux/arm64 -t <registry>/mm-bob:latest --push .
```

Building for the other architecture needs emulation (QEMU, included in Docker Desktop). Without it, the build stops with `exec format error`.

An image built this way, outside compose, gives its `mm` account the uid and gid 1000. Whoever runs it with other numbers gets a user with no name in the container: add `--build-arg MM_UID=… --build-arg MM_GID=…` to build it for them.

## Use the files on another machine

`compose.yaml` records the uid and gid of the machine that ran `mm dockerinit`. The container runs as that user, so that the files the agent creates belong to you, and the image's `mm` account is built with the same numbers, so that every program in the container knows who it runs as — `whoami`, the shell's prompt, ssh. On a machine where yours differ, set them, then rebuild the image:

```bash
export MM_UID=$(id -u) MM_GID=$(id -g)
docker compose up -d --build
```

Without the rebuild, the container runs as your uid while the image's account keeps the old one: the shell's prompt then reads `I have no name!` and `whoami` fails.

Files written by `mm dockerinit` before v1.1.0 always built the account with uid 1000 — on a Mac, whose user is uid 501, the shell said `I have no name!`. Run `mm dockerinit` again (answer `yes` to replace both files), then `docker compose up -d --build`.

git in the container still needs an identity to commit: the account has a name, but git does not make one up from it. Set `user.name` and `user.email` in the project (`git config user.name …`), or pass `GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME` and `GIT_COMMITTER_EMAIL` to the container.

## What the container protects

The agent does not run as root, but it can still change and delete everything in the mounted project, and it has network access. Keep the project under version control, and use `yolo: false` if you want to approve each command: see [confirm tool calls](confirm-tool-calls.md).

All the flags are in the [CLI reference](../reference/cli.md#mm-dockerinit--the-container-files).