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
|
# Reference: command line
> Neutral description of the `mm` executable: flags, positional argument, environment variables, start-up output and exit codes.
## Invocation
```
mm [-config <path>] [-acp] [-tui] [-prompt <text>|-p <text>] [--version] [--about] [<path>]
mm [-config <path>] --ask <agent> [-p <question>] (question on stdin when -p is absent)
mm [-config <path>] --ask-with-context <agent> [-p <question>] (context on stdin)
```
| Element | Type | Default | Description |
|---------|------|---------|-------------|
| `-config <path>` | string | `""` | Path of the YAML configuration file. |
| `<path>` | positional | none | Same as `-config`, when `-config` is not given. A second positional argument is an error. |
| `-acp` | bool | `false` | Serve the Agent Client Protocol on stdin/stdout instead of the terminal REPL. |
| `-tui` | bool | `false` | Open the single-window mode (conversation above, input box below). Same effect as `tui: true` in the YAML; ignored with `-acp`. Falls back to the line mode when stdin or stdout is not a terminal. |
| `-prompt <text>` / `-p <text>` | string | `""` | Run a single prompt and exit. The prompt text is required. Works with the config file before or after: `mm -p "hello" config.yaml` and `mm config.yaml -p "hello"` are both valid. No banner, no session persistence, no TUI/ACP. |
| `--version` | bool | `false` | Print the version and exit, before the configuration is read. `-version` is the same flag. |
| `--about` | bool | `false` | Print what `mm` is — one screen: version, the three front ends, the tools, the model servers, where the project and the docs live — and exit, before the configuration is read. |
| `--ask <agent>` | string | `""` | Ask the agent `<agent>` (a key of `mmConfigs`) one question and exit; see [Ask mode specifics](#ask-mode-specifics). Like `-p`, works with the config file before or after: `mm agent.yaml --ask lucy -p "…"` and `mm --ask lucy -p "…" agent.yaml` are both valid. |
| `--ask-with-context <agent>` | string | `""` | Same, sending a conversation read from stdin before the question. |
| `-h` | — | — | Print the flag usage and exit. |
## Version
`mm --version` (or `-version`) prints one line and exits, before the configuration file is looked for — so it answers in any directory, with no model server running:
```
mm v0.1.7 (go1.26.5, darwin/arm64)
```
`mm --about` prints the same version inside a short description of the program. The version also opens the start-up banner (`mm v0.1.7 | config: …`), which the window mode keeps as the conversation's first line, and sits in the window's status bar before the counters.
| Where it comes from | What you see |
|---|---|
| A release binary, stamped at build time by `02-build-releases.sh` | The tag: `v0.1.7` |
| `go install`ed from a tagged version | That tag |
| Built by hand from a working tree (`go build`, `./install.sh`) | The short commit, `9073268`, with `+dirty` when the tree had uncommitted changes |
| Built with `-buildvcs=false` | `unknown` |
## Configuration file resolution
The first existing source wins.
| Order | Source | Missing file |
|-------|--------|--------------|
| 1 | `-config` flag or positional argument | Error, exit code 1 |
| 2 | `AGENT_CONFIG` environment variable | Error, exit code 1 |
| 3 | `./agent.yaml` | Not an error: built-in defaults are used, the banner shows `config: built-in defaults` |
## Environment variables
| Variable | Effect |
|----------|--------|
| `AGENT_CONFIG` | Path of the configuration file (see above). |
| `AGENT_PROVIDER` | Overrides the `provider` key. |
| `AGENT_MODEL` | Overrides the `model` key. |
| `AGENT_BASE_URL` | Overrides `baseUrl` and disables the fallback probe. |
| `DMR_BASE_URL` | Same as `AGENT_BASE_URL`, for the `dmr` provider only; `AGENT_BASE_URL` wins when both are set. |
| `AGENT_SESSIONS` | `off` turns session persistence off for this run, whatever `sessions.enabled` says. Set by `/ask` on the agents it starts. |
| `AGENT_YOLO` | Overrides the `yolo` key: `true` or `false` (any `strconv.ParseBool` spelling; anything else is a configuration error). Set to `false` by `/ask` on the agents it starts, so the asking agent decides. |
| `MM_BIN` | Set by `mm` for the commands its `bash` tool runs: the path of the running `mm` binary. |
| `MM_CONFIG` | Set by `mm` for the commands its `bash` tool runs: the absolute path of its configuration file. Read by `--ask` / `--ask-with-context` when no `-config` and no positional path are given. |
| `MM_ASK_DEPTH` | How many `/ask` levels deep this agent runs (unset = 0). Set by `/ask`; at 2, `/ask` is refused. |
| Variable named by `apiKeyEnv` | Holds the API key. Default name: none for `dmr`, `LLAMA_API_KEY` for `llamacpp`, `LLMMAN_API_KEY` for `llmman`, `OLLAMA_API_KEY` for `ollama`. |
## Start-up output
Printed on stdout in terminal mode, on stderr in ACP mode. Dimmed when stdout is a terminal.
| Line | Content |
|------|---------|
| `[warning: …]` | Zero or more probe warnings: server unreachable, model not in the server's list, no chat template, compression that can never trigger, no tool declared at all, an `mmConfigs` file not found (`mmConfigs: <name> → <path> not found — /ask-<name> will fail`), the deprecated `permissions` key. |
| `mm <version> \| config: … \| provider: … \| model: … \| ctx: … \| tools: … \| skills: N \| yolo: …` | Version (see above), configuration path, provider name, model identifier, context window with its origin (`config`, `/props`) or `unknown`, declared tool names, number of skills found, `yolo: on` or `yolo: off (tools ask)`. |
| `Agent ready. Commands: …` | Terminal mode only. |
| `Shortcut: Ctrl+C …` | Terminal mode only. |
| `sessions: saved under <dir>[ · N earlier — /resume to continue the latest, /sessions to list]` | Terminal mode, `sessions.enabled` only: the resolved sessions directory and how many sessions it already holds. |
### Example
```
[warning: llamacpp: nothing answers at http://127.0.0.1:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080]
mm v0.1.7 | config: agent.llamacpp.yaml | provider: llamacpp | model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | ctx: unknown | tools: bash, read_file, write_file, edit_file | skills: 0 | yolo: on
```
## ACP mode specifics
| Aspect | Behaviour |
|--------|-----------|
| stdout | JSON-RPC 2.0 messages only, one per line. |
| stderr | Banner, warnings, `[acp] …` trail, SDK logs. |
| Spinner | Disabled. |
| Relative `skillsDir` | Resolved relative to the directory of the configuration file, when a file was found; otherwise from the working directory, as in terminal mode. |
| Permissions | `yolo: true`: no `session/request_permission` is sent for the built-in tools. `yolo: false`: one per call, with four options — `allow` (allow once), `allow_always` (this tool for the session), `reject` (reject once), `never` (`reject_always`: this tool, for the session). MCP tools marked `ask` always send one. |
## Line mode specifics
| Aspect | Behaviour |
|--------|-----------|
| Permissions | With `yolo: false` (and for MCP tools marked `ask`), after the tool's `🛠️` line: `🔐 <tool title>`, the legend `[a] allow once · [s] allow <tool> for this session · [r] reject · [n] never <tool>` and ` ? `. The next typed line answers (`a`, `s`, `r`, `n` or the words `once`, `session`, `reject`, `never`); another answer prints the legend again; a line starting with `/` is a command (`/abort`, `/quit`), not an answer. `Ctrl+C` or `/abort` rejects and stops the turn. The same prompt answers the calls of an agent asked with `/ask`. |
## Window mode specifics
| Aspect | Behaviour |
|--------|-----------|
| Selection | `-tui` flag, or `tui: true` in the YAML; `-acp` wins over both. |
| Terminal check | Both stdin and stdout must be character devices. Otherwise `[tui: stdin or stdout is not a terminal — running the line mode]` is printed and the line mode runs, banner included. |
| Screen | The terminal's alternate screen, released on exit; the terminal's own scrollback is not written to. |
| Banner | Not printed on stdout; shown as the first line of the conversation. |
| Spinner | Disabled; the rule under the conversation animates instead. |
| Model name | The header shows a short form of the model identifier: registry host and organisation dropped, the `-gguf` format suffix dropped, the tag kept, capped at 28 characters (`huggingface.co/unsloth/qwen3.5-2b-gguf:Q4_K_M` → `qwen3.5-2b:Q4_K_M`). The full identifier is in the start-up banner, which the window keeps as the conversation's first line. |
| Layout | Header line (agent, model `@` provider, context use as `ctx N% (used/window)` or `ctx ~used (window unknown)`, `session <id>` when sessions are on); conversation with a scroll bar; rule with state and key hints; 3-row input box; status bar (`F1 help · Ctrl-Y copy · F2 mouse: … · Ctrl-C quit` on the left, `<version> · N msgs · N tools` on the right — the version is dropped when the two sides would not fit, so the key hints are never truncated to make room for it). |
| Tool calls | `‣ <tool> <detail> <status> <time>` where status is `… pending`, `… waiting for permission`, `… running`, `✓ done` or `✗ failed`; output folded to `previewLines` lines (`… N more line(s)`); `+`/`-` lines of `write_file`/`edit_file` output coloured. |
| Pickers | `/` completes a command, `@` a path under the working directory, `$` a skill of the catalogue — the last two anywhere in a sentence, keeping their prefix. See [Slash commands](slash-commands.md#the-three-pickers). |
| Thinking | A thinking model's reasoning is its own `‣ thinking` entry, dim italic in a different colour, before the answer. Hidden with `showThinking: false`. |
| Errors | One line `[error: <explanation>]`; a cancelled turn shows `🛑 Generation aborted.`; each turn ends with `⚙ N command(s) [· 📝 N file op(s)] [· 📖 N skill(s)]`. |
| Permissions | With `yolo: false` (and for MCP tools marked `ask`), the box shows `? <tool title>` with `[a] allow once [s] allow <tool> for this session [r] reject [n] never <tool>` until answered (`Esc` = `r`); a turn cancelled while asking rejects. |
| Keys | See [Slash commands — window keys](slash-commands.md#window-mode-keys). |
| Mouse | Not captured at start-up, so the terminal's click-and-drag selection works. `F2` captures it (wheel scrolling; `Shift`+drag selects) and releases it again. |
## Prompt mode specifics
| Aspect | Behaviour |
|--------|-----------|
| Execution | Runs a single generation cycle and exits. No REPL, no session persistence. |
| Output | Prints tool call statistics and the model's response, then exits. Same display as the line mode (⚙ commands, 📝 file ops, 📖 skills, 🔎 LSP calls). |
| Banner | Not printed. |
| Session | Not saved; no session directory used. |
| Config file | Can appear before or after the `-prompt`/`-p` flag: `mm -p "prompt" config.yaml` and `mm config.yaml -p "prompt"` both work. |
| Compatibility | Incompatible with `-acp` and `-tui`; prompt mode takes precedence and runs regardless. |
| Permissions | Nobody can answer. With `yolo: false`, every call that would ask is rejected (`[command rejected by the user]` for the model) and stderr says once: `[yolo is off and this mode cannot ask: tool calls that need a confirmation are rejected — set yolo: true to let them run]`. MCP tools marked `ask` are rejected the same way, whatever `yolo` says. |
## Ask mode specifics
| Aspect | Behaviour |
|--------|-----------|
| Configuration | `-config`, the positional path, then `MM_CONFIG`, then the usual resolution. The agent name is looked up in that file's `mmConfigs`. No engine is started for this configuration's own model. |
| Question | `-p <question>`; without `-p`, the whole of stdin. |
| Context (`--ask-with-context`) | stdin. Without `-p`, stdin is `<context>`, a line `---`, then the question. |
| stdout | The agent's answer, and nothing else, followed by a newline. |
| stderr | `🗣 asking <agent> (<provider>/<model>)…`, one `🛠️ <agent> · <tool>: <args>` line per tool call, `[ask: …]` on error. |
| The agent's tool calls | Decided by this configuration's `yolo`: `true` = allowed; `false` = rejected, with the same stderr line as in prompt mode (stdin carried the question, nobody can answer). |
| Parent process | Watched every 500 ms: when it is gone, the ask is cancelled and the agent stopped. |
| Session | None: neither this process nor the agent writes session files. |
## Exit codes
| Code | Cause |
|------|-------|
| 0 | `/quit`, `Ctrl+C` at the prompt, end of stdin, or the ACP client closed the connection. `--ask`: the agent answered. |
| 1 | More than one positional argument; configuration load error; engine initialisation error (unknown provider, required key not set). `--ask`: no question, no context, unknown agent, the agent failed or gave no answer. |
| 130 | `--ask`: interrupted (`Ctrl+C`, or the parent process is gone). |
## Build and install
| Command | Effect |
|---------|--------|
| `go build -o mm .` | Builds the binary in the current directory. |
| `./install.sh` | Builds `mm` and copies it to `/usr/local/bin`, with `sudo` when the directory is not writable. |
| `go test ./...` | Runs the unit tests. |
|