# Command line tool
URL: https://docs.munito.ai/cli

```bash
npx @munitoai/cli agent "fix the failing test"
```

That creates a sandbox, uploads your git worktree, runs Claude Code on the open
models of Munito AI, applies the patch to your working copy, prints what it
cost and deletes the machine. One command, one key.

## Install [#install]

```bash
npm install -g @munitoai/cli
```

Or run it with no install, as `npx @munitoai/cli <command>`. It needs Node 22.12 or
later.

The command is `munito` either way. In a project that wants `npx munito` as well,
take the alias:

```bash
npm install -D munito@npm:@munitoai/cli
```

## Sign in [#sign-in]

```bash
munito login
```

The command asks for an [API key](https://console.munito.ai/keys) with the
**Inference** permission, checks it, and saves it to
`~/.config/munito/auth.json`, readable by you only. `MUNITO_API_KEY` in the
environment wins over the saved key, so a scripted run never takes a stale
sign-in.

## Run an agent [#run-an-agent]

```bash
munito agent "fix the failing test"             # claude, on our models
munito agent codex "add a retry to the client"  # another harness
munito agent dsh "explain this module"
```

The first word is the harness when it names one, and part of the task when it
does not.

| Flag          | What it does                                                                           |
| ------------- | -------------------------------------------------------------------------------------- |
| `--provider`  | Where the model comes from: `munito`, `anthropic` or `openai`. The default is `munito` |
| `--auth`      | `token` or `subscription`. The default is `token`                                      |
| `--model`     | A model id, in place of the recommended one                                            |
| `--repo`      | A directory to upload. The default is the current git worktree                         |
| `--no-upload` | Send no files                                                                          |
| `--no-apply`  | Do not apply the patch to your worktree                                                |
| `--keep`      | Leave the sandbox running when the task ends                                           |
| `--max-turns` | Stop the agent after this many turns                                                   |
| `--size`      | `tiny`, `small`, `default` or `large`                                                  |
| `--json`      | NDJSON events, for a script or another agent                                           |

### What goes up, and what comes back [#what-goes-up-and-what-comes-back]

The agent runs on the `agent` [template](https://docs.munito.ai/sandboxes/templates), which carries the harnesses. Against a
region that does not have that template yet, the tool uses `ubuntu` and installs the harness once, which takes about
a minute. Pass `--template` to choose one yourself.

Only files that git tracks, or would track, go up: `git ls-files -co
--exclude-standard`. So an ignored secret, a build directory and a virtual
environment never leave your machine. Binary files and files above 1 MiB are
skipped, and the whole upload stops at 16 MiB.

The agent works in a git repository inside the sandbox. When it finishes, the
tool reads `git diff` and applies it to your worktree, leaving build
artefacts behind. Nothing is committed: `git diff` on your side shows what the
agent did.

### Your own key, or your own plan [#your-own-key-or-your-own-plan]

```bash
munito agent claude --provider anthropic     # your ANTHROPIC_API_KEY
munito agent claude --auth subscription      # your Claude plan, in the sandbox
```

With `--provider anthropic` the tool clears every Munito AI variable first, so
your Anthropic key reaches Anthropic and nothing else. With `--auth
subscription` it sets no credential at all: sign in inside the sandbox over
[SSH](https://docs.munito.ai/sandboxes/ports-and-ssh#ssh), and the sign-in stays there.
Munito AI never accepts, stores or forwards the token of a subscription.

## Machines [#machines]

```bash
munito ls                        # your sandboxes
munito create --template agent   # one that stays
munito create --agent codex      # one with a harness already pointed at us
munito run "pytest -q"           # one command in a throwaway sandbox
munito exec <id> "ls /workspace" # a command in a sandbox you have
munito ssh <id>                  # a shell
munito ssh <id> --forward 3080   # a shell, and a private port on your machine
munito open <id>                 # its desktop, in your browser
munito open <id> --port 3000     # any port, signed
munito pause <id>                # keep its files and processes
munito resume <id>
munito fork <id> --count 8       # eight copies of a paused sandbox
munito rm <id>
```

`munito create --agent <name>` takes the same `--provider`, `--auth` and
`--model` as `munito agent`, and leaves the machine running.

`munito open` signs a URL and opens it, so the port is public while the link
lasts. `munito ssh --forward` keeps the port private: it reaches your machine
through the SSH connection and nowhere else. Give it `3080`, `3081:3080`, or a
full `local:host:remote`, once per port.

## An agent with a screen [#an-agent-with-a-screen]

```bash
munito agent --desktop "open the docs in Firefox and read the pricing page"
```

`--desktop` starts the agent on the `desktop` [template](https://docs.munito.ai/sandboxes/desktop),
signs port 6080 and opens the viewer in your browser, so you watch the agent
work. It implies `--keep`, because a screen is no use once the machine ends.
Delete the sandbox with `munito rm <id>` when you are done.

## CI jobs on a warm disk [#ci-jobs-on-a-warm-disk]

A CI job spends its first minute installing what the last job installed. Build
the disk once, pause it, and fork it for each job. This is the
[CI recipe](https://docs.munito.ai/sandboxes/ci), as three commands.

```bash
munito ci warm "npm ci && npx playwright install --with-deps chromium"
munito ci run "npm test"
munito ci run "npm run lint"
```

`munito ci warm` creates a persistent sandbox, runs your install command,
and pauses it. A paused sandbox pays only for
[saved state](https://docs.munito.ai/sandboxes/pricing#saved-state). `munito ci run` forks
that base, runs one job in the fork, streams its output, deletes the fork and
exits with the job's exit code.

| Command                      | What it does                                                     |
| ---------------------------- | ---------------------------------------------------------------- |
| `munito ci warm "<install>"` | Build the base and pause it. A base of the same name is replaced |
| `munito ci run "<job>"`      | Fork, run, delete, and exit with the job's code                  |
| `munito ci status`           | Which base this repository has, and its state                    |
| `munito ci drop`             | Delete the base                                                  |

The base is named for the repository: `GITHUB_REPOSITORY`, then
`CI_PROJECT_PATH`, then the name of the current directory. Pass `--name` to
keep more than one. `munito ci warm` takes `--size`, `--disk` and
`--template`; `munito ci run` takes `--cwd`, `--timeout` and `--keep`, which
leaves a failed fork alive to look at.

Rebuild the base when a lock file changes:

```yaml
- run: npx @munitoai/cli ci warm "npm ci"
  if: steps.lock.outputs.changed == 'true'
- run: npx @munitoai/cli ci run "npm test"
```

A fork starts in about 310 ms with the whole warm disk in place, and the job's
exit code reaches the shell.

## From herdr [#from-herdr]

```bash
munito herdr add --name work
```

[herdr](https://herdr.dev/) is an open-source runtime for coding agents. It holds no compute: you bring machines and
it reaches them over SSH. This command makes a persistent sandbox, mints its SSH credential and hands herdr the
connection, with herdr's own `--install` copying its Linux build in. Our SSH is a plain byte pipe, so that works with
no helper of ours.

```bash
hc run --bg --on work --cwd /workspace --name agent claude
munito pause <id>     # keeps the terminal, the scrollback and the conversation
```

A paused sandbox pays only for its saved state, and a resume brings the agent back with its conversation. The minted
SSH credential expires, so run `munito herdr add` again for a new machine.

## From another coding agent [#from-another-coding-agent]

```bash
claude mcp add munito -- npx @munitoai/cli mcp
```

`munito mcp` serves the same work as MCP tools on stdio, so a Claude Code or Codex session can farm a task out to a
sandbox instead of running it on your own machine. Three tools:

| Tool          | What it does                                                            |
| ------------- | ----------------------------------------------------------------------- |
| `run_agent`   | Run a coding agent on a fresh microVM and return its answer and a patch |
| `run_command` | Run one command on a fresh microVM and return its output                |
| `list_agents` | The harnesses and providers that this key can use                       |

Each one deletes its sandbox when it finishes. Several can run at once, each isolated from the others.

## On your own machine [#on-your-own-machine]

```bash
munito init dsh
munito init claude --dry-run
```

`munito init` writes the configuration of a harness on this computer, from the
same table the sandbox uses. For a harness that takes a plugin instead, such as
Hermes, pi or OpenClaw, it prints the one command that installs ours.

## Colour and output [#colour-and-output]

The tool prints a table and colour only when it writes to a terminal. A pipe,
a CI job or a call from another agent gets plain lines, and `--json` gets
NDJSON, one event per line. It respects `NO_COLOR` and `FORCE_COLOR`.

## As an SDK [#as-an-sdk]

The package is the library as well as the binary.

```ts
import { Munito } from "@munitoai/cli";

const munito = new Munito({ apiKey: process.env.MUNITO_API_KEY!, region: "eu" });

const run = await munito.agent.run({
  agent: "claude",
  prompt: "fix the failing test",
  maxTurns: 20,
  onEvent: (event) => console.error(event.type),
});
console.log(run.result, run.patch);

const box = await munito.sandboxes.create({ template: "agent", internet: true });
await munito.sandboxes.exec(box.id, { command: "pytest -q" });
```

`munito.agent.run` takes an `onEvent` callback for progress, and returns the
answer, the patch, the exit code and the sandbox id.

## Exit codes [#exit-codes]

| Code  | Meaning                                             |
| ----- | --------------------------------------------------- |
| `0`   | The agent finished and its command succeeded        |
| `1`   | The API or the agent failed                         |
| `2`   | Your key, your plan or your arguments need a change |
| other | The exit code of the agent's own command            |
