Shepherd: one conversation, many agents
Running one agent is easy. You talk to it, it does the work, you review it.
Running ten is different. Each one needs its own branch and worktree so they don't trip over each other. Each one needs a brief. Each one gets stuck in its own way. One hits a failing check to fix. One needs me to run a command it isn't allowed to run. One finishes and sits there idle. Another finishes and needs cleaned up.
I was the scheduler, the pager, and the memory for all of them. That's the part a computer should do.
I run my agents in Herdr, a terminal that knows which panes are agents and what each one is doing, and track work in beads, an issue tracker that many agents can update at once. On top of those I tried the obvious options. Minding sessions by hand stopped scaling around a dozen. A dashboard showed me the state of every agent, but seeing isn't coordinating. A full orchestrator was a whole world to buy into. The closest was herdr-projects: one coordinator, a worker per task, a sidebar of what needs you. But it kept its own state in Markdown files, and for state that many agents read and write at once, beads is the better tool. A few other rough edges and I knew I'd only be happy with a setup I wrote myself.
So I wrote shepherd. It keeps herdr-projects' shape, puts all the state in beads, and runs as much in parallel as I'll let it.
What shepherd is
Shepherd is a Herdr plugin. It does four things.
One place to coordinate from. I talk to one agent, the coordinator. I tell it what I want. It turns that into beads, proposes how to split the work, and waits for me to say go. It never does the work itself, so it's always free to answer me.
One bead, one branch, one worktree, one agent. When I say go, shepherd claims the bead, creates a worktree on its own branch, starts Claude or Codex in it named after the bead, and sends it a short brief. Starting a thread is one key. Cleaning up after a merge is one command.
Workers get checked on automatically. A background ticker follows every thread. When a PR's checks fail, it tells the worker. When review comments land, it tells the worker. When the PR merges, it tells the worker to verify and close the bead. It follows deploy workflows linked in the bead too. It only types into an agent that's been idle for a minute, so it never lands in the middle of something I'm typing.
Beads is the only state. Shepherd keeps no task list of its own. Statuses, notes, questions and lessons live in beads. That's what makes running many agents at once work: they all read and write the same record. It's also why nothing is lost when an agent or the whole terminal restarts. The next session picks up exactly where things are.
The sidebar puts the coordinator on top with a summary of what's waiting, then every thread sorted so what needs me comes first. Each worker is named after its bead, so every row says which task it is and where it stands:
shepherd coordinator · 2 need you · 1 review · 3 working · 2 inbox app-7qd needs you · run command app-k2m checks failing · PR #405 (integration-tests) app-9xr-2 review · PR #411 approved · ENG-1024 app-3fw rolling out · PR #398 · deploy running app-p1c working app-c8n-1 idle
The pieces never talk to each other directly. A worker says everything through its bead: notes, a PR link, a question, a command it needs me to run. The ticker reads beads, Herdr and GitHub, and writes what changed to an inbox, which is just a folder of files. The coordinator reads the inbox when it's nudged, or when I ask. The state lives in beads and those files. A prompt only says "go look", so if one gets missed, nothing is lost.
A day with it
Here's what a day looks like. The details are made up. The shape is real.
Morning. I open the coordinator and ask where things stand. It reads the state and gives me three lines. One worker is asking whether to roll out to one region first or all at once. Overnight, one PR's integration tests failed, and the ticker already sent that worker the failure, so it's fixing it. Another PR merged, and its worker verified it and closed its bead.
I answer the one question. The coordinator passes it on. I haven't opened a single pane.
New work. I paste in my notes from yesterday's incident: a resolver got saturated, requests timed out, and our alerts said nothing because they watched errors, not demand. I want an alert on demand, a config fix, and a write-up for the postmortem.
The coordinator makes three beads, notices the write-up should cite the alert's threshold, adds a dependency, and proposes starting two now. I say go. Two workspaces open, each on its own branch.
Midday. The alert PR fails lint. I don't touch it. The ticker sees the failure, waits for the worker to go idle, and sends it the failing check. It fixes it and pushes. On the other PR, a teammate asks for the timeout to be configurable. The ticker hands the review to that worker, which makes the change and replies. I can see and follow all of this looking at the sidebar.
A command only I can run. One worker needs a production change its permissions won't allow. It writes the exact command on the bead and marks it as needing me. The sidebar goes red: needs you · run command. I copy the command from the board, run it, and the worker sees what happened and continues.
Afternoon. The alert merges. The worker checks that the rule actually loaded, then closes its bead. That unblocks the write-up, which the coordinator mentions in its next status.
A restart. Herdr restarts, and it doesn't relaunch agents. The coordinator lists two threads as resumable. shepherd resume starts each worker again in its worktree, continuing its last conversation.
End of day. shepherd report writes my daily update: what shipped and how it was verified, what's in flight, what needs me. I ask the coordinator what's left, and I mark two beads for tomorrow. One lesson from the day goes into beads' memory, so every agent that starts tomorrow sees it.
Nothing about the day lived in my head. Tomorrow starts the same way: open the coordinator, ask where things stand.
How I built it
I built the first version in a day with Claude. It's a single Go binary. Herdr has a CLI and a socket API for panes, agents, worktrees and sidebar metadata, so shepherd is mostly glue between Herdr, beads and gh.
The second round was more interesting. I asked Claude how shepherd could fit the way I actually work. It looked at my beads, my running agents and what had come up that day, and came back with a list: resume agents after a restart, surface commands that only I can run, keep following work after merge, support several repos, keep Linear in step, write my daily report, clean up old worktrees.
Then it built all seven at once. Seven agents, each on its own branch in its own worktree, which is exactly what shepherd is for. It merged them one at a time and ran the tests after each. Then an independent reviewer went over the combined change, and it caught two real bugs: cleanup could have deleted the worktree of a rollout that was still in progress, and an old command could have been offered to me to run again. Fixed and shipped.
That's the workflow in miniature. The agents did the work in parallel. The review caught what parallel work misses. I made the calls.
The sharp edges
- The coordinator proposes; it doesn't decide. It waits for me before starting threads. Agents are good at doing work and worse at knowing which work matters.
- Automated prompts need manners. The ticker only types into an agent that has sat idle for a minute. On the Herdr version I run, a prompt merges into whatever you've half-typed, and nothing annoys you faster than an agent that interrupts you.
- Cleanup is where you lose work. Removing a worktree is irreversible. Shepherd keeps anything dirty, anything with unpushed commits, anything with an agent in it, and anything whose bead is still active. The dry run is the default.
- Names are the contract. Shepherd ties a worker to its bead by its name. It names each worker itself when it starts it, and if a name drifts, the ticker finds the one agent in that bead's worktree and renames it back.
- Folder trust is per path. Claude asks whether to trust every new folder. Worktrees of a repo you've already trusted seem to be fine. For anything else, shepherd holds the brief until you answer.
- It's built for how I work. One tracker, one terminal, Claude and Codex, GitHub. If your setup is different, the ideas probably carry over better than the code.
Why build it
What I needed was small. Start an agent in the right place. Check on it. Tell me when it needs me. Clean up after it. Keep the state where it already lives.
AI didn't make managing agents unnecessary. It made the agents good enough that managing them became the bottleneck. Shepherd moves that job off me and onto a loop that doesn't forget, so the time I have goes to the decisions.
Shepherd is on GitHub at travisjeffery/herdr-shepherd. Installing takes two commands, with nothing to build:
herdr plugin install travisjeffery/herdr-shepherd --ref v0.2.0
herdr plugin action invoke configure --plugin shepherd # from a workspace in your repo