The API
Drive a running mnml from any shell with mnml remote, decide what a program may do through one prompt, and let a Claude Code session in an mnml pane use mnml as its IDE with no setup.
Every running mnml serves a local socket. Anything in one of its panes, or any shell on the same machine, can talk to it: open a file in it, run one of its commands, ask what it has open. Nothing that changes more than the view happens without you saying yes.
The same socket is what a Claude Code session in an mnml pane uses to treat mnml as its IDE.
mnml remote
mnml remote — or mnml r for short — is the shell client:
mnml remote open PATH[:LINE[:COL]]
mnml remote run COMMAND-ID
mnml remote status
mnml remote panes
mnml remote ping
mnml remote instances
mnml remote call METHOD [JSON]| Verb | What it does |
|---|---|
open PATH[:LINE[:COL]] |
Opens the file in the active pane, at the line and column if you give them. |
run COMMAND-ID |
Runs one of mnml's commands — any id from the command reference. It asks you first unless the command only changes the view. |
status |
The instance's status. |
panes |
The open panes. |
ping |
A round trip, to check that mnml answers. |
instances |
Every mnml running on the machine. |
call METHOD [JSON] |
Any method of the API, raw, with its parameters as JSON. |
For example, from a shell beside a test failure:
mnml r open src/parser.zig:120:8
mnml r run git.refreshThree flags go before the verb:
--jsonprints the result as JSON, exactly as mnml sent it — for scripts.--instance PIDpicks the mnml with that process id.--workspace PATHpicks the mnml open on that workspace.
Which mnml it talks to
Each running mnml leaves a small marker file naming its process id, its
workspace and its socket, and removes it when it exits. mnml remote
takes the first of these that matches:
- The mnml it runs in. Every terminal pane tells its programs where its own mnml's socket is, so a command run in a pane always reaches the mnml that pane belongs to — and acts as that pane.
--instanceor--workspace, if you gave one.- The directory you are in. The mnml whose workspace holds the current directory (the closest one, if workspaces nest).
- The only one running.
If none of these picks one — nothing is running, or several are and
nothing tells them apart — it stops with exit code 3 and prints the candidates — process id, workspace and start
time — so you can pick one with --instance or --workspace. A marker
left behind by an mnml that is no longer running is cleaned up by
whoever finds it.
Exit codes
| Code | Meaning |
|---|---|
0 |
Done. |
1 |
The method failed — no such command, for instance. The reason is on stderr. |
2 |
Usage: a missing or unknown verb or argument. |
3 |
No mnml found, or several and none matched. |
4 |
Not permitted: the caller is not an mnml pane, or the API is off. |
5 |
You said no, or nobody answered within two minutes. |
7 |
Protocol mismatch: an mnml that does not speak this version of the API, or no such method. |
What a program may do
Every command has an effect class, listed for each one in the command reference:
| Class | What it can touch |
|---|---|
view |
Only what you see. |
edit |
A buffer. |
write |
The disk, git, the network, config. |
exec |
A process. |
A view command asked for over the API runs at once. Anything above it
waits for you:
- A toast says who is asking and for what — for example
pane 4 · zsh asks to run git.commit (write)— with a Review button. It never takes the key you are typing. - Review opens a confirm box with four answers: Allow once, Allow write for the session (named for the class asked for), Deny, and Cancel, which puts the request back on its toast to answer later.
- A request nobody answers in two minutes is denied.
A grant for the session covers that one class, for the pane that asked, until the pane closes. Closing a pane denies whatever it was waiting on.
Only a program running in one of mnml's own panes can ask at all. Each
pane hands its programs a private token, so mnml knows which pane is
calling and names it in the toast. A connection from anywhere else — a
shell in another terminal, say — may read the status, list the commands
and ping, and nothing more: open, panes and run from there exit
with code 4.
Letting things through unasked
There is no Settings row for this; it goes in config.zon:
.api = .{
.allow_commands = .{ "git.refresh" },
.clients = .{ .{ .name = "file-channel", .allow = .{ .edit }, .commands = .{ "test.run_file" } } },
},.api.allow_commands lists commands that run without asking, for any
caller allowed to ask in the first place.
Each .api.clients row names a caller — pane:<id> for a pane,
file-channel for the file channel below — and the classes and
commands it may use unasked. The
configuration reference has the details.
The audit trail
Every decision — run freely, allowed by the config, allowed once or for
the session, denied, timed out — is one line in
<workspace>/.mnml/ipc/audit.jsonl, readable only by you.
The file channel
mnml also reads commands a program appends to
<workspace>/.mnml/ipc/command. That channel asks the same way, through
the same toast and confirm box, and writes to the same audit file.
Claude Code, with no setup
A Claude Code session that mnml starts in one of its panes links to mnml
as its IDE, the way it would link to an editor plugin. There is nothing
to install or configure: mnml prepares the link when it starts the pane.
It is made only for panes mnml started as Claude Code sessions — a
claude typed into a shell pane, a Codex pane or a plain shell gets no
link — and only while the API is on.
Each session gets a link of its own, so mnml always knows which session is asking.
What the session can do
- Read your selection — what is selected in the editor you are in, or in the last one you used.
- See what is open — the workspace, the open editors, and which of them have unsaved changes.
- Read diagnostics from your language servers, for one file or all of them.
- Open a file, optionally with a passage selected.
- Propose a change. The proposed file opens in the review pane
beside your buffer, titled with the session's name, diffed against the
buffer as it stands — unsaved edits included. Accept the hunks you
want and press Enter: they go into the buffer as one undo step, the
file is saved, and the session is told so. Esc,
q, closing the tab, or Enter with nothing accepted rejects the proposal. A second proposal for the same file replaces the first. - Ask to save a file. Saving is a
write, so it asks you through the same toast as a command, unless you have allowedwritefor that session.
The proposal is the one change that does not ask first, because your review of it is the approval.
The review opens where it leaves the session in view. It becomes a tab
in the split that holds the file, or else in a split showing an editor.
When the session is the only split on screen, a new split opens beside
it. Accepting, rejecting or pressing Esc puts the focus back on the
session. To choose a different placement, set ai.review_placement or
use its row in Settings ▸ AI: .beside always opens a split beside the
session, and .tab opens the review as a tab of the focused split, as
earlier versions did.
What it cannot do is run code through the link: mnml refuses that request.
What you see
- A link mark,
⇄(=with--ascii), after the session's name on its tab while the link is up, and in the gutter beside its card in the SESSIONS section of the sidebar when no other mark is showing there. - A toast the first time the session connects:
Claude Code connected to mnml (pane 4).
Your selection
As you select text in an editor, mnml tells one linked session about it: the one whose pane you looked at most recently. With several sessions open, look at the one you mean before you select.
ai.send_selection goes a step further and points that session at the
selected lines — or the cursor's line, with nothing selected — so you
can ask about them by name. See AI sessions for the
sessions themselves.
Every call a session makes goes through the same gate as the socket and is a line in the audit file.
Turning it off
Settings → Integrations → API: on / off. Off, mnml serves no
socket, mnml remote cannot reach it, and Claude Code sessions are not
linked. In config.zon it is .api.enabled.