boatyard runs several Claude Code agents through one backlog. Each agent works in a terminal multiplexer pane of its own, called a berth. A steward agent drives an effort from its top bead, starts a worker agent for each piece of work that is ready, and keeps track of them until the work lands. The work and its state live in a beads tracker, so a seat that dies can be replaced without losing anything.
It also compacts an agent's context when the agent is at rest, before it runs low, so the next message lands on a lean session instead of one about to auto-compact mid-turn.
boatyard is one developer's daily setup, published as it is. It supports one multiplexer, herdr, and one agent, Claude Code. It has no other users yet, so expect rough edges.
berthis a small command for opening, naming, reading and closing terminal panes, for asking whether one is still open, and for asking whether the agent in one is busy, at rest or waiting on a person. The skills only ever talk to the multiplexer through it, and herdr is its first backend.sign-onlaunches Claude Code in a new berth and gets it past Claude Code's startup prompt.- The Claude Code plugin carries four skills and the compaction mod:
musterturns a body of work into an effort a steward can drive.stewarddrives one effort.workerdoes one bead's worth of work inside an effort.tallyreports every effort that is running and what each one needs from you.
docs/design.md is the full design.
- herdr, with the agents running inside it.
- Claude Code.
- A beads tracker for each project an effort touches, and the
bdclient. - commy, which carries the messages between the steward, its workers and you. It needs a Zulip realm.
- beady-eye, which wakes an agent when a bead it waits on changes, and whose
bdireads readiness across trackers. - GitHub and its
ghclient, for a repo that takes work through pull requests. A repo hosted anywhere else takes its work by a direct push. - Nix, if you install the packages from the flake. Without it, you need
bash,coreutils,gitandjqon the path.
The flake exports berth and sign-on:
nix profile install github:CodeForBreakfast/boatyard#berth github:CodeForBreakfast/boatyard#sign-onWithout Nix, put the scripts in bin/ on your path.
Install the packages even though the plugin carries the same scripts. A service manager does not see the plugin's bin/, so anything started outside Claude Code needs them on the path.
Load the plugin from a checkout of the same revision as the packages:
git clone https://github.com/CodeForBreakfast/boatyard ~/src/boatyard
claude --plugin-dir ~/src/boatyardIf your managed settings allow only your own organization's plugin mods, allow this one too, or the compaction mod does not load.
berth needs to know which multiplexer it drives:
export BERTH_BACKEND=herdrsign-on reads the Claude Code command and its startup settings from the environment. The header of bin/sign-on lists them. The command must include the --plugin-dir flag, so that every seat loads the plugin:
export SIGN_ON_CLAUDE="claude --plugin-dir $HOME/src/boatyard"With Nix, set the same things as package arguments instead:
boatyard.packages.${system}.sign-on.override {
claudeCommand = "claude --plugin-dir ${boatyard}";
}berth takes herdr as an argument in the same way, so a host can supply its own build.
Compaction is off unless a session opts in. sign-on opts in every seat it launches. To opt in every session, turn on the plugin's compactAtRest setting.
sign-on launches a seat only in a folder that Claude Code already trusts. Before a seat's first launch in a new folder, open that folder in Claude Code yourself and answer its trust dialog. sign-on never grants that trust, because a folder's hooks, MCP servers and permissions may come from someone else.
Each seat needs permission to run berth and sign-on.
bd leases every claim for 5 minutes. A claim whose lease lapses looks like a dead seat, and bd reclaim hands its bead back. boatyard ships no renewer, so the host runs one for every seat that is running, including a seat that is asleep.
bd heartbeat renews one claim, and only as the actor that holds it. This loop renews every claim in a tracker once a minute. Run it from the project's checkout, under a service manager or in a spare pane:
while true; do
bd list --status in_progress --json | jq -r '.[] | "\(.id) \(.assignee)"' |
while read -r id actor; do bd heartbeat --actor "$actor" "$id"; done
sleep 60
doneEach project has its own tracker, so run one loop per project. Leases are kept on the machine that granted them, so run the loop there.
commy runs on a Zulip realm, which you host or rent, and boatyard cannot run without one. commy's own README lists what it needs from the realm: a user that may create bots, and that user's API key. Set commy up before you start a seat.
From inside herdr, open a Claude Code seat in a workspace of its own:
sign-on --as independent --cwd ~/src/example-app --label "example-app" --focusTo start an effort, type /boatyard:muster and describe the work. Once the work is ready to drive, the seat becomes the effort's steward.
nix develop gives you the toolchain, and nix flake check runs every test. CLAUDE.md has the conventions for a change.
Apache 2.0. See LICENSE.