Reference: slash commands and keyboard shortcuts
Neutral description of the commands recognised at the terminal prompt of
mm. They are matched on the whole trimmed line; anything else is sent to the model.
Commands
| Command | At the prompt | During a generation |
|---|---|---|
/quit |
Exits the program. | Cancels the generation, prints Goodbye., exits. |
/abort |
Prints ⚠️ No generation in progress. |
Cancels the generation, prints 🛑 Aborting...; the commands already run stay in the history. |
/compact |
Compresses the history now, regardless of the threshold; prints the 🗜️ report, or 🗜️ nothing to compact when no turn is older than context.keepLastTurns. |
Sent to the model as a new message (see below). |
/new |
Clears the history back to the system prompt, resets the loop detector, forgets the server's last token count and the conversation's plans; prints 🆕 new session: N message(s) forgotten (N counts every message except the system prompt). |
Treated like any other text: cancels the generation, keeps its partial history, then runs as /new on that history. |
/sessions |
Lists the project's stored sessions, newest first: id, last update, question count, first question, then · ⚠️ N error(s) when the session recorded errors; * marks the current one. With sessions.enabled: false: ⚠️ sessions are off (set sessions.enabled: true in the YAML). |
Sent to the model as a new message. |
/resume [id] |
Continues a stored session: the most recently updated one other than the current, skipping empty ones, or the named id. Prints ↩️ resumed <id> — N message(s), started with "<first question>" (plus · ⚠️ N error(s) when the session recorded errors); resets the loop detector, the server's token count and the plans; later turns are saved to that session. Refused with a ⚠️ reason when sessions are off, when there is no earlier session, when the id is unknown or is the current session. |
Sent to the model as a new message. |
/help |
Prints the commands of this front end, one per line with their description, aligned. | Sent to the model as a new message. |
/copy [n|all] |
Copies the last answer (n: the n-th from the end) to the clipboard through pbcopy/wl-copy/xclip/xsel or, failing that, OSC 52 when stdout is a terminal, and prints 📋 copied N chars (<road>) or ⚠️ …. /copy all is window-mode only: here it says so. |
Sent to the model as a new message. |
/save <file> [n] |
Writes the last answer (n: the n-th from the end) as it is to a new file, creating the missing directories, and prints 💾 saved the last answer to <file> (N bytes). Never overwrites: an existing file gives ⚠️ <file> already exists — nothing was written; choose another name. A file name with spaces is not supported. The model is not called. |
Sent to the model as a new message. |
/memory <words> |
With sessions.enabled and sessions.searchMemory: searches the project's stored sessions and prints 🔎 N hit(s) for "<words>" in <dir>, then two lines per hit — <session id> · <date> · turn <n> · question|answer|summary and the text around the words found, plus → <answer> under a question (the answer its turn ended on) — or 🔎 no hit for "<words>" in <dir>. Case and accents do not count; words of one or two letters are left out beside longer ones; a hit holds at least one of the words; hits are ranked by the number of words held, then newest first; 10 at most. Questions, answers and /compact summaries are searched, not tool calls; the conversation in progress is left out. Without words: ⚠️ nothing to search: give one or more words. The model is not called; the history is not touched. |
Sent to the model as a new message. |
/docs <words> |
With docSearch.searchDocs: searches the text files of docSearch.dirs with BM25 and prints 🔎 N passage(s) for "<words>" — F file(s) in <dirs>, then per passage a line ── <path>:<line> · <heading › subheading> and the passage as written; or 🔎 no passage for "<words>" — F file(s) in <dirs>. Case and accents do not count; words of 4+ letters also match longer words and plurals; 5 passages at most. Without words: ⚠️ nothing to search: give one or more words. The model is not called; the history is not touched. |
Sent to the model as a new message. |
/unload [model] |
With unloadModels (default on): unloads a model from the server's memory — this agent's own, or the one named — and prints one line: 🧹 unloaded <model>, 🧹 <model> was not loaded: nothing to unload, or 🧹 cannot unload <model>: <reason> (a provider or a server that has no way to). The history is not touched; the next question reloads the agent's model. |
Sent to the model as a new message. |
With sessions.enabled, /new leaves the current session's file as it is; the next question opens a new file. An empty line at the prompt is ignored.
Asking another agent
Present only when mmConfigs declares at least one agent; /help and the / picker list them. <name> is a key of mmConfigs.
| Command | Front ends | Effect |
|---|---|---|
/ask-<name> <prompt> |
terminal, window, editor | Sends <prompt> alone to <name>. |
/ask-with-context-<name> <prompt> |
terminal, window, editor | Sends a transcript of the current conversation, then <prompt>. |
/ask <name> <prompt> |
terminal, window | Same as /ask-<name> <prompt>. |
/ask-with-context <name> <prompt> |
terminal, window | Same as /ask-with-context-<name> <prompt>. |
While it runs:
| Item | Behaviour |
|---|---|
| First line | 🗣 asking <name> (<provider>/<model>)…, or …, with the conversation… for the context forms. |
<name>'s answer |
Streamed where answers appear. Its reasoning is shown as reasoning when showThinking is on. |
<name>'s tool calls |
Shown as tool calls titled <name> · <tool>: <args>. Permission requests go through this front end: none in the line mode (allowed), permissions in the window (a/s/r, "for this session" keyed on <name>/<tool>), the editor's dialog over ACP. |
/abort, Esc, Ctrl+C, session/cancel |
Cancel the ask; 🛑 Ask aborted — nothing kept. |
/quit |
Cancels the ask and exits. |
| Any other line (line mode) | ⚠️ <name> is still answering — /abort to stop it.; the line is dropped. |
When it ends:
| Outcome | History | Message |
|---|---|---|
| Answered | Two messages appended: user [asked <name> (<provider>/<model>)[, with this conversation as context]: <prompt>], assistant [<name>'s answer] + the answer (capped at maxOutput characters, beginning and end kept). Saved with the session. |
🗣 <name>'s answer is in the history for your next question |
| Cancelled | Unchanged. | 🛑 Ask aborted — nothing kept. |
| Failed | Unchanged; recorded in the session file with where: "ask". |
[error: …] (terminal, window) or a JSON-RPC error (editor). |
The transcript sent by the context forms holds the user's questions, the assistant's answers, one line per tool call (Assistant ran <tool>: <args>, args cut at 160 characters) and the compaction summary if any; never the system prompt, tool outputs or reasoning. Capped at maxOutput characters, newest lines kept, [… earlier conversation omitted …] marking the cut.
| Error | Cause |
|---|---|
usage: /ask <agent> <prompt> — agents: … |
/ask without a name. |
unknown agent "x" — agents: … |
/ask x … with a name not in mmConfigs. |
nothing to ask: type the question after the command |
No prompt. |
<name>: config file <path>: no such file or directory |
The file of mmConfigs.<name> does not exist. |
<name> did not start: … — <last stderr line> |
The agent's process exited or did not answer initialize within 60 s. |
<name> failed: … |
The agent's turn ended with an error (its own one-line explanation). |
<name> gave no answer |
The agent ended its turn without any text. |
this agent was itself asked through 2 level(s) of /ask; it cannot ask further (max 2) |
MM_ASK_DEPTH is 2. |
@path in a question
| Input | Effect |
|---|---|
@<path> at the start or after a space, bracket or quote |
If the path exists (relative to the start directory, absolute, or ~/…), a dim 📎 <absolute path> line is printed and [attached file: <absolute path>] (or [attached directory: …]) is appended to the message the model receives. Trailing punctuation is ignored; each path is attached once. |
A @<path> that names nothing on disk, or @ glued to a word |
Left as typed. |
Details and examples: Point the model at a file with @path.
Any other text during a generation
| Input | Behaviour |
|---|---|
| A non-command line | Prints 🔄 New command received. Cancelling current task..., cancels the current generation, keeps its partial history, then submits the new line as the next question. |
Keyboard shortcuts
| Key | At the prompt | During a generation |
|---|---|---|
Ctrl+C |
Prints Goodbye. and exits. |
Prints 🛑 Interrupted (Ctrl+C). and cancels the generation; the prompt comes back. |
Ctrl+D (end of input) |
Exits. | — |
Window mode keys
In mm -tui the same commands exist, plus /shell; /abort when idle prints ⚠️ No generation in progress. as a notice, and the picker opened by / lists them — see The three pickers.
/quit, /abort and /shell take effect immediately, even while a turn is running. Every other command and every question waits for the turn to end, because it needs the history the turn is still writing. See Leaving a turn that will not stop.
/shell
Window mode only. Takes no argument: /shell <text> is sent to the model.
| Step | Behaviour |
|---|---|
| Start | The window gives the terminal back (tcell Suspend: normal screen, cooked mode, mouse and paste modes off), prints mm: <shell> in <dir> — type exit to come back to the conversation. and runs the shell with the terminal as its input and output. |
| Shell | $SHELL, else /bin/sh; on Windows %COMSPEC%, else cmd.exe. Started in the window's working directory, with mm's environment plus MM_SHELL=1. |
| Prompt | Starts with (mm) , in front of the prompt your own configuration sets (see below). |
Ctrl-C, Ctrl-\ |
Reach the shell and what it runs; mm ignores them while the shell runs. |
| A turn in progress | Goes on, and is not cancelled. What it streams is shown on the way back. A permission it asks for waits until the window is back. |
| Return | When the shell exits: the window is redrawn whole, and a notice says how it ended. |
| Notice | When |
|---|---|
🐚 Back from the shell. |
The shell exited with status 0. |
🐚 Back from the shell (exit status N). |
The shell exited with status N (exit 3, or the last command's status). |
⚠️ /shell: <error> |
The shell could not start (for example exec: "/bin/fish": no such file or directory), or the terminal could not be suspended or resumed. |
The history is not touched and the model is not called.
How the (mm) prefix is added, per shell (recognised by the program's name):
| Shell | How | Your configuration |
|---|---|---|
bash |
--rcfile with a file of mm's that runs ~/.bashrc, then sets PS1="(mm) $PS1" |
~/.bashrc runs as usual |
zsh |
ZDOTDIR points at a directory of mm's whose .zshenv and .zshrc run yours (from your ZDOTDIR, else $HOME), then set PROMPT="(mm) $PROMPT"; ZDOTDIR is set back to yours |
.zshenv and .zshrc run as usual |
fish |
-C wraps your fish_prompt function after your configuration is read |
config.fish runs as usual |
sh, dash, ash, ksh, mksh |
PS1="(mm) $ " in the environment |
a file named by $ENV that sets PS1 replaces the prefix |
cmd |
PROMPT="(mm) $P$G" in the environment |
— |
| any other | nothing: no prefix | — |
mm's files are written in a temporary directory (mm-shell-*), removed when the shell exits; when they cannot be written, the shell starts without the prefix. A theme that rebuilds the prompt before each line (powerlevel10k, for instance) replaces the prefix: test MM_SHELL in its configuration instead.
The keys:
| Key | Action |
|---|---|
Enter |
Sends the box (nothing on an empty box). With the picker open on an incomplete name, completes it instead. |
Ctrl-J, Alt-Enter |
Inserts a newline in the box. |
Esc |
Cancels the running turn (same as /abort); when no turn runs and the box is not empty, clears the box instead; closes the picker; rejects a pending permission. |
Ctrl-C |
Cancels the running turn; quits when idle — and quits too when the turn has already been asked to stop and has not. |
Tab |
Moves the focus between the box and the conversation; completes the picker's choice when it is open (/, @ or $). |
↑ ↓ |
In the box: move between its rows — a long line wraps at spaces into several rows. From the first row, ↑ recalls the previous question (sessions on: this session, then the earlier ones, newest first); from the last row during a recall, ↓ the next one, then the text typed before. With nothing to recall, they scroll the conversation from the first/last row. On the conversation: scroll one line. In the picker: move the choice. |
PgUp PgDn |
Scroll one page. |
Home End |
In the box: start/end of the line. On the conversation: top / bottom (bottom resumes following). |
Ctrl-L |
Clears the displayed conversation; the history is kept. |
F1 |
Same as /help. |
F2 |
Toggles mouse capture. Off (default): the terminal's own click-and-drag selection works; the status bar says F2 mouse: off. On: the wheel scrolls, Shift+drag selects, the status bar says mouse: on (Shift+drag selects). |
Ctrl-Y |
Same as /copy: the last answer to the clipboard. |
a s r n |
Answer a pending permission (yolo: false, or an MCP tool marked ask): allow once, allow this tool for the session, reject this call (Esc too), never allow this tool in this session. |
| Mouse wheel | Scrolls the conversation — only while the mouse is captured (F2). |
| Bracketed paste | Inserted as one block; its line breaks become newlines, never a send. Longer than 3 lines or 200 characters: collapsed into one [Pasted #n · L lines · C chars] token that edits as a single character; Enter sends the full text, the conversation keeps the token. @path inside a paste is not looked up. |
Leaving a turn that will not stop
A turn normally ends when it is cancelled. A turn that ignores the cancellation — an engine that stopped answering, a tool blocked on something that never returns — used to trap the window: /quit and /abort waited for the turn to end, so they never ran, and Ctrl-C read "there is a turn to cancel" as "so do not quit". The only way out was to kill mm from another terminal.
The way out, in order:
| You do | The window does |
|---|---|
Esc or /abort |
Cancels the turn, and says 🛑 Aborting…. |
Esc or /abort again |
The turn is still there: ⚠️ The turn is not answering the cancellation — press Ctrl-C (or /quit) to leave mm. |
Ctrl-C |
Cancels, as above. |
Ctrl-C again |
Leaves mm, turn or no turn. |
/quit |
Leaves mm at once, at any moment. |
Leaving this way does not wait for the stuck job: the session file holds everything saved up to the last completed turn.
The three pickers
A popup opens over the conversation as you type one of three triggers, and narrows as you type more. Tab completes the highlighted row, ↑/↓ move, Esc dismisses it until the text changes.
| Trigger | Offers | Where it works | What Tab writes |
|---|---|---|---|
/ |
the window's commands | only as the whole first word of the box — a command is the message | the command, replacing the box, with a space when it takes an argument |
@ |
files and directories under the working directory | anywhere in a sentence | the path with its @ kept. A directory gets a trailing / and no space, so Tab again walks down the tree; a file gets a space, so the sentence continues |
$ |
the skills of the catalogue | anywhere in a sentence | $name — the $ kept — plus a space, with the cursor after it, ready for the skill's parameters |
Three rules keep the popup out of the way:
- A trigger glued to the end of a word is not a trigger:
bob@example.comopens nothing, and neither does5$. @hides dotfiles until you type the.yourself.$offers nothing when no skill matches, soecho $HOMEand$PATHare left alone.
Enter on a @ or $ token completes it rather than sending: the message is not finished. Enter on a command whose name is already complete sends it.
What $name does when sent
$greetings Bob Morane appends one line to what the model reads, the same way @path appends an attachment line:
use $greetings Bob Morane
[skill: greetings — load it with read_skill and carry out its steps now; parameters: Bob Morane]
The parameters are the rest of the line. The model still makes the read_skill call itself, so the loop detector, the permission gate and the 📖 N skill(s) recap all see it — mm does not load the skill behind the model's back.
The notation works in the line mode and over ACP too, typed by hand: a $skill means the same thing wherever it is written, as @path does. A $name that matches no skill is left alone, and a $ inside a collapsed paste is not looked up.
Messages printed at the end of a turn
| Message | Meaning |
|---|---|
🛑 Generation aborted. |
The turn was cancelled (/abort, Ctrl+C). The question and any completed tool turns stay in the history. |
[error: …] |
The provider explained a failure in one line; a question that got no answer is removed from the history. |
⚙ N command(s) |
Number of bash commands that actually ran in the turn. |
· 📝 N file op(s) |
Appended when file tools ran. |
· 📖 N skill(s) |
Appended when skills were loaded. |
| Numbered green list | The commands and file operations of the turn, one per line, when displayCommands: true. |
ACP mode
Two commands exist in ACP mode, three with unloadModels (the default): /new, /compact and /unload — plus /memory with sessions.searchMemory and /docs with docSearch.searchDocs. They are advertised to the editor through an available_commands_update notification and intercepted by session/prompt when the prompt text, trimmed, is exactly the command (/unload may be followed by a model name, /memory and /docs by their words). Each answers with one agent_message_chunk carrying the line the terminal would print, then stopReason: end_turn; the model is not consulted.
| Command | Over ACP |
|---|---|
/new |
Same as in the terminal: history back to the system prompt, token count and this session's plans forgotten (other sessions keep theirs); the session id, cwd and allow-always grants are kept. |
/compact |
Same as in the terminal, always forced: 🗜️ compressed …, 🗜️ nothing to compact: … or [compact: failed, history kept: …]. Waits for a running turn to finish first. |
/memory <words> |
With sessions.enabled and sessions.searchMemory, advertised with the input hint <words>: same as in the terminal, in the session's project (sessions.dir under its cwd), as the agent's text; the history is not touched. |
/docs <words> |
With docSearch.searchDocs, advertised with the input hint <words>: same as in the terminal, from the session's cwd, as the agent's text; the history is not touched. |
/unload [model] |
With unloadModels (default on), advertised with the input hint [model]: same as in the terminal, the 🧹 line as the agent's text; the history is not touched. |
With mmConfigs, /ask-<name> and /ask-with-context-<name> are advertised too, each with the input hint <prompt>; the generic /ask <name> is not, since an editor's menu completes a command name but not its argument. See Asking another agent.
/quit and /abort do not exist in ACP mode: the editor owns the process and ends it by closing stdin, and cancels a turn with its own stop key through session/cancel. Each skill is offered there as a command of its own — ACP has no picker for skills, so /greetings Bob in the editor's menu is the equivalent of $greetings Bob in the window, and it is rewritten into exactly that. See the ACP 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 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 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
|