# runpane CLI

`runpane` is a CLI that does two things: it installs Pane, and it lets agents control Pane.

For the landing page overview, see [runpane CLI: Agent Control for Pane](/runpane-cli). For the full issue-to-PR workflow, use the orchestrator skill built into [Pane Chat](/docs/pane-chat).

[Sessions](/docs/sessions) are Pane's built-in orchestrator, and they use these same commands from inside Pane. A Session runs Claude Code, Codex, Cursor or your own command, and coordinates repos, panes and agents for you. Agents that prefer tools can use the same commands through Pane's [MCP server](/docs/mcp).

<PackageInstall />

## How agents find Pane

Start by checking that Pane is set up and healthy:

```bash
# Before installing anything:
curl -fsSL https://runpane.com/runpane-cli-contract.json

# After runpane is installed:
runpane doctor --json
runpane agent-context --json
runpane agent-context --command "panes create" --json
```

`runpane agent-context` prints a short summary by default. It works without Pane running. Use `--command` to get full details for one specific command when you need them. The command name is flexible: `panes create`, `panes.create`, and `runpane panes create` all work.

`runpane version` just prints the package version. It doesn't launch or focus Pane.

`runpane doctor` checks the wrapper, installed app, local daemon, remote service, and remote setup. On macOS and Windows, it reads app metadata instead of launching Pane.

## Start with doctor

Run this before a script creates or changes anything:

```bash
runpane doctor --json
```

The report tells you which Pane directory and daemon endpoint the CLI checked. It also gives you the next command when something is missing.

For an isolated remote host, point it at that host's Pane directory. If you chose a different directory during setup, use that path instead of `~/.pane_remote`.

```bash
runpane doctor --pane-dir ~/.pane_remote --json
```

Doctor also checks whether the remote service can find Pane after a restart. A reachable daemon can still be unsafe to restart after an upgrade. Doctor catches that state and prints the repair command.

