Skip to content

Commands

github-actions[bot] edited this page Sep 8, 2026 · 23 revisions

Commands

Fifteen, and you need three of them. bothy opens the workspace, bothy doctor says what is wrong, bothy config set changes a setting. The rest are for a specific afternoon.

bothy --help prints the same list; this page says what each one actually does.

Opening the workspace

bothy

Opens the workspace in the current directory: file browser across the top, the agent and a shell below. First run fills any gaps first — it lists what is missing, asks before downloading, then opens.

flag
--dir <path> open somewhere other than the current directory
--profile <name> use a layout profile other than the configured one
--window always open a new Ghostty window
--in-place always run in the terminal you are already in

Closing the window does not strand the project. Inside a container the multiplexer client would otherwise outlive the terminal that opened it — podman exec ignores the hangup — and a session with a client on it is refused, which used to mean the project could not be opened again. bothy ends its client when the window closes. If one is left behind anyway, by a crash or a version older than this, the next launch ends it and says so:

bothy: reclaimed bothy-work from a closed window

A session someone is actually looking at is still refused; see [ADR-042] (https://github.com/bspeelm/bothy/blob/main/docs/decisions.md) for how it tells the two apart.

--window and --in-place override bothy's own judgement for one run. It normally decides by asking whether your terminal can draw images. To make the override permanent, bothy config set workspace.launch here (or window); the flags still win for a single run.

bothy attach [session]

Reattach to this project's session, which has gone on without you. With no argument it picks the session for the current directory.

bothy ls [--prune]

Which sessions are running, marking the one you are in — and which have stopped but are still kept:

  bothy-api                  the one you are in
  bothy-server_setup

2 stopped, kept so they can be resurrected:
  polite-galaxy
  bothy-notes
Clear them with 'bothy ls --prune'.

A stopped session is not junk: attaching brings its layout back as it was. But nothing removes them either, so they accumulate. --prune deletes the stopped ones and refuses anything still running.

bothy kill [session]

Ends a session without attaching to it. With no name, this directory's session.

$ bothy kill bothy-server_setup
ended bothy-server_setup

Nothing is left behind — the same end state as pressing Ctrl-q inside it. It refuses the session you are currently in, because that is what Ctrl-q is for, and refuses one that has already stopped, because that is what bothy ls --prune is for.

bothy box [ls|use|stop|create|rm]

Which toolbox this project opens in, and why:

$ bothy box
~/code/api
  box       dev
  because   this project is recorded for it

The reason matters as much as the name: four rules can decide it, and the one that answered is the one to change. bothy box ls shows every box on the machine and the sessions really in each, marking this project's:

* dev                      running   bothy-api
  docs                     exited
  legacy                   running   bothy-legacy
  rust                     exited

Sessions are read from the process table, not from bothy's record, so a session somewhere unexpected is listed where it actually is.

bothy box use <name> moves this project to another box, and bothy box use host moves it out of every box. The session has to end first — the multiplexer server runs inside the container, so there is no carrying a running one across — so it says what will end and asks:

$ bothy box use rust
bothy-api is running and has to end before this project can move to rust.
end it? [y/N]

--yes answers for you; without a terminal and without --yes it refuses, which is the opposite of every other prompt in bothy and deliberate: refusing a download costs a download, and refusing this costs a running session.

bothy box stop <name> stops a box nothing is using. It stops it — the container and everything installed in it are still there, and the next toolbox run starts it again. It refuses a box with a live session in it and names the session. This is a podman stop under a nicer name: toolbox has no stop of its own, and from inside a box you have no podman either.

bothy box create <name> hands the work to toolbox create and then does the two things toolbox cannot — record that this project belongs in the new box, and offer to install bothy's tools inside it, which is where the missing-tool trap starts. bothy box rm <name> is the other end of that: toolbox rm, and then every project that pointed at the box is told where it opens now.

Toolboxes has the rules, the first-run prompt, and what happens on a machine with no toolboxes.

bothy connect [edit] <host>

Opens the workspace against another machine. The file browser shows its files, the shell pane is a login session on it, and the agent can reach it the same way you can.

$ bothy connect <client>
directory on <client> [/]: /srv/api
ssh key, if that host needs one named [none]:
<client> mounted at ~/.local/share/bothy/cache/remotes/<client>

bothy puts nothing on the machine you connect to. It needs sshfs on your own machine and refuses with the install command if it is missing. --dir sets the directory without being asked; bothy connect edit <client> changes what was remembered.

Inside the workspace, on <command> runs something on that machine in the right directory — the agent needs it because the paths on the two machines differ. Connecting explains all of it.

bothy keys

The bindings worth knowing on a first day. They are Zellij's, not bothy's — bothy leaves them alone.

Finding out what is wrong

bothy doctor [--json]

Thirty checks against the workspace, each with a fix. This is the command the project is built around: The doctor explains the output, the severities and the capability grouping.

bothy tower [--mirror session] [--every duration]

One window showing every running agent, so several open sessions can be watched from one place.

$ bothy tower
watching 3 agent(s)

Each row mirrors one session's agent pane, refreshed every two seconds. Move between rows with Alt+h/j/k/l, the multiplexer's own pane navigation.

The tower reads panes and writes nothing to them. It sends no input to an agent, starts and stops nothing, and creates no session but its own — so an agent cannot be disturbed by being watched. It also attaches to nothing: a second terminal attached to a session would size that session to the smaller of the two windows.

A session is shown when it is running and has a live agent pane. A session whose agent has exited is skipped, because the pane outlives the agent and would show a frozen screen.

An agent walled off with bothy confine is watched like any other. Its pane runs podman rather than the agent, so it is found by the pane's name instead.

--mirror <session> watches one session and nothing else. --every sets the refresh interval.

The tower expands each agent pane before it opens. A mirror can only show what its pane displays, and a cockpit gives its agent about a quarter of the window — 57 columns by 23 rows, against 191 by 46 for the same pane filling its tab. So the tower makes each watched agent pane fullscreen in its own window, which is what makes a mirror worth reading.

It reads the state before changing it, so a pane you had already expanded is left alone, and it puts back only the panes it expanded — checking again on the way out, because you may have collapsed one yourself in the meantime. Fullscreen is Ctrl+P then f, and that keeps working normally while the tower runs.

--no-expand leaves your panes exactly as they are, at the cost of thin mirrors. --restore collapses expanded agent panes, for when a terminal was closed before the tower could put them back.

Mirrors sit side by side when the window is wide enough to hold them all at their own width, and stack when it is not; bothy tower says which it chose. Stacked, each shows the bottom of its pane — enough to see which agent wants you — and the multiplexer's fullscreen binding on a tower pane then shows the whole thing.

Answering from the tower

Type into a mirror and press Enter, and the line goes to the agent that mirror is watching, as if you had typed it in that agent's own window. Move between mirrors with Alt+h/j/k/l first, so the reply goes where you are looking.

bothy relays; it does not speak. Everything that reaches an agent came from your keyboard. bothy composes nothing, answers nothing on your behalf, and sends nothing on a timer.

The bottom two rows of a mirror are yours. Nothing the mirror draws reaches them, so a reply stays on screen while the agent above it keeps working — you can type at an agent mid-thought, which is when you most often want to.

This sends a line of text. It does not send arrows, tab, or Ctrl-C, so a question that has to be answered by moving a selection still needs its own window.

It cannot bring a session's window to the front. Selecting a row shows you which session wants attention; switching to it is yours to do. No Wayland compositor lets one application raise another's window, and bothy will not install a shell extension to get around that.

bothy tools

Which tools are in use, which version, where each came from — bothy's own copy or one already on your PATH — and, for the ones bothy fetched, where the pinned checksum came from:

✓ fd        a faster find        10.5.0    supplied by bothy  pin: download
✓ ripgrep   a faster grep        15.2.0    supplied by bothy  pin: upstream

pin: upstream means the checksum in bothy.lock matched one the project published, so the release cannot have been changed after publication. pin: download means the project publishes no checksum, so the pin is the hash of what bothy downloaded on the day it was pinned. Neither says the release itself is good; see Security.

bothy outdated [--json]

Which pinned tools have newer releases upstream. Reports; it does not upgrade. The pins live in bothy.lock.

bothy layout [--profile P]

Prints the Zellij layout bothy would launch, generated from the profile. For when you doubt what it is about to do.

bothy version

The version, and whether it is a release or a source build.

Changing things

bothy config [get|set|edit|path]

bothy config              # print the whole config
bothy config get <key>    # one value
bothy config set <key> <value>
bothy config edit         # open it in $EDITOR
bothy config path         # where the file is

config.toml carries schema = 1, which is bookkeeping rather than a setting — config set refuses it. Unrecognised keys warn rather than fail, and bothy doctor names a retired key's replacement.

bothy install [--dry-run]

Writes the configs from your settings, then runs the doctor against the result. Run it after changing a setting, or after replacing the binary. --dry-run shows what it would write.

Every generated file says it is bothy's and names where to put your own changes.

bothy theme example

Prints a blank eleven-token palette to fill in. Point bothy at the result with bothy config set theme.palette <path>.

bothy desktop-entry [--install]

Prints a .desktop launcher that opens the workspace in a directory. --install writes it; --remove deletes it. It lands outside bothy's tree by necessity, so bothy uninstall names it rather than removing it.

The rest

bothy completion <bash|zsh> [--install] [--remove]

Prints the completion script for a shell. With --install, writes it where that shell looks for it.

$ bothy completion bash --install
wrote ~/.local/share/bash-completion/completions/bothy
this is outside bothy's tree -- 'bothy uninstall' will not remove it,
but 'bothy completion bash --remove' will.

You need this only if bothy came from the install script, Homebrew or go install. dnf, apt, pacman and the AUR place these files themselves.

The file goes outside bothy's directory because the shell has to find it there, which is the same exception the desktop entry makes. bothy uninstall names it on the way out rather than removing it.

zsh has no per-user directory it reads by default, so --install prints the one fpath line to add to your ~/.zshrc. bash needs nothing.

bothy confine

Runs the agent pane in a rootless podman container, with the project directory and the agent's credentials mounted and nothing else from $HOME. Opt-in; there is no setting that turns it on. See Walling off the agent — including what it deliberately does not stop.

bothy upgrade

Works out how this copy was installed and prints the right command for it — brew, dnf, apt, go install, the script, or a source build. It prints; it does not upgrade.

bothy uninstall [--dry-run]

Removes bothy's tree and the binary, and names the three things it leaves: your settings, the container image if you confined the agent, and the desktop entry if you added one. --dry-run shows what would go.

Clone this wiki locally