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 - the nix binary to use. By default bothy finds nix on PATH, or in the installer’s profile at /nix/var/nix/profiles/default/bin/nix.
  • BOTHY_GC_INTERVAL_SECS - how often the daemon runs nix 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 to 0 to turn collection off. bothy status --all shows when the last collection ran. Set this in the daemon’s environment.