Repository navigation
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.
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.
Reattach to this project's session, which has gone on without you. With no argument it picks the session for the current directory.
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.
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.
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.
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.
The bindings worth knowing on a first day. They are Zellij's, not bothy's — bothy leaves them alone.
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.
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.
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.
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.
Which pinned tools have newer releases upstream. Reports; it does not upgrade.
The pins live in bothy.lock.
Prints the Zellij layout bothy would launch, generated from the profile. For when you doubt what it is about to do.
The version, and whether it is a release or a source build.
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 isconfig.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.
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.
Prints a blank eleven-token palette to fill in. Point bothy at the result with
bothy config set theme.palette <path>.
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.
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.
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.
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.
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.