Reference
Command line
Everything the TUI does to panes, projects and machines is also a conch subcommand, so you can script agents from a shell. conch help prints the commands to start with, and conch help all every one.
Scripting
conch task -cwd ~/src/api "Add a health check endpoint" # pane, worktree, branch
conch new -agent claude -cwd ~/src/api # Claude in the repo
conch send p1 "fix the failing tests" && conch send -keys p1 enter
conch read p1 # visible screen as text
conch status # panes with agent state
conch project ls # projects, base, worktrees
conch branch commit -m "Fix the flaky test" && conch branch pr # finish a task
conch worktree clean -y # remove finished worktrees and their branches
conch wait p1 && conch send p2 "review what p1 just changed" # chain tasks
conch agent prompt -wait p2 "check finding 3 again" && conch read p2 # one agent driving another
conch close p1
conch server reload # run a new build; panes keep running
conch server stop # stops the server and all panes
conch server stop stops the server and every pane it owns. To move onto a new build, use conch server reload.
On macOS the server runs with GODEBUG=asyncpreemptoff=1, restarting itself once at start-up to get there: a reload re-execs the server process, and macOS makes that wait for scheduling signals a busy server never takes, which would leave it serving nothing. If a reload ever leaves the socket in place with nothing serving it, conch status says the server is not answering rather than that it is gone, and simply running conch again clears that socket and starts a fresh server. The panes of the old one are lost; nothing else needs cleaning up by hand.
Global flag
-m MACHINE (or --machine MACHINE) before the subcommand runs it against a remote machine instead of this one; local means this machine.
conch -m gpu-box status
Subcommands
conch
conch with no subcommand opens the TUI, starting the server if needed.
Inside one of its own panes it refuses, the way tmux refuses a nested session: the inner TUI would take the keys and the mouse, and closing the pane would kill it. Detach with ctrl+b d first, or run CONCH_PANE_ID= conch to open one inside the pane anyway (conch -m MACHINE for another machine's TUI always works).
server
| Command | Description |
|---|---|
conch server | run the server in the foreground |
conch server stop | stop the server and every pane it owns |
conch server reload [-binary PATH] | run a new conch build without stopping panes; -binary picks the program to reload into (default: the server's own executable path) |
Panes
| Command | Description |
|---|---|
conch view | what the terminal is showing: its tabs, what each holds, and which pane has the keyboard. The server keeps no layout of its own — a TUI publishes this and conch carries it |
conch show [-name NAME] ID... | ask the terminal to put those panes in front of the person: one is brought up, several are gathered side by side in one tab. A request, not an order |
conch status (or conch ls) | show server and pane status: ID, name, state, agent, ssh host, size, folder and command of each pane. The ssh column is the host a terminal is logged in to with plain ssh right now — the one -ssh on upload and download reaches — and - for the rest. Its first line gives the server's uptime, which counts from the first server of a chain of reloads — its panes have been alive that whole time — and then (reloaded N ago) for when the running binary was loaded, which is the one that says whether your last build got there |
conch new [-cwd DIR] [-name N] -- CMD [ARGS...] | start a pane (default command: your shell; default folder: the current one, or with -m that machine's home) and print its ID |
conch new -agent claude [-cwd DIR] [-- CLAUDE ARGS...] | start Claude Code with state tracking |
conch send [-keys] ID TEXT... | type text into a pane; with -keys, the arguments are key names (e.g. enter, ctrl+c) |
conch read ID | print a pane's visible screen |
conch close ID | close a pane |
conch rename ID [NAME] | name a pane; without NAME it gets its own back. Refused when a running pane already has the name |
conch redraw ID | draw a pane's screen again, for stale text a program left behind |
conch wait ID [-state done] [-timeout 30m] | block until the pane's agent is done (or waiting, working, idle — several, comma separated, stop on the first to happen). Prints ID AGENT STATE. Exits 124 if the time runs out, so a script can tell that from a failure; without -timeout it waits as long as it takes |
conch [-m MACHINE] upload [-to DIR [-p]] [-f] PATH... | copy files or folders to the machine and print where each landed there: into DIR there (~ is its home), else its uploads folder (~/.config/conch/uploads), as dropping them on its pane does. A DIR that is missing is refused unless -p, which makes it and the folders above it first, as mkdir -p does. A name already taken is numbered (ca 2.pem) unless -f |
conch [-m MACHINE] download [-to DIR] [-f] PATH... | copy files or folders from the machine into DIR here (default: the current folder) and print where each landed; -f as for upload |
conch [-m MACHINE] upload|download -ssh PANE ... | the same with the host the terminal PANE (its ID or name) is logged in to with plain ssh — nothing of conch's needed there, as in its Files view. upload goes to that host's home unless -to says otherwise. It needs a key or an ssh agent for the host, since nobody is there to type a password |
Pane names
Every command that takes a pane's ID — send, read, close, redraw, wait, rename, agent explain, agent prompt — takes its name as well: the one in conch status's name column, set with conch rename or conch task -name. That is how one agent addresses another it started, without keeping track of IDs:
conch task -name reviewer -agent codex "Review the diff on this branch"
conch agent prompt -wait reviewer "Check finding 3 again" && conch read reviewer
- An ID is always an ID:
pand a number is never looked up as a name, so names of that shape are refused. - A name is looked up once, when the command starts; a
waitthen stays with that pane. - Names are exact and case sensitive. A name two running panes share is refused rather than guessed — say which with its ID. A pane that has ended still answers to its name until another running pane takes it.
- Names belong to one machine's server, so
-mlooks them up there.
When an agent runs these commands
An agent in a conch pane can drive conch with the same commands — start a reviewer, prompt it, read its answer. conch agent skill -apply teaches it how, and when to stop and ask you; Agents working together walks through it with examples. What it may change is kept to its own work:
- panes it started, and the panes those started, in any project;
- panes in its own project, whoever started them;
- its own project's branches and worktrees.
Anything else — typing into, closing, renaming or marking as seen another project's pane, sending it keys or a broadcast, removing another project, committing, pushing or discarding there — is refused with out_of_scope, and so is conch server stop or reload, and changing your own setup: the agents' skill, the library, a sync, or which local files a project copies into its worktrees:
conch: out_of_scope: the claude agent in p4 may not close p1: it did not start it, and it is in another project; do it from the TUI or a terminal pane
Reading is never refused (read, status, wait, sessions), and neither is starting panes and tasks: what an agent starts is its own, and each pane in the server's pane list carries who started it (created_by).
conch tells who is asking from the operating system — the process at the other end of the socket, and its parents up to a pane — not from CONCH_PANE_ID, so unsetting that changes nothing. Only a pane with an agent running in it is held to this: a terminal pane, the TUI and scripts outside conch act as you. It is a guard against a confused agent closing the wrong session, not a sandbox: a program set on escaping can leave the pane's process tree.
On other machines. -m from an agent's pane carries its scope along: conch asks this machine's server who is running the command and, for an agent, has the other machine's server hold the connection to what that agent started there — its panes (and theirs), and the projects it started them in. It has no project there otherwise, so another project's panes stay out of reach even when they share a name with its own. A machine whose conch predates this isn't driven from an agent's pane at all; conch machine upgrade it. A terminal pane's -m is you, as before. Like the rest, this asks conch: an agent that runs ssh itself, or points CONCH_SOCKET elsewhere so this machine's server can't be asked, is not held by it.
agent
| Command | Description |
|---|---|
conch agent explain ID | show how a pane's agent state was decided, as JSON |
conch agent status | list each supported agent: installed (with version and path) or not |
conch agent install NAME | run an agent's installer in a pane and wait for it |
conch agent prompt [-wait] [-until done,idle,waiting] [-timeout 30m] [-at TIME] ID TEXT... | send the pane's agent its next message and submit it. Unlike conch send it only types into an agent, and never into one waiting on a question — a permission prompt, a menu — where its Enter could answer something nobody read: it exits 3 and types nothing (a question that comes up in the moment before Enter leaves the message typed but unsent). With -wait it blocks until the work the message starts has ended — not on the done or idle still showing from before it — and prints ID AGENT STATE; a question the agent asks ends it too, unless -until leaves waiting out. An agent already working gets the message when that work ends, so that work is the one waited for. Exits 124 if -timeout runs out, and fails if the pane ends or another program takes it over. With -at (14:05, +30m, 2026-10-15 09:00) the server keeps the message and sends it then, once the agent is free — see Later, and on a schedule |
conch agent skill [-agent NAMES] [-remove] [-apply] | install conch's skill — how an agent in a conch pane starts, prompts and reads another — where each agent reads your skills: ~/.claude/skills/conch for Claude, ~/.agents/skills/conch for Codex, Gemini and OpenCode, ~/.config/devin/skills/conch for Devin. Without -apply it only says what it would do; -remove takes it away again. A conch skill there that conch didn't write is left alone. With -m it installs on that machine. Not from an agent's pane: it is your setup |
conch skill | print that skill to stdout instead of installing it, for an agent whose skills folder conch does not manage, a system prompt you assemble yourself, or a sandbox where it goes inline. The same bytes the installer writes |
conch agent setup [-agent NAME] [-copy] [-json] [DIR] | show what each agent loads in a folder; -agent limits it to one agent, -copy copies missing local files from the main checkout first, -json prints JSON |
conch agent sync [-user] [-from NAME] [-to NAMES] [-apply] [-undo [-stamp S]] [DIR] | give the other agents one agent's setup — instructions, skills, MCP servers — in a checkout, or with -user the setup in your home. Without -apply it only says what it would do; -undo puts a sync back. See One setup, every agent |
conch agent library [list | add | mcp | skill | on | off | rm | import AGENT | plan | apply | undo] | MCP servers and skills kept in conch, each given to the agents you choose. add NAME URL or add NAME -- COMMAND ARGS with -to NAMES, -env K=${VAR}, -header K=V, -sse; skill NAME FOLDER; on/off NAME AGENTS; plan says what apply would write. See Shared MCP servers and skills |
project
| Command | Description |
|---|---|
conch project add PATH | add a project to the sidebar |
conch project create [-no-git] PATH | create a folder with a git repository and an initial commit (-no-git: a plain folder) |
conch project ls | list projects, their base branch and worktrees |
conch project rm ID | remove a project from the sidebar |
conch project files ID [-reset | -none | PATTERN...] | set the local file patterns copied into new worktrees; -reset restores the defaults, -none copies nothing |
conch project setup ID [-none | COMMAND] | show or set the setup command run in each new worktree; -none runs nothing |
task
conch task [-cwd DIR] [-branch B] [-base B] [-agent NAME] [-n N] [-name N] [-at TIME] [-every SPAN] [-queue [-wip N]] [-after REF] PROMPT creates a branch and worktree and starts an agent with the prompt (-at later, -every again and again, -queue when the project has room, -after once other work has finished, on top of it: see Later, and on a schedule; conch schedule lists and removes what is scheduled); in a folder that isn't a git repository — or, with -m and no -cwd, the machine's home — the agent works there with no branch. See Tasks.
| Flag | Default |
|---|---|
-cwd DIR | a directory in the project; default: the current one. With -m it is required, as an absolute path on that machine |
-branch B | branch name; default: derived from the prompt |
-base B | branch to start from; default: the project's base |
-agent NAME | claude, codex, gemini or opencode, or several separated by commas; default: [agents] default |
-n N | attempts at the same prompt, each on its own branch (default: one per agent, at most 10) |
-name N | name the task's pane, to address it by in place of its ID (see Pane names). Refused while a running pane has that name, and with more than one attempt |
branch
Finishing a task from a script, the same steps as the changes view. Every command takes -cwd DIR (a directory in the project; default: the current one) and -branch B; without -branch conch uses the branch checked out in that directory. With -m MACHINE, -cwd is required and must be an absolute path on that machine.
| Command | Description |
|---|---|
conch branch commit -m MESSAGE [-file PATH]... | commit every change on the branch, or only the -file paths (repeat the flag; a rename needs both its paths). Prints the new commit |
conch branch push | push the branch, setting its upstream on origin (or the only remote) the first time; a remote that has moved on refuses it, and -rebase takes its commits, puts the branch's own on top and pushes |
conch branch pr [-title T] [-body B] [-draft] | push, then open a pull request into the base with gh, and print its URL. Without -title, gh fills the title and body from the commits |
conch branch merge [-no-squash] [-m MESSAGE] | merge the branch into the base where the base is checked out, squashed unless -no-squash. A merge that conflicts is undone and the command fails |
conch branch discard [-n] [-force] | remove the branch's worktree and delete the branch. It refuses when that would lose uncommitted files or unpushed commits, unless -force; -n only prints what would go |
conch branch commit -m "Add the health check" && conch branch pr -title "Health check"
conch branch merge && conch branch discard # land it and clean up
review
The changes view's comments from a shell: the same ones, kept by the server, so a comment written here shows on a's hunk marks and the phone's agent card, and the other way round. Like branch, every command takes -cwd DIR and -branch B, and without -branch uses the branch checked out in that directory.
| Command | Description |
|---|---|
conch review | list the comments waiting for the branch's agent, oldest first, each with its ID, where it is and who wrote it when an agent did. The unresolved comments on the branch's pull request follow, with the reviewer (alice on GitHub), their replies and their link |
conch review add FILE[:LINE] NOTE | comment on a file, or one line of it (a.go:12). Every word after the file is the note. Run from an agent's pane, the comment says which agent wrote it |
conch review rm ID | take a comment away. A pull request's comment is refused: answer or resolve it on GitHub |
conch review send [-agent A] | hand every comment to the agent working on the branch as one message, numbered, and clear them. The pull request's comments stay on GitHub but aren't sent again until somebody replies to them. Refused while that agent waits on a question. With no agent on the branch it is refused too, unless -agent names one to start in the branch's worktree with them |
conch review add api/login.py:42 "This swallows the timeout; let it raise."
conch review send
An agent kept to its own work may comment on and send for its own project's branches, and no others — which is what lets a reviewer you started leave its findings as comments instead of a file.
worktree
| Command | Description |
|---|---|
conch worktree ls | list the project's worktrees besides the main checkout, with why each looks finished and what removing it would lose |
conch worktree clean [-y] [-force] [PATH|BRANCH...] | remove the worktrees that look finished and lose nothing, or the ones named, deleting their branches (never the base). Without -y it only prints what it would remove; -force allows losing work |
Committing single hunks is a TUI-only step: see Finishing a task.
machine
| Command | Description |
|---|---|
conch machine add [-label NAME] [-yes] SSH_TARGET | add a remote machine, installing conch there; -label sets the name shown in the sidebar (default: the host), -yes installs without asking |
conch machine ls | list machines (also plain conch machine) |
conch machine rm ID | remove a machine |
conch machine rename ID LABEL | change the name a machine is shown by; its ID and ssh target stay |
conch machine upgrade ID | install this build on a machine and reload its server |
conch machine hosts | list the host aliases in ~/.ssh/config, for suggesting machines to add |
sandbox
| Command | Description |
|---|---|
conch sandbox stats [-provider P] | every provider's sandboxes in one table, and a line per provider: how many, in which states, what is running; no provider needed |
conch sandbox -provider daytona|boat|devin … | whose sandboxes the command means, in front of any subcommand below. Required for all of them — there is no default, and a sandbox named under another provider is refused |
conch sandbox -provider P create [-label L] [-snapshot S] [-cpu N] [-memory GiB] [-disk GiB] [-env NAME]... [-yes] | make a sandbox (key in $DAYTONA_API_KEY, $BOAT_API_KEY or $DEVIN_API_KEY; Devin Cloud also needs the devin CLI signed in), install conch there and add it as a machine; it runs until stopped. -env passes a variable from your environment; -yes deletes the sandbox without asking if setting it up fails |
conch sandbox -provider P add [-label L] ID | make a sandbox ls shows with no machine — one whose machine was removed, or on boat.dev one made in its own interface — one of conch's machines: started if stopped, conch installed, and added. Never deleted if that fails |
conch sandbox -provider P ls | conch's sandboxes, their state and size, including ones no longer added as machines (also plain conch sandbox -provider P) |
conch sandbox -provider P ssh [-t] ID [COMMAND...] | a shell in a running sandbox, or COMMAND run there (-t gives it a terminal); exits with its status |
conch sandbox -provider P start ID | start a stopped sandbox |
conch sandbox -provider P stop [-y] ID | stop it: its agents and terminals end, its files stay |
conch sandbox -provider P rm [-y] ID | delete it for good and remove the machine; lists work that isn't pushed first |
conch sandbox -provider P url [-expires 1h] [-open] ID PORT | a link to a port inside the sandbox |
conch sandbox -provider P usage [-since 720h] ID | what it has cost, period by period |
conch sandbox -provider P snapshot [-name N] ID | keep it, to make others from |
conch sandbox -provider P snapshots [-rm NAME] | list what is kept, or forget one |
ID is the machine's ID or label, the provider's own sandbox ID, or PROVIDER:ID; it must belong to the provider -provider names. See Sandboxes.
web
conch web [-listen ADDR] [-port N] [-url URL] [-cert FILE -key FILE] # the gateway a phone reaches
conch web pair [-permission view|reply|full] [-machine NAME] # a QR code and one-time code, good for 5
# minutes; it reaches this computer unless
# -machine names a machine
conch web devices # the paired phones
conch web revoke ID # cut one off at once
conch web permission ID view|reply|full [-machine NAME]... # change what one may do, and which
# machines it reaches (this computer only
# until you name one; 'local' clears them)
conch web stop # end one running in the background
conch web serves your phone on this machine's Tailscale address and nowhere else, unless -listen names another address. -url is the address phones open — the https://…ts.net one tailscale serve gives — which the QR code points at. pair draws the QR code only when it prints to a terminal. It takes no -m: it shows the agents of the machine it runs on. pair and revoke are refused from an agent's pane.
mcp
conch mcp # an MCP server on stdin and stdout
An agent that would rather call a tool than a command talks to conch through conch mcp: a Model Context Protocol server over stdio, in front of the same socket the CLI uses. A tool call comes back as a typed result and a refusal it can act on, where shelling out hands it a screenful of text to parse.
| Tool | What it does |
|---|---|
list | the panes you may see, each with what its agent is doing and the subagents running inside it |
read | a pane's screen now (tail for its last lines — leave it out for an agent, whose last lines are its prompt box) |
start | an agent in a pane of its own, in a folder that exists |
prompt | an agent's next message; wait holds until the work it starts has ended |
wait | block until a pane's agent is done, idle, waiting or working |
task | a branch, a worktree and an agent on a prompt |
rename | name a pane, to address it by that instead of its id |
view | what the person is looking at: the tabs, what is in each, and which pane has the keyboard |
show | ask the terminal to put panes in front of them — one is revealed, several open side by side in a tab of their own |
view and show are the two that reach past the server to the screen. The server owns panes and the terminal owns the arrangement of them, so conch carries both ways: a TUI publishes what it is showing, and a show is passed back to it as a request. A request, not an order — the panes asked for are gathered side by side in one tab and nothing else is touched. They move rather than being copied, since a pane is shown in exactly one place, which is the same rule that governs ctrl+b ! and dragging a pane between tabs. An agent may only show panes it could already type into, by the same scope that governs prompt.
The tools are the same work as conch agent prompt, conch wait, conch task and the rest — the same server methods with the same payloads — so the two doors cannot drift. Scope comes for free: conch finds the caller from the socket's peer pid walked up to a pane's program, so an MCP server an agent starts inside its own pane reaches only what that pane may reach, and nothing in a tool call can widen it.
Installing it is one action, because the entry is the same for every agent — the library writes it in each one's own format:
conch agent library mcp # conch's own tools, as a server in the library
conch agent library apply # write it into each agent's configuration
Or in the TUI: , → Agents → Shared MCP servers & skills… → Add conch's own tools…, then Apply…. It is conch mcp on stdio with nothing in its environment — it finds its socket the way every other command does — and the command is the bare name, so an update that moves the binary doesn't strand it. Adding it twice is adding it once. Restart an agent afterwards for its client to list the tools.
Three reviewers at once is what this is for: several helpers, several kinds of agent, no shell.
Stdin and stdout are the protocol: notes go to stderr, one request per line (this revision of MCP has no batches), answered one at a time in order, and a wait tool holds the session until it ends, as conch wait holds a shell. A tool that names a pane refuses a name shaped like a pane id or one another running pane holds, as conch rename does — ids win, so such a name would pick out nothing. timeout_seconds defaults to 1800, 0 waits with no limit, and anything over a day is capped.
doctor
conch doctor # check what conch needs, and say how to fix what is wrong
conch doctor -json # the same checks, for a script
The first thing to run when something does not work. Each line is one thing conch relies on, and anything wrong comes with the command that puts it right:
✓ conch 0.1.9 · darwin/arm64
✓ config /Users/you/.config/conch/config.toml
✓ socket /Users/you/.config/conch/conch.sock
! server pid 28356, up 6d, on another build (0.1.8) than this conch (0.1.9)
→ conch server reload -binary /Users/you/.local/bin/conch (panes and agents keep running)
✓ agents claude 2.1.3 · codex 0.46.0 (not installed: gemini, opencode, devin)
✓ git 2.49.0, committing as You
! gh 2.62.0 not signed in
→ gh auth login
✓ terminal ghostty, xterm-256color, 24-bit colour
✓ machines 1 machine saved (not dialled; conch -m NAME status reaches one)
conch works; 2 things worth a look.
| Check | ✗ (must be fixed) | ! (worth a look) |
|---|---|---|
| config | config.toml does not parse, so none of it is in force | an [[actions]] entry with no name, no command or an unknown place |
| socket | the socket path is longer than the system allows (103 bytes on macOS, 107 on Linux), so no server can listen | |
| server | the socket is there but nothing answers — stuck, or somebody else's (starting conch would clear it, and every pane) | not running; on another build than this conch (the fix reloads it onto this binary, or says to run the newer one when the server is ahead); missing features this conch uses |
| agents | the server finds none installed | not checked, because no server is running |
| git | not found | no name or email to commit as, in git's config or its environment variables; older than 2.38, which telling which branches would conflict needs |
| gh | not found, or not signed in — pull requests, CI results and issues come through it | |
| terminal | TERM is empty or dumb | inside tmux with the same prefix as tmux (asked of tmux itself), and a key free in both to use instead |
| machines | machines.json cannot be read; machines are saved but there is no ssh |
It exits 1 when anything is marked ✗, and 0 otherwise. The checks run side by side, so one slow thing costs only its own wait. It changes nothing and starts nothing — not even the server — and it does not dial your machines, so a machine that is asleep cannot make it hang. Whether gh is signed in is asked without reaching GitHub, so an offline laptop is not called signed out (a gh too old for that is asked the usual way), and the token gh hands back is thrown away. It checks this computer: on another machine, run it there.
bug
conch bug # the facts about this conch
conch bug -open "the tree lost a terminal" # …in a GitHub issue, already filled in
conch bug -log # where the server's log is
What to hand over when conch itself is the problem, without writing anything down:
conch 0.1.7-dev (build 29945acfb71a, darwin/arm64)
server: 0.1.7-dev (build 01096cd11ad4, darwin/arm64), pid 28356, up 6d
reloaded 5h06m ago
panes: 25 · claude×16
machines: 2, 1 reachable
terminal: iTerm.app, xterm-256color, 247×48, icons=nerd
last error: out_of_scope: the claude agent in p1 may not reload the server
It is facts, not contents: versions, counts, sizes, the capabilities a server is missing, and conch's own last error. Never a path, a project, a branch, a pane's title or anything off a screen — which is what makes it safe to send without reading it through first. The two builds above being different is the sort of thing it is for.
-open opens a GitHub issue with the block already in it; nothing is sent until you press submit there. Over ssh, or anywhere with no desktop, it prints the link instead. -log says where the server's log is and what is in it — paths, branch names and pane titles — and leaves attaching it to you.
Run conch doctor first: what it finds usually has a fix you can make yourself.
In the TUI the same thing is , → Report a problem…, which shows the report and offers to open the issue, copy it, or copy the log's path.
ask
conch ask [-y | -n] REQUEST asks the brain; it proposes actions and runs them once you confirm. -y runs the plan without asking; -n only shows it.
update
conch update [VERSION | latest | list | rollback] replaces this binary with a release and reloads the local server onto it, keeping panes.
| Command | What it does |
|---|---|
conch update | install the latest release, or say it is already running |
conch update VERSION | install that release; an older one moves conch back |
conch update list | list the releases published upstream, newest first, marking the running, latest and locally kept ones |
conch update rollback | go back to the version before the last update, from the copy it kept |
See Auto-update and Going back to an older version.
version
conch version [--json] prints the version, build and platform (also --version, -v).
Internal commands
These are run by conch itself, not by you:
| Command | Used by |
|---|---|
conch bridge | a remote client over ssh: connects stdio to this machine's server, starting it if needed |
conch report | agent hooks and plugins, to report state to the server |