A Night on the Farm
A Night on the Farm
Section titled “A Night on the Farm”The night shift, once. In Coming Back to a Project you looked for what the farm did while you were away. In Watching BoB Work you watched a run on your own machine. This tutorial puts the two together: you hand
hello-linksto the farm for one night, watch its tick start from your laptop, and read what it did in the morning. Every command below comes from The Farm, which also explains why the farm works the way it does.
What you will do
Section titled “What you will do”| Stop | When | You will |
|---|---|---|
| 1 | Evening | See what the farm is and whether it is alive |
| 2 | Evening | Delegate one requirement to the farm |
| 3 | Evening | Reach the farm and give it the project |
| 4 | Bedtime | Start one tick, dry run first |
| 5 | Bedtime | Watch the tick from your laptop |
| 6 | Morning | Read what the farm did |
| 7 | Morning | Read the limits the farm never crosses |
Then a “When it breaks” section for the nights that do not go to plan.
Allow half an hour in the evening and a quarter of an hour in the morning. The farm works in between.
Before you start
Section titled “Before you start”- Finish Coming Back to a Project first. This tutorial reuses
its
hello-linksproject, pushed to GitHub. Watching BoB Work taught the views you use to watch the tick. - A farm. A fleet machine with the role
farm-workerin your operator repo’smachines.json, on your tailnet. The examples call itfarm-01. - One small approved requirement in
hello-links, notserial-only, for example “The links page shows how many links there are”. File it with/requirementand approve it. - Replace the placeholders.
<N>is that requirement’s number,<owner>is the GitHub owner ofhello-links, and<project>ishello-links.
Stop 1. What the farm is
Section titled “Stop 1. What the farm is”From your laptop:
node ~/.claude/scripts/fleet/machine.js get farm-01bob status --scope fleet --no-liveWhat you should see.
scripts/fleet/machine.js get farm-01prints the farm’s entry as JSON:"role": "farm-worker", itstailscale_name, and abob_workloadblock with the tick’sschedule(for exampledaily 02:30 America/Los_Angeles) anddry_run.bob status --scope fleet --no-liveprints the fleet table. The farm’s row hasSTATUScachedand anAGEunder a day.
What just happened. The farm is a machine like your laptop, with its own BoB and its own GitHub login. What makes it the farm is its declared workload: a timer that runs one tick a night, under a lock so that two ticks never overlap. The tick grooms, plans, runs one warp-drive session and writes down what it did. The Farm explains each piece.
Checkpoint. The farm’s row says
cached, notcached(stale)ornever. A stale farm is off or has stopped publishing; fix that before you hand it work.
Stop 2. Delegate one requirement
Section titled “Stop 2. Delegate one requirement”From the hello-links directory on your laptop:
gh issue edit <N> --add-label farmnode ~/.claude/scripts/warp-drive/eligibility.js check <N>bob operator showbob plan build --from farmWhat you should see.
gh issue editprints the issue’s URL.scripts/warp-drive/eligibility.js check <N>prints the issue as eligible and exits 0. If it prints excluded, the reason names the fix: approve it, removeserial-only, or add the missing label.bob operator showprints your operator profile and the repo it came from. Openprovisions/hello-links.jsonthere:_meta.activeis absent ortrue.bob plan build --from farmprints the plan issue’s number. The plan, titledFlight plan: farm (unattended), lists your requirement. Any other approved issue is printed as[dropped]with the reason, such asno farm label.
What just happened. You delegated the work explicitly. The farm takes an issue
only when one rule says yes, and the farm label is how you say yes for one issue.
Nothing that needs you, such as a serial-only item or a blocked one, can reach
the farm. The plan you built is a preview: the tick rebuilds it when it starts.
Checkpoint. The farm plan lists your requirement, and nothing you did not label.
Stop 3. Reach the farm
Section titled “Stop 3. Reach the farm”From your laptop, then on the farm:
tailscale ping --c 1 --timeout 3s farm-01node ~/.claude/scripts/fleet/audit.js pull farm-01node ~/.claude/scripts/fleet/audit.js pull farm-01 --cmd 'gh auth status'ssh farm-01bob ready <owner>/<project>What you should see.
tailscale pingprintspong from farm-01with the address and whether the path is direct or through a relay (via DERP). Both work.scripts/fleet/audit.js pull farm-01prints the farm’s snapshot as JSON and caches it.gh auth statuson the farm printsLogged in to github.comwith the farm’s account.ssh farm-01opens a shell on the farm. There,bob ready <owner>/hello-linksprints arepostepcloned, then its other steps, and endsready.
What just happened. Every command went over the tailnet, and none of them moved
a secret. The farm has its own GitHub login; you checked that it is there, and if
it were not, you would log in on the farm itself. BoB never copies a token from
one machine to another. bob ready cloned hello-links next to the farm’s other
projects and linked its BoB tooling, exactly as it does on a laptop.
Checkpoint. On the farm,
ls ~/projects/hello-linkslists the project, andbob readyendedready.
Stop 4. Start one tick
Section titled “Stop 4. Start one tick”Still on the farm, at bedtime:
ls ~/.claude/.bob-tick.pausebob tick --dry-run --cwd ~/projects/<project>tmux new-session -d -s <project>-night 'bob tick --cwd ~/projects/<project>'What you should see.
ls ~/.claude/.bob-tick.pauseprintsNo such file or directory. If the file exists, the farm is paused: every tick exits 3 and does nothing. Read why withcatbefore youbob tick --resume, because the pause covers the scheduled tick too.bob tick --dry-run --cwd ~/projects/hello-linksprints each step and ends with a digest whose Taken row readswould take 1:and your requirement.- The
tmux new-sessionline returns at once. Leave the SSH session withexit.
What just happened. The dry run walked the whole tick read-only. The real tick
now runs in the hello-links-night tmux session on the farm: it takes the lock,
grooms, rebuilds the farm plan and starts a Level 3 warp-drive run on it, then
waits for that run. The run merges through a pull request that must pass CI, never
by pushing to main.
Checkpoint. The dry run’s Taken row names your requirement, and nothing else.
Stop 5. Watch the tick from your laptop
Section titled “Stop 5. Watch the tick from your laptop”Back on your laptop, before you go to bed:
node ~/.claude/scripts/fleet/audit.js pull farm-01 --cmd 'tmux ls'node ~/.claude/scripts/fleet/audit.js pull farm-01 --cmd 'node ~/.claude/scripts/warp-drive/state-machine.js status ~/projects/<project>'bob vizWhat you should see.
tmux lson the farm listshello-links-nightand the warp-drive session the tick started.- The run’s state on the farm, as JSON: a
phasesuch ascoding, andrequirementwith your requirement’s number. bob vizshows the farm’s tiles. They are as old as the farm’s last snapshot, sohello-linksmay not show the run until the tick publishes its own.
What just happened. You watched the farm without logging in to it. Each
--cmd is one short command over SSH with a 30-second limit, which is why the
tick itself runs in tmux on the farm and not over your connection.
Checkpoint. The run’s state on the farm names your requirement.
Stop 6. The morning read
Section titled “Stop 6. The morning read”The next morning, from your laptop, in the hello-links directory:
node ~/.claude/scripts/fleet/audit.js pull farm-01 --cmd 'cat "$(ls -t ~/.claude/fleet/ticks/*.md | head -1)"'gh issue list --label flight-plan --state all --search "farm (unattended) in:title"gh issue list --label session-report --state all --limit 3gh pr list --state merged --limit 5node ~/.claude/scripts/fleet/audit.js pull farm-01bob status --scope fleet --no-livegit -C ~/projects/bigbrain tag --list 'nightly-*' --sort=-creatordateWhat you should see.
- The digest from the farm:
## bob tick — <date> on farm-01, a Verdict, and a table with Taken, Merged, Blocked (todos filed), Tokens and Budget rows. - The farm plan issue, with the digest as its newest comment and your requirement ticked.
- The session summary the run filed, and its chunk reports.
- The merged pull request, with
fixes #<N>in its body and its checks green. - After the pull, the farm’s fleet row with an
AGEof a few hours. - The nightly tags of BoB itself.
hello-linksnever cuts one; the list only moves on the nights the farm maintains BoB.
What just happened. The farm left one record in each place you already know:
the digest on the farm and on the plan, the run’s reports in the tracker, the pull
request in the history and a fresh snapshot in the fleet view. Nothing it did is
known only to the farm. Run /status in Claude Code in hello-links: its catch-up
lists the farm’s merged work next to yours, and its next-work list no longer
includes the requirement.
Checkpoint. The digest’s Merged row names your requirement, the requirement is closed, and
/statusnames the farm’s work.
Stop 7. What the farm never does
Section titled “Stop 7. What the farm never does”Still in the morning, from hello-links:
jq -r '.permissions.deny[]' ~/.claude/profiles/autonomous.jsonnode ~/.claude/scripts/promotion/promotion.js decide --unattended --jsonnode ~/.claude/scripts/fleet/deploy-pending.js statusWhat you should see.
- The deny list of the
autonomousprofile, among themBash(git push --force*),Bash(git reset --hard*),Bash(git branch -D *)andBash(rm -rf *). - One JSON line from
scripts/promotion/promotion.js decide --unattended:"merge":"pr","merge_via":"merge-on-green", and adeployno higher than your project’s ceiling ("none"for a ceiling ofexternalorpr). deploy-pending: nothing queuedwith exit 0, or the deploy that is waiting and since when.
What just happened. You read the three floors under every farm run, each where it is declared. The run cannot force-delete anything, because its permission profile refuses it. It cannot deploy past the promotion ceiling, because the shared deploy entrypoint and a hook both check it. It cannot redeploy BoB under a live Claude Code session, because that would silence the session’s hooks: the deploy is queued instead, and runs itself when the last session ends or at the next tick. None of these is a setting the night can change.
Checkpoint.
scripts/promotion/promotion.js decide --unattendedsays"merge":"pr".
When it breaks
Section titled “When it breaks”A night that did not go to plan says why, in the digest’s Verdict and in the tracker. From your laptop:
node ~/.claude/scripts/fleet/audit.js pull farm-01 --cmd 'tmux ls'gh issue list --label todo --state opennode ~/.claude/scripts/fleet/audit.js pull farm-01 --cmd 'bob doctor'node ~/.claude/scripts/fleet/audit.js pull farm-01 --cmd 'bob forge queue status'node ~/.claude/scripts/fleet/audit.js pull farm-01 --cmd 'systemctl --user list-timers bob-tick.timer'| What you see in the morning | Why | What to do |
|---|---|---|
Verdict exit 3 and another tick holds …/.bob-tick.lock |
Another tick was running, often the timer’s own. | tmux ls on the farm names it. Wait until it ends, then start yours again. Never delete the lock file. |
The run ended blocked and a new todo is open |
The farm’s preflight failed: its BoB is unusable, or hello-links is not ready on the farm. |
Read the todo; bob doctor on the farm names a host fix. Do it and add the completed label. The next tick retries. |
| Merged is empty and writes are waiting | GitHub was down or rate-limited overnight. The run queued its writes and parked before merging. | bob forge queue status on the farm lists them. The next tick replays them; nothing is lost. |
The farm’s fleet row is cached(stale), or every pull fails |
The farm is off, off the tailnet, or its timer stopped. | tailscale ping farm-01 first. If it answers, the timer list shows whether the next tick is scheduled. |
The explanation page has the same table with more on each cause: When a night goes wrong.
Where you are now
Section titled “Where you are now”You handed one project to the farm for one night. You delegated one requirement with a label, reached the farm over the tailnet without moving a secret, started a tick and watched it from your laptop, read four records of the night in the morning, and read the three limits no night can cross. When a night goes wrong, the digest’s verdict and the table above tell you which of four things happened.
Where to go next
Section titled “Where to go next”- The Farm: why the farm takes only what you delegate, and how each record is made.
- Farm Tick (the night shift): every step of a tick, the timer, the budgets and the pause.
- tailscale-remote-ops: the rules for reaching any fleet machine.
Next tutorial: Getting Started — Stand up a project and run the autonomous loop, start to finish.