# CLI

mandeck — the same Deck API from any shell or script. Every command, how ids work, and the exit codes an orchestrator branches on.

## Get it

`scripts/mandeck` is a zero-dependency bash script. Install it on `PATH` with
`scripts/install-cli.sh`, or take it from a deck you can already reach — no
repo checkout needed:

```bash
curl -so /opt/homebrew/bin/mandeck http://127.0.0.1:7717/cli/mandeck \
  && chmod +x /opt/homebrew/bin/mandeck
```

It reads the bearer token from the app's own support directory, so there is
nothing to configure. A bot should call the absolute path
(`/opt/homebrew/bin/mandeck`): a shell alias of the same name is a common
collision, and a bot cannot see the alias table.

Any agent in any pane can run this — that is how one agent hands work to agents
in other repos, and how you get one place to watch it happen.

## Every command

`mandeck` with no arguments lists sessions.

| Command | Does |
|---|---|
| `mandeck ps` | what is running: address, pane uuid, agent, state |
| `mandeck spawn <agent> [dir] [-p "task"]` | start one |
| `mandeck fanout <agent> "task" <dir>...` | the same task in every repo, one tab |
| `mandeck send <id> "text"` | type into a pane, press Return |
| `mandeck screen <id> [lines]` | what that pane shows right now |
| `mandeck waiting` | only the panes waiting on a human |
| `mandeck key <id> ctrl-c\|escape\|ctrl-d\|enter\|up\|down\|0-9` | interrupt, or answer a TUI picker |
| `mandeck close <id> [--force]` | close a pane (one the human opened needs `--force`) |
| `mandeck focus <id>` | bring the human's eyes to it |
| `mandeck tabs` | the tabs on this deck |
| `mandeck history [query]` | what this deck worked on before |
| `mandeck resume <session-id>` | reopen a past conversation |
| `mandeck accounts` | subscriptions this deck can spend |
| `mandeck agents` | agent CLIs this Mac can actually run |
| `mandeck jobs` | tasked-spawn jobs, newest first |
| `mandeck events [since]` | `needs-you\|spawned\|needs-review\|done\|failed` after seq |
| `mandeck messages <id> [limit]` | structured transcript (screen when the agent has none) |

## The job lifecycle, in a shell

| Command | Does |
|---|---|
| `mandeck job spawn <agent> --dir PATH [-p "task"] [--force]` | start a tasked pane |
| `mandeck job send <id> "text"` | type into that job's pane |
| `mandeck job wait <id> [--timeout SEC]` | block until done, failed, waiting-you, or timeout |
| `mandeck job report <id>` | transcript / last output to stdout |
| `mandeck job done <id>` · `mandeck job fail <id>` | explicit finish (the only way a job ends) |

`job spawn` prints one `job<TAB>session<TAB>pane` line. On 409 — that agent and
cwd already have a live pane — it still prints that line for the existing pane
and exits 2, and **the prompt was not delivered**: `job send` it, or pass
`--force`.

`job spawn` also takes `--tab NAME` to group panes and `--check-after MIN` to
set how long the deck waits before reminding you to check the result. See
[Jobs & hand-offs](/docs/jobs-and-hand-offs).

```bash
JOB=$(mandeck job spawn claude-code --dir ~/myrepo -p "fix the failing test" | cut -f1)
mandeck job wait "$JOB" --timeout 600
mandeck job report "$JOB"
```

## Exit codes

`job wait` exits `0` done, `2` failed, `3` waiting-you, `4` timeout. On
waiting-you, read the screen, answer with `job send` or `key`, and wait again.
Invalid arguments print usage.

## Addressing

Ids are what `ps` prints: `"2.3"` is tab 2, pane 3 — a **position** that moves
when a pane opens above it or closes. The pane uuid (`p70`) never moves. Hold
the uuid for anything longer than one command, and never close or send by
address from a script.
