# 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, check the open-source orchestrator skills for [Codex](https://github.com/dcouple/skills/tree/main/parsa/.codex/skills/runpane-orchestrator) and [Claude Code](https://github.com/dcouple/skills/tree/main/parsa/.claude/skills/runpane-orchestrator).

[Pane Chat](/docs/pane-chat) is the built-in orchestrator that uses these same commands from inside Pane. It can run Claude or Codex, load local workflow skills, and coordinate repos, panes, agents, reviews, and PR tests.

<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

| Command | Needs Pane running | Changes things | What it does |
| --- | --- | --- | --- |
| `runpane version` | No | No | Print the package version. |
| `runpane doctor --json` | No (but checks daemons) | No | Check the wrapper, app, daemon, remote service, and setup. |
| `runpane daemon repair --pane-dir <path> --yes --json` | No | Yes | Rewrite and restart a managed remote service without changing its connection setup. |
| `runpane agent-context --json` | No | No | Print a short command summary for agents. |
| `runpane agent-context --command "<cmd>" --json` | No | No | Print full details for one command. |
| `runpane agents doctor --agent codex --repo active --json` | Yes | No | Check if the selected agent is available in the repo environment Pane will use. |
| `runpane repos list --json` | Yes | No | List saved repos. |
| `runpane repos add --path <repo> --yes --json` | Yes | Yes | Add a git repo to Pane. |
| `runpane panes list --repo active --json` | Yes | No | List panes (optionally for one repo). |
| `runpane panes create ... --yes --json` | Yes | Yes | Create panes and start agents. |
| `runpane panes cost --json` | Yes | No | Show token usage and estimated cost per pane. |
| `runpane panes archive --pane <pane-id> --yes --json` | Yes | Yes | Archive a pane and safely remove its Pane-managed worktree. |
| `runpane panes pin ...` | Yes | Yes | Pin a pane without changing focus. |
| `runpane panes unpin ...` | Yes | Yes | Unpin a pane without changing focus. |
| `runpane panes rename ...` | Yes | Yes | Rename a pane without changing its branch or worktree. |
| `runpane panels create ... --yes --json` | Yes | Yes | Add a terminal tab to an existing pane. |
| `runpane panels list --pane <pane-id> --json` | Yes | No | List tabs inside a pane. |
| `runpane panels screen --panel <panel-id> --json` | Yes | No | Read what's currently on screen. |
| `runpane panels output --panel <panel-id> --json` | Yes | No | Read recent terminal output (scrollback). |
| `runpane panels wait --panel <panel-id> --json` | Yes | No | Wait until a panel is ready, idle, or shows specific text. |
| `runpane panels submit --panel <panel-id> ... --yes --json` | Yes | Yes | Send text and press Enter. |
| `runpane panels input --panel <panel-id> ... --yes --json` | Yes | Yes | Send raw terminal bytes. |
| `runpane panels submit-composer --panel <panel-id> --yes --json` | Yes | Yes | Submit an agent's composer with the right key combo. |
| `runpane watch --self-test` | Yes | No | Check that the event stream works, without touching any cursor. |
| `runpane watch --as <name> --follow` | Yes | No | Stream agent, pane, and tab events as they happen. See [runpane watch](#runpane-watch). |
| `runpane doctor --report --title <text> --body-file <path\|-> --json` | No | No | Write a watcher failure report from captured output, for handing to a human. |

Commands that change things require `--yes` for automation.

## 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.

Create a pane 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. Add `--pinned` when the pane should show up pinned from the start.

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
```

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`. | Decide whether to give it work or archive the pane. |
| `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. |

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 kinds | Only print these event kinds. Kinds: `agent.ready`, `agent.busy`, `agent.blocked`, `agent.idle`, `agent.unknown`, `pane.created`, `pane.gone`, `panel.exited`. |
| `--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. Pane Chat keeps it and filters, so a person reading the raw stream still sees proof of life.

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. It is exactly what [Pane Chat](/docs/pane-chat) arms at session start, 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 finished pane:

```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 for the worktree to be removed before the command returns.

## 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

After a PR exists, keep reviewers in the same pane instead of creating more top-level panes:

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

runpane panels create \
  --pane <pane-id> \
  --agent codex \
  --source agent \
  --no-focus \
  --wait-ready \
  --yes \
  --json
```

Send each reviewer `/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.

The reusable version of this workflow lives in [`dcouple/skills`](https://github.com/dcouple/skills): [Codex](https://github.com/dcouple/skills/tree/main/parsa/.codex/skills/runpane-orchestrator) and [Claude Code](https://github.com/dcouple/skills/tree/main/parsa/.claude/skills/runpane-orchestrator).

## Creating multiple panes at once

`panes create --from-json <path|->` accepts a JSON payload. It's cleaner than shell-escaping a bunch of prompts.

```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 that create, change, or delete things ask for confirmation in a terminal. Pass `--yes` in scripts. Without it, a command that changes things fails instead of waiting forever in CI.

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
```

## 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>
--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 />
