Commands
Every bothy command, with the ones you run most at the top.
Day to day
bothy status # every worktree, live: browse services and logs, q quits
bothy status web # the same, opened on this service
bothy status --print # this worktree, printed one time (a pipe does the same)
bothy status --all --print # every worktree, printed one time
bothy logs -f web # print a service log, and follow it
bothy logs web -n 50 # print its last 50 lines
bothy explain # what this worktree declares, runs and sets
bothy up # start anything declared that does not run, then follow its logs
bothy up web # only this service and what it depends on
bothy up web -d # start it, return at once, and leave it running
bothy down web # stop one service
bothy down # stop this worktree's services
bothy restart web # stop one service and start it again
bothy restart # restart this worktree's services
Setup and teardown
bothy init # write bothy.yaml, add .env and .bothy/ to .gitignore, add the agent hooks
bothy install # set the machine up: Nix if missing, then the shell hook
bothy install nix # only Nix (add --yes in CI)
bothy install hook # only the hook line (--shell zsh when $SHELL is not your shell)
bothy uninstall # stop every service, remove the hook line, then Nix itself
bothy uninstall hook # only remove the hook line, and keep Nix
bothy uninstall nix # only remove Nix (--yes without a terminal)
bothy clean # reap what bothy lost track of (--dry-run to look first)
bothy tools # list this worktree's tools
bothy tools add nodejs_24 # add one, or path:<dir> for a local binary
bothy tools remove nodejs_24 # remove one
For scripts and agents
bothy status --json # the state of the machine, as data
bothy explain --json # this worktree's environment, as data
bothy schema # the JSON Schema for bothy.yaml
bothy exec -- pytest # start the services, then run one command with the environment
bothy exec --with ingest -- pytest # also start a service that entry leaves down
bothy status
On a terminal, bothy status is a live view of every worktree, updated every second.
Press j and k to move, enter to open the services of a worktree and then the log
of a service, esc to go back, / to filter, i to show idle worktrees, and q to
quit.
With --print, or through a pipe, it prints the report of this worktree one time and
exits. Scripts and agents read bothy status --json.
bothy explain
bothy explain prints what this worktree declares, runs and sets, with the reason for
each name. It starts nothing, not even the daemon. Parsing is the check, so unknown
fields, bad versions, dependency cycles and illegal service names all fail here in
milliseconds. If the services run, the output shows their real ports. If not, the
commands show {port} in place of each port.
$ bothy explain
~/src/app (ece24ab3)
PATH additions (first wins over anything already on PATH):
/nix/store/5918k9hx7biik7js08n5jxhjggavk3xn-ripgrep-15.1.0/bin
/nix/store/57hsx9iid0cb7hhs2rj5z21xkzz62v16-postgresql-16.15/bin
services, in start order:
pg (postgres, port 28015, running)
starts: on entry
runs: postgres -D ~/.local/state/bothy/w/ece24ab3/pg -p 28015 -h 127.0.0.1 -k ~/.local/state/bothy/w/ece24ab3/pg
ready when: pg_isready -h 127.0.0.1 -p 28015
then: createuser -h 127.0.0.1 -p 28015 -U bothy --superuser bothy (unless psql -X -h 127.0.0.1 -p 28015 -U bothy -d template1 -tAc 'select 1 from pg_roles where rolname = 'bothy'' prints 1)
createdb -h 127.0.0.1 -p 28015 -U bothy --owner bothy postgres (unless psql -X -h 127.0.0.1 -p 28015 -U bothy -d template1 -tAc 'select 1 from pg_database where datname = 'postgres'' prints 1)
data dir: ~/.local/state/bothy/w/ece24ab3/pg
stops with: SIGINT to the process group, then SIGKILL after 30s
tools, put on PATH and not supervised:
ripgrep
environment -- your shell and every service:
BOTHY_PG_DATA_DIR = ~/.local/state/bothy/w/ece24ab3/pg
^ pg: every service gets a per-worktree data dir
BOTHY_PG_PORT = 28015
^ pg: the port bothy allocated
DATABASE_URL = postgres://bothy@127.0.0.1:28015/postgres
^ pg: `url_env:`
BOTHY_PG_URL = postgres://bothy@127.0.0.1:28015/postgres
^ pg: a postgres service knows its own URL
also exported by the shell hook: PATH, BOTHY_ROOT, BOTHY_SESSION_ID, BOTHY_VARS, BOTHY_ENV_SOURCE, BOTHY_PENDING
bothy explain --resolve also resolves every package that the file names. This needs
Nix and is slower. It fails on a package that does not resolve.
bothy up and down
bothy up with no name starts every declared service that does not run, manual
services included. A named service starts with its dependencies. bothy down web stops
only what you named, so a service that depends on web keeps running.
bothy up follows the logs of the services you named. Press Ctrl-C to stop those
services, the same as bothy down on the same names. A dependency that started only
because a named service needed it keeps running. Pass -d to skip the logs and leave
the services running.
A bothy up does not hold a worktree open. Only a shell in the worktree does that.
bothy restart
bothy restart web stops web and starts it again with the current bothy.yaml. If
you edit the file or a service is stuck, use it. The services that depend on
web keep running. If web was not running, the command starts it and tells you.
With no name, bothy restart restarts the services that run. It also starts the
services that entry starts. It does not start an autostart: false service that was
down. A restart does not follow logs.
bothy exec
bothy exec is entry without a shell. It starts what entry starts, runs your command
with the environment, and holds the worktree open until that command exits. Its exit
code is the exit code of the command. It is the command to use in CI. See
CI.
--with <service> also starts a service that has autostart: false. Name the flag
once per service. A name that bothy.yaml does not declare is refused before the
command runs.
bothy schema
bothy schema prints a JSON Schema made from bothy’s own types. Point an editor at it,
or give it to an agent that must write a bothy.yaml:
bothy schema > bothy.schema.json
# then, at the top of bothy.yaml:
# yaml-language-server: $schema=./bothy.schema.json
Variables that bothy reads
BOTHY_NIX_BIN- thenixbinary to use. By default bothy findsnixonPATH, or in the installer’s profile at/nix/var/nix/profiles/default/bin/nix.BOTHY_GC_INTERVAL_SECS- how often the daemon runsnix store gc. The default is once a day. Every package a worktree uses keeps a GC root, so collection removes only what nothing uses. Set it to0to turn collection off.bothy status --allshows when the last collection ran. Set this in the daemon’s environment.