See [Remote VM Setup](/docs/remote-daemon#check-and-repair-the-service) before restarting the service.

## Install

For a one-time install or update:

```bash
npx --yes runpane@latest
pnpm dlx runpane@latest
pipx run runpane
uvx runpane@latest
```

For agents or scripts that call `runpane` repeatedly, install it permanently:

```bash
npm i -g runpane
runpane setup

python -m pip install runpane
python -m runpane setup
```

The packages don't install or configure Pane during package install. Nothing happens until you actually run a `runpane` command.

## Setup wizard

Run `runpane` with no arguments (or `runpane setup`) in a terminal. The wizard can:

- Install the Pane desktop app
- Set up this machine as a remote host
- Update an existing install
- Run diagnostics

In CI or non-interactive shells, it prints help instead of waiting for input.

## Command reference

`runpane` has 77 commands. Here they are by job. Run `runpane agent-context --command "<command>" --json` for every flag of one command.


### Setup and health

| Command | What it does |
| --- | --- |
| `runpane help` | Show help for runpane or a specific command. |
| `runpane setup` | Open the guided setup wizard for install, remote host setup, update, and diagnostics. |
| `runpane install` | Install Pane on this machine or configure this machine as a remote daemon host. |
| `runpane update` | Update the Pane desktop app using the same artifact path as install client. |
| `runpane version` | Print the runpane wrapper version without contacting, launching, or focusing Pane. |
| `runpane doctor` | Run platform, release, installed Pane, daemon reachability, and remote setup diagnostics. |
| `runpane daemon repair` | Repair and restart the managed remote-daemon launcher without changing pairing or tunnel configuration. |
| `runpane agents doctor` | Diagnose whether a built-in agent command is available in a Pane repository environment. |
| `runpane agent-context` | Print token-efficient Pane command context for coding agents. |
| `runpane mcp` | Run the Pane MCP server over stdio so coding agents can call runpane commands as tools. |
| `runpane docs search` | Search Pane's docs, runpane help, and the Pane Chat skills. |
| `runpane docs read` | Read one Pane doc, help topic, or skill in full. |

### Repos and panes

| Command | What it does |
| --- | --- |
| `runpane repos list` | List repositories saved in the running Pane app. |
| `runpane repos add` | Register an existing git repository with the running Pane app. |
| `runpane panes list` | List Pane sessions in a saved repository. |
| `runpane panes create` | 1 feature = 1 worktree = 1 branch = 1 Pane; reviews, audits, fixes and QA for it are tabs in that Pane. Create a Pane (a new worktree) only when the work's branch has no Pane yet; for review, audit, fix or QA on existing work use `panels create --pane <id>`. |
| `runpane panes adopt` | Adopt an existing externally managed git worktree as a Pane without changing the worktree. |
| `runpane panes archive` | Archive a Pane (session) exactly like the UI Archive action, including safe removal of its Pane-managed git worktree, or archive every merged Pane in a Session. |
| `runpane panes restore` | Restore an archived Pane, recreating its worktree. |
| `runpane panes pin` | Declaratively pin a Pane; pinned is the Pane UI's favorite/pin star and repeated requests are idempotent. |
| `runpane panes unpin` | Declaratively unpin a Pane; pinned is the Pane UI's favorite/pin star and repeated requests are idempotent. |
| `runpane panes rename` | Rename a Pane without changing its worktree, branch, panels, or focus. |
| `runpane panes focus` | Raise the Pane window and select a Pane (and optionally one of its panels) on explicit user request. |
| `runpane panes move` | Move a Pane into a sidebar folder. |
| `runpane folders list` | List the sidebar folders of a repository. |
| `runpane folders create` | Create a sidebar folder in a repository. |
| `runpane panes cost` | Report estimated token cost per Pane, with per-model breakdown and cache efficiency. |
| `runpane workspace state` | Read one workspace snapshot of every Pane and CLI panel. |

### Tabs and terminals

| Command | What it does |
| --- | --- |
| `runpane panels create` | Open a new agent or terminal tab inside an existing Pane, sharing its worktree. The default for review, QA, fixes and any other agent on work that already has a Pane. |
| `runpane panels open` | Open a URL or file as a browser/editor tab in a Pane, in split view beside the agent by default. |
| `runpane panels list` | List tool panels inside a Pane session. |
| `runpane panels output` | Read recent terminal output from a panel. |
| `runpane panels screen` | Read a compact current-screen view from a terminal panel. |
| `runpane panels input` | Send input bytes to a terminal panel. |
| `runpane panels submit` | Send and submit text to a terminal panel, including idle agent composers. |
| `runpane panels submit-composer` | Submit an agent composer using the panel-appropriate key sequence. |
| `runpane panels wait` | Wait for a terminal panel to initialize, become ready/idle, or contain text. |
| `runpane panels last-message` | Read an agent's last reply from its transcript, without scraping the screen. |

### Git and scripts

| Command | What it does |
| --- | --- |
| `runpane panes git-status` | Read the git status of a Pane worktree: uncommitted, unpushed, and behind-main counts. |
| `runpane panes commit` | Stage all changes in a Pane worktree and commit them. |
| `runpane panes push` | Push a Pane branch to its remote. |
| `runpane panes pull` | Pull the remote branch into a Pane worktree. |
| `runpane panes fetch` | Fetch the remote for a Pane worktree. |
| `runpane panes rebase-main` | Rebase a Pane branch onto the latest main branch. |
| `runpane panes squash-rebase` | Squash a Pane branch into one commit and rebase it onto main. |
| `runpane panes stash` | Stash uncommitted changes in a Pane worktree. |
| `runpane panes stash-pop` | Apply and drop the latest stash in a Pane worktree. |
| `runpane panes soft-reset` | Undo the last commit in a Pane, keeping its changes staged. |
| `runpane panes run-script` | Run the repository's run script in a Pane. |
| `runpane panes stop-script` | Stop the run script running in a Pane. |

### Agents and orchestration

| Command | What it does |
| --- | --- |
| `runpane agents start` | Start an agent on a task and wait until it is ready: as a new tab in an existing Pane with `--pane <id>` (review, audit, fix, QA), or in a new Pane with `--repo` and `--name` for new work. |
| `runpane agents status` | Check on an agent: whether it is working, ready, blocked, or idle, plus its current screen. |
| `runpane agents send` | Send a follow-up message to an agent and confirm it was submitted. |
| `runpane report` | Hand back a worker's structured report: state, PR, head commit, summary, and the question when blocked. |
| `runpane watch` | Wait for workspace agent and Pane transitions using a daemon-held cursor. |
| `runpane sessions list` | List durable named orchestration Sessions. |
| `runpane sessions create` | Create a durable named orchestration Session and its hidden terminal owner. |
| `runpane sessions get` | Read one durable named orchestration Session. |
| `runpane sessions pin` | Pin a named Session to the top of the sidebar. |
| `runpane sessions unpin` | Unpin a named Session. |
| `runpane sessions update` | Update a Session overview from structured JSON. |
| `runpane sessions set-agent` | Switch the durable terminal agent for a named Session. |
| `runpane sessions associate` | Associate a user-visible Pane with a named Session. |
| `runpane sessions detach` | Detach a Pane from a named Session. |
| `runpane sessions overview` | Read a live status, activity, git, and pull request overview for a named Session. |
| `runpane lock acquire` | Acquire a named lock on a resource shared between agents, such as one test account, optionally waiting for it. |
| `runpane lock release` | Release a named lock you hold, or force-release another owner's lock. |
| `runpane lock list` | List held named locks, optionally only one Session's. |

### Other machines and Handoff

| Command | What it does |
| --- | --- |
| `runpane workspace list` | List your Tailscale machines and their Pane status. |
| `runpane workspace enable` | Turn on this machine's Workspaces listener. |
| `runpane workspace disable` | Turn off this machine's Workspaces listener. |
| `runpane workspace read` | Read a file on another machine. |
| `runpane workspace write` | Write stdin to a file on another machine. |
| `runpane workspace exec` | Run a shell command on another machine. |
| `runpane handoff` | Send your branch and a note to a fresh agent on the destination machine. |

These commands need the npm CLI. See [Workspaces](/docs/runpane-workspaces) and [Handoff](/docs/runpane-handoff) for examples and limits.

### Links

| Command | What it does |
| --- | --- |
| `runpane links create` | Build a pane:// link that opens a Pane, panel, repository, or Session in the Pane app. |
| `runpane links open` | Open a pane:// link in the running Pane app. |

Commands whose usage includes `--yes` require it for automation. Session creation, updates and pinning don't use that flag.

## Typical agent workflow

Here's what an agent does to get started:

```bash
runpane doctor --json
runpane agent-context --json
runpane repos list --json
runpane repos add --path "$PWD" --yes --json
runpane agents doctor --agent codex --repo active --json
```

`active` means the repo currently selected in Pane. You can also use a saved repo's id, exact path, or name. If a script could match more than one repo, use the id.

`repos add` only saves an existing git repo in Pane. It doesn't create a folder or run `git init` for you.

**1 feature = 1 worktree = 1 branch = 1 Pane; reviews, audits, fixes and QA for it are tabs in that Pane.** Create a pane only when the work's branch has no pane yet. To find the pane for a PR, get its head branch, then check each pane's `worktreePath` from `panes list`:

```bash
gh pr view <number> --json headRefName
runpane panes list --repo active --json
git -C <worktreePath> branch --show-current
```

If no pane owns the branch, create one with an agent:

```bash
runpane panes create \
  --repo active \
  --name "issue-252" \
  --agent codex \
  --prompt "Plan issue 252. Stop before editing." \
  --source agent \
  --wait-ready \
  --yes \
  --json
```

Pane creates the branch and worktree for the new pane. A worktree is its own isolated copy of the repo.

Use `--base-branch` when the work shouldn't start from the repo's default branch. New panes are pinned by default. Add `--no-pinned` to create one unpinned. Panes a Session creates start unpinned.

With `--wait-ready`, the CLI waits for the terminal and initial input. Check `initialInput.verifiedSubmitted` before you claim the prompt was submitted. `true` means Pane verified it.

If Pane can't verify submission without risking a duplicate, the result includes a safe `nextCommand`.

Use a custom terminal command when the agent isn't built in:

```bash
runpane panes create \
  --repo active \
  --name "custom-loop" \
  --tool-command "bash -lc 'my-agent --flag'" \
  --initial-input-file prompt.txt \
  --source agent \
  --wait-ready \
  --yes \
  --json
```

After creation, check what actually happened before pulling more history:

```bash
runpane panels list --pane <pane-id> --json
runpane panels wait --panel <panel-id> --for ready --timeout-ms 30000 --json
runpane panels screen --panel <panel-id> --limit 80 --json
runpane panels output --panel <panel-id> --limit 200 --json
```

Use `panels submit` for normal text:

```bash
runpane panels submit \
  --panel <panel-id> \
  --text "Continue with the review pass." \
  --yes \
  --json
```

For Claude Code and Codex, check `delivery` to see whether the agent took the follow-up or queued it. Don't resend a queued message. Add `--interrupt` to stop the current turn and send a replacement task in Claude Code, Codex or Cursor. For long prompts, `--as-file-pointer` writes the text to a file and sends its path.

Use `panels input` for raw bytes, Ctrl-C, escape sequences, or anything shell-sensitive:

```bash
printf '\003' | runpane panels input --panel <panel-id> --input-file - --yes --json
runpane panels screen --panel <panel-id> --json
```

If text is sitting in a Codex or Claude composer, let Pane submit it instead of guessing whether it's Enter or Ctrl+Enter:

```bash
runpane panels submit-composer --panel <panel-id> --strategy auto --yes --json
```

## runpane watch

`runpane watch` waits for things to change in your workspace and prints one line per event. It replaces polling `panels wait` or `panels screen` in a loop. The Pane daemon keeps the cursor, so a watcher started with a name picks up where it left off after a restart.

```bash
runpane watch --self-test
runpane watch --as my-orchestrator --follow
```

Run `--self-test` first. It probes the watch path without touching any cursor and prints a `WATCH OK` line when the daemon is reachable. Then start `--follow`, which keeps printing until you stop it. Without `--follow`, `watch` waits for one batch of events (up to `--timeout-ms`, a minute by default) and exits. `IDLE` lines need `--idle-after`, which is only set by default under `--follow`.

Give the watcher a name with `--as` whenever it might be restarted. A named cursor resumes from the last event it delivered; an anonymous one starts from now, so anything that happened while it was down is skipped. Inside a Pane tab you can skip `--as`, because Pane sets `PANE_PANEL_ID` and the CLI uses that as the name.

### What the lines mean

Each line starts with a keyword, then the pane name, pane id, and, for agent events, the tab (panel) id:

| Line | Meaning | What an orchestrator does with it |
| --- | --- | --- |
| `READY` | An agent finished its turn and is waiting at its prompt. | Read the screen, then send the next instruction. |
| `BLOCKED` | An agent is waiting on a person: a question or an approval. | Tell the human. |
| `BUSY` | An agent started working. | Nothing. There is no action to take on a working agent. |
| `IDLE <name> <n>m` | An agent has been sitting at its prompt with nothing sent to it for `n` minutes. Repeats every `--idle-after`. | Give it work. Archive its pane only after its PR merges or closes. |
| `STUCK ... held-input-present` | Real text is sitting unsent in an agent's composer. Printed right after the `READY` or `IDLE` it belongs to, and travels with it. Claude Code's grey prompt suggestion doesn't count. | Verify, then `panels submit-composer`. |
| `UNKNOWN` | Pane can't tell what state the agent is in, usually right after a restart. The next real state change follows on its own. | Read the screen if you need to know now. |
| `NEW`, `GONE` | A pane was created or archived. | Update your list. |
| `EXIT ... code <n>` | A tab's process exited. | Check whether it was expected. |
| `CHANGED` | Printed when a named cursor resumes and a pane's state differs from the last state it delivered. | Read the screen. |
| `HEARTBEAT` | The stream is alive. Printed every `--heartbeat` seconds. | Nothing. See [the cadence flags](#the-cadence-flags) for keeping it from waking an orchestrator. |
| `WATCH OK` | Printed once when the stream is armed. | Nothing. |
| `WATCH ERROR`, `WATCH RECONNECTED` | Under `--follow`, the CLI retries a daemon error every second. It prints `WATCH ERROR` when the error first appears or changes, and again once per `--heartbeat` interval while the same error continues, then `WATCH RECONNECTED` when the daemon answers again. An error it won't retry makes it exit non-zero. | Treat a `WATCH ERROR` line or a non-zero exit as a dead watcher and re-arm it. |
| `RESET`, `DROPPED` | The daemon's journal lost history: it was restarted, or events were evicted before delivery. | Re-read the screen of every pane you care about. |
| `REPORT <pane> pane <id> panel <id> <state> pr#<n> <sha>` | A worker ran `runpane report` with its state (`ready`, `blocked`, `failed` or `done`), PR and commit. It skips the `--min-interval` batch. Opt in with `agent.report`. | Read the full report with `runpane agents status` or `sessions overview`. |
| `JOINED`, `LEFT` | A pane joined or left the Session you're watching with `--session`. | Nothing. The watcher already follows it. |
| `PR <pane> pane <id> #<n> CONFLICTED` | A Session member's PR has a merge conflict. Pane checks open PRs about every 3 minutes, and prints on changes only. | Tell the pane's agent to fix it. |
| `PR ... CHECKS PASSED`, `PR ... CHECKS FAILED <names>` | The PR's checks finished. | On a failure, send the agent the fix. |
| `PR ... MERGED` | The PR merged. | Close out the work. |

Add `--json` (or `--format json`) to get one JSON object per line instead. Events carry the same fields plus the journal generation, and status lines become objects whose `kind` is `_ok`, `_heartbeat`, `_error`, `_reconnected`, `_reset`, or `_dropped`. The `epoch` in `_ok` identifies the journal; a `_reset` reports a new one. `--include-held-input` adds the actual composer text, which the lines form never prints.

### Flags

All watch flags are optional. Defaults are the responsive ones: every agent event kind, no delay, no batching. The four cadence flags are marked "opt in" and are covered in the next section.

| Flag | Default | What it does |
| --- | --- | --- |
| `--follow` | off | Keep streaming until interrupted. Required by the four opt-in cadence flags. |
| `--as <name>` | none (`PANE_PANEL_ID` inside a Pane tab, under `--follow`) | Use a named cursor the daemon persists across restarts. |
| `--since <generation>` | none | Use an explicit generation cursor instead of a named one. Can't be combined with `--as`. |
| `--from <now\|earliest>` | `now` | Where a brand-new named cursor starts. |
| `--format <lines\|json>` | `lines` | Output format. `--json` is an alias for `json`. |
| `--heartbeat <seconds>` | `60` under `--follow` | Seconds between `HEARTBEAT` lines. Off without `--follow`. Values above 120 are capped silently. `0` turns heartbeats off. |
| `--idle-after <ms>` | `600000` under `--follow` | Milliseconds an agent sits at its prompt before `IDLE` fires, and how often it repeats. Off without `--follow`. |
| `--settle <ms>` | `0` | Opt in. Print `READY` only if the agent is still idle after this many milliseconds. |
| `--blocked-settle <ms>` | `0` | Opt in. Print `BLOCKED` only if the agent is still blocked after this many milliseconds. |
| `--min-interval <ms>` | `0` | Opt in. Hold non-urgent lines and flush them together at most once per this many milliseconds. `BLOCKED` bypasses it. |
| `--idle-backoff` | off | Opt in. `IDLE` fires at `--idle-after`, then 30 min, 1 h, 3 h, then daily. |
| `--kinds <kind,...>` | all agent and pane kinds | Only print these event kinds: `agent.ready`, `agent.busy`, `agent.blocked`, `agent.idle`, `agent.unknown`, `pane.created`, `pane.gone`, `panel.exited`. Opt-in kinds print only when listed (or implied by `--session`): `agent.report`, `pane.associated`, `pane.detached`, `pr.conflicted`, `pr.checks`, `pr.merged`. |
| `--session <id\|name>` | none | Watch every pane associated with a [Session](/docs/sessions). Pane re-reads the Session's panes on every read, so associating or detaching a pane needs no restart. Can't be combined with `--pane` or `--all-managed`. |
| `--quiet` | off | Drop the lines that only prove the stream is alive: `WATCH OK`, `HEARTBEAT` and `WATCH RECONNECTED`. `WATCH ERROR`, `RESET` and `DROPPED` always print. Alias: `--no-control-lines`. |
| `--all-managed` | on | Watch every pane Pane manages. The default scope, spelled out. |
| `--pane <id>` | none | Watch one pane. Repeatable. Can't be combined with an explicit `--all-managed`. |
| `--exclude-pane <id>` | none | Skip one pane. Repeatable. |
| `--repo <selector>` | none | Only panes in one saved repo. |
| `--name-contains <text>` | none | Only panes whose name contains this text. |
| `--agents-only` | on under `--follow` | Only agent tabs, not plain shells. A one-shot `watch` includes shells unless you pass this. |
| `--include-shells` | off | Also watch ordinary shell tabs. |
| `--timeout-ms <ms>` | `60000` | How long a single wait lasts, capped at 120000. Under `--follow` the loop re-issues the wait. `0` polls once and exits. |
| `--limit <count>` | `256` | Maximum entries per response. |
| `--ack-now` | off | Advance a named cursor as soon as entries are handed out (at-most-once) instead of after they're delivered (at-least-once). Leave it off for an orchestrator: a repeated line is harmless because you read the screen before acting, while a lost one isn't. |
| `--include-held-input` | off | Include up to 120 characters of unsubmitted composer text in JSON output. |
| `--no-held-input` | off | Turn off `STUCK` detection entirely. |
| `--self-test` | off | Anonymous read-only probe of the watch path. Never advances a cursor and never applies cadence. |

Times are milliseconds everywhere except `--heartbeat`, which is seconds. `--heartbeat`, `--idle-after`, `--settle`, `--blocked-settle`, and `--min-interval` take a whole non-negative number; a fraction or a negative value is rejected before the daemon is contacted.

Two places to confirm what your install actually does: `runpane doctor` prints the effective `--follow` defaults for the installed version, and `runpane agent-context --command watch --json` prints this flag list with the wording the CLI ships.

### The cadence flags

Every line the watcher prints re-invokes the orchestrator that runs it. That's the model when an agent like Pane Chat runs `watch --follow` as a background task under its harness: the harness delivers each new line as a notification, and answering a notification means sending the agent's entire conversation back to the model as input. For a long-running orchestrator that is roughly 150k to 250k tokens per notification, most of it re-read from cache but paid for all the same. That re-invocation is what this page calls a wake-up.

The four opt-in cadence flags exist to print fewer lines. Each one removes a class of wake-up that carries nothing to act on. All four require `--follow`. Panes and people reading the stream in a shell pay nothing per line, so the defaults stay responsive and nothing changes for them.

- `--settle <ms>` holds a `READY` until the agent has stayed idle for the window. If that agent goes `BUSY`, `BLOCKED`, or `UNKNOWN`, or its tab exits, or its pane is archived inside the window, the `READY` is dropped silently, and so is the `STUCK` that would have followed it. A newer `READY` for the same agent replaces the pending one and restarts the window. The `READY` that does print carries `settledMs` in JSON. This is for agents whose status flips while they wait on their own subagents: a Claude Code pane running a `/do` workflow can go idle and working every few seconds for minutes, and each idle blip is a `READY` nobody should act on.
- `--blocked-settle <ms>` does the same for `BLOCKED`. If the question is answered in the pane within the window, no line prints.
- `--min-interval <ms>` batches. Every line you asked for except `BLOCKED` (`READY`, `IDLE`, `NEW`, `GONE`, `EXIT`, `UNKNOWN`, and `BUSY` if you kept it) is held and printed together, in one burst, at most once per interval, so a harness that wakes on new output wakes once for the batch. `BLOCKED` is the only urgent line: it bypasses the interval and carries whatever was held along with it. A settled `READY` therefore arrives with the next flush, up to settle plus interval after the turn actually ended.
- `--idle-backoff` stops `IDLE` from repeating forever. It fires at `--idle-after`, then 30 minutes, 1 hour, 3 hours, then once a day, per agent. Any state change in that agent resets the schedule. Without it, a pane idle for two days reports `IDLE` every ten minutes, all night.

`HEARTBEAT` is not shaped by any of these. It is printed by the CLI, not the daemon, and it's still 60 lines an hour. Either turn it off with `--heartbeat 0`, or keep it and make sure your harness's monitor filters lines starting with `HEARTBEAT` before they reach the agent. A Session runs with `--quiet`, which drops it, so a person who wants proof of life can run their own watcher without it.

Cadence state lives in the daemon, per named consumer, so both the npm and pip packages get the same behavior:

- `--settle`, `--blocked-settle`, and `--min-interval` need a named cursor: `--as <name>`, or `PANE_PANEL_ID` inside a Pane tab. If you pass one of them under `--follow` with no name, the CLI names the watcher `follow-<pid>`, which works but won't resume after a restart. `--idle-backoff` needs `--follow` but not a name.
- The three value flags can't be combined with `--since`, because an explicit generation cursor has no name to hold state under.
- `--self-test` sends no consumer name, so it never applies cadence.
- The daemon still reads every state change for an agent even when you exclude a kind with `--kinds`. That's how a `BUSY` you didn't ask for can still cancel a settling `READY`.
- If a named consumer comes back with different flags or a different scope, or with no cadence flags at all, the lines it was holding are re-delivered under the new filter. Named cursors are at-least-once: nothing is lost, and a line may repeat.

### Example: a cost-conscious orchestrator

This is the watcher an orchestrator should sit on. A [Session](/docs/sessions) runs the same flags with `--session <id>` once you've handed it work, where `PANE_PANEL_ID` supplies the name; outside a Pane tab, add `--as <name>` so a restart resumes instead of skipping:

```bash
runpane watch --self-test
runpane watch --follow \
  --kinds agent.ready,agent.blocked,agent.idle,panel.exited,pane.gone \
  --settle 180000 \
  --blocked-settle 30000 \
  --min-interval 600000 \
  --idle-backoff
```

Reading it flag by flag:

- `--kinds ...` drops `BUSY`, `UNKNOWN`, and `NEW`. `BUSY` is the big one: an agent starting work is not something an orchestrator can act on, and a pane waiting on subagents emits it constantly. `NEW` is dropped because the orchestrator is the one creating panes, and `UNKNOWN` because the next real state change follows on its own.
- `--settle 180000` waits three minutes before believing a `READY`. Measured across worktree panes, most gaps of more than two minutes between an agent's API calls were waits on subagents or review dispatches in the middle of a turn, not the end of one. A `READY` has to survive a few quiet minutes before it means anything.
- `--blocked-settle 30000` gives a person thirty seconds to answer a prompt in the pane before anyone is paged.
- `--min-interval 600000` delivers everything else in one batch every ten minutes. A `BLOCKED` still arrives within thirty seconds and brings the batch with it. (This ten minutes is unrelated to the `--idle-after` default, which also happens to be ten minutes.)
- `--idle-backoff` turns a pane that's been idle all night into a handful of `IDLE` lines instead of dozens.

The budget this buys: the ten-minute interval caps routine wake-ups at six an hour, and in practice an active pane produces one to three. `BLOCKED` lines add to that, which is the point. The trade is latency on `READY`. A turn that ends is acted on within about thirteen minutes at most (three of settle, then whenever the next ten-minute flush lands), which is fine for a pane whose next step is another multi-minute agent turn. Anything that actually needs a person still surfaces in thirty seconds.

Two consequences for whoever runs this watcher:

- Keep `HEARTBEAT` away from the agent, as described above. With it filtered, silence proves nothing: every pane may simply be busy.
- A watcher is dead when it exits non-zero or prints a `WATCH ERROR` line. Re-arm it once. If it dies again, capture its last lines to a file and file a report with `runpane doctor --report --title "runpane watch failed" --body-file <file> --json`, then tell the human.

## Manage a pane after creation

Pin important panes without changing what you're looking at:

```bash
runpane panes pin --pane <pane-id> --yes --json
runpane panes unpin --pane <pane-id> --yes --json
```

Rename a pane without renaming its branch or worktree:

```bash
runpane panes rename --pane <pane-id> --name "issue-393" --yes --json
```

Archive a pane after its PR merges or closes:

```bash
runpane panes archive --pane <pane-id> --source agent --yes --json
```

Archive uses the same safety checks as the desktop app. It stops when the pane has uncommitted, untracked, or unpushed work.

Commit and push anything you want to keep. Only use `--force` when you mean to discard that work and remove the worktree. Pane waits up to 30 seconds for cleanup. Check `worktreeCleanup` in the JSON result: `timeout` means the pane is archived but cleanup is still running. `trashDeletion: "pending"` means the worktree has been detached from git while its files are still being deleted.

## Background panes

When agents create panes, they shouldn't steal your active view.

- Use `--source agent` so the pane opens in the background by default.
- Use `--no-focus` if you want an explicit background guarantee.
- Use `--focus` only when the user asked to be moved to the new pane.

## Adding review tabs to the same pane

**1 feature = 1 worktree = 1 branch = 1 Pane; reviews, audits, fixes and QA for it are tabs in that Pane.** After a PR exists, add reviewers to its pane. Tabs share one checkout: only the implementer moves HEAD, and review, audit and QA tabs never run `git checkout`, `reset` or `stash`.

```bash
runpane panels create \
  --pane <pane-id> \
  --agent claude \
  --initial-input "/review" \
  --source agent \
  --no-focus \
  --wait-ready \
  --yes \
  --json

runpane panels create \
  --pane <pane-id> \
  --agent codex \
  --initial-input "/review" \
  --source agent \
  --no-focus \
  --wait-ready \
  --yes \
  --json
```

Each reviewer starts with `/review`. Wait for them to finish, copy their findings into the implementation tab, and ask the implementation agent to fix the real issues. Repeat until only non-blocking edge cases remain.

`runpane agents start` does the same in one call and waits until the agent is ready. Pass `--pane <id>` to open it as a tab in the feature's pane. Use `--repo` and `--name` only for new work, which creates a pane. This needs Pane 2.4.175 or later.

```bash
runpane agents start \
  --pane <pane-id> \
  --agent codex \
  --prompt "Review the PR from this branch and report findings." \
  --yes \
  --json
```

Usage:

```text
runpane agents start (--pane <pane-id> | --repo <selector> --name <name> [--base-branch <branch>]) (--agent <codex|claude|cursor>|--tool-command <command>) --prompt <task> --yes [--json] [--pane-dir <path>]
```

The reusable version of this workflow ships with Pane as the orchestrator skill in [Pane Chat](/docs/pane-chat).

## Creating multiple panes at once

`panes create --from-json <path|->` accepts a JSON payload. It's cleaner than shell-escaping a bunch of prompts. Each entry is a new worktree that installs and often builds, so list only features whose branches have no pane yet.

```json
{
  "repo": "active",
  "source": "agent",
  "waitReady": true,
  "panes": [
    {
      "name": "issue-252-discussion",
      "agent": "codex",
      "initialInput": "Run the discussion skill for issue 252."
    },
    {
      "name": "issue-253-discussion",
      "agent": "codex",
      "initialInput": "Run the discussion skill for issue 253."
    }
  ]
}
```

```bash
runpane panes create --from-json panes.json --yes --json
```

## Scripts and CI

Use `--json` when a script reads the result. You'll get JSON on success and failure, so you don't have to scrape terminal text.

Commands whose usage includes `--yes` ask for confirmation in a terminal. Pass it in scripts. Without it, those commands fail instead of waiting forever in CI. Session creation, updates and pinning don't use `--yes`; check the command's usage before adding flags.

Use `--dry-run` where the command supports it. Pane validates the request and shows what would change. It doesn't make the change. This is useful before create, pin, unpin, or rename commands.

For long prompts or exact input, use a file or stdin. This avoids broken quoting:

```bash
runpane panes create --from-json panes.json --yes --json
printf 'Continue with the review.\n' | \
  runpane panels input --panel <panel-id> --input-file - --yes --json
```

## Your other machines

When Tailscale is signed in, runpane reaches your other Macs, Windows PCs, and Linux machines with `runpane workspace <machine> read|write|exec|<command>`. The host's visibility decides who can connect. The CLI can't reach password-protected hosts yet, including for cross-machine Handoff. See [Workspaces](/docs/runpane-workspaces). To send a task to a fresh agent on another machine, see [Handoff](/docs/runpane-handoff).

## WSL and Windows

If your agent runs inside WSL but Pane is installed as a Windows app, the Linux shell might not see the Windows daemon. Call the Windows wrapper through PowerShell from a Windows directory:

```bash
powershell.exe -NoProfile -Command \
  'Set-Location $env:TEMP; runpane doctor --json'
```

Create panes the same way, selecting the saved repo by name or id:

```bash
powershell.exe -NoProfile -Command \
  'Set-Location $env:TEMP; runpane panes create --repo "Pane" --name "loop-smoke" --agent codex --prompt "Say hello from this loop and wait." --source agent --wait-ready --yes --json'
```

Run `runpane agents doctor --agent codex --repo <selector> --json` to check the environment Pane will actually use, not just the shell where the wrapper is running.

## Wrapper commands

```bash
runpane install [client|daemon] [options]
runpane update [options]
runpane version
runpane doctor [--json]
runpane daemon repair --pane-dir <path> [--yes] [--json]
runpane help [command]
```

Wrapper flags:

```bash
--version <latest|vX.Y.Z>
--download-dir <path>
--pane-path <path>
--format <auto|appimage|deb|dmg|zip|exe>
--dry-run
--yes
--verbose
```

`runpane install` is shorthand for `runpane install client`. `runpane install daemon` forwards remote-host setup flags to Pane's `--remote-setup` path.

Remote host setup flags:

```bash
--label <name>
--prefer-tunnel <tailscale|ssh|manual|auto>
--channel <stable|nightly>
--base-url <url>
--pane-dir <path>
--listen-port <port>
--port <port>
--repo-ref <ref>
--auto-listen-port
--interactive-tailscale-setup
--no-install-service
--no-tailscale-serve
--print-only
```

Unknown daemon flags get forwarded so newer Pane versions can extend remote setup without needing a wrapper update first. Unknown flags for other commands fail clearly.

## Local flags

These flags are used by commands that talk to the Pane daemon:

```bash
--pane-dir <path>
--repo <selector>
--pane <pane-id>
--panel <panel-id>
--path <path>
--name <name>
--worktree-name <name>
--base-branch <branch>
--agent <codex|claude|cursor|opencode>
--tool-command <command>
--title <title>
--initial-input <text>
--prompt <text>
--initial-input-file <path|->
--from-json <path|->
--timeout-ms <milliseconds>
--ready-timeout-ms <milliseconds>
--concurrency <count>
--limit <count>
--for <initialized|ready|idle|text>
--contains <text>
--interval-ms <milliseconds>
--format <lines|json>
--as <name>
--since <generation>
--from <now|earliest>
--kinds <kind,...>
--exclude-pane <pane-id>
--name-contains <text>
--heartbeat <seconds>
--idle-after <milliseconds>
--settle <milliseconds>
--blocked-settle <milliseconds>
--min-interval <milliseconds>
--text <text>
--input-file <path|->
--source <user|agent>
--strategy <auto|codex-ctrl-enter|enter>
--json
--wait-ready
--no-focus
--focus
--pinned
--force
--follow
--idle-backoff
--all-managed
--agents-only
--include-shells
--ack-now
--include-held-input
--no-held-input
--self-test
```

`--prompt` is an alias for `--initial-input`. In JSON payloads, use `initialInput`.

## JSON schemas

The `--json` request and response schemas live in one place:

```bash
curl -fsSL https://runpane.com/runpane-cli-contract.json
```

The contract is the exact command reference for the npm wrapper, PyPI wrapper, help text, and package tests. Use this guide for the workflow. Use the contract when your script needs field names or response shapes.

## Shell installers

Shell installers are still available if you don't have Node or Python:

<OsInstall />

Remote host shell installers:

<RemoteInstall />
