Introducing uBixShepherd — One Voice for a Swarm of AI Agents
I had become the message bus
Most days I have several AI coding sessions running at once: a few on uBixCore, one on a product built on it, one on the docs site, one on the deployment repo. They’re good at the work. What they’re bad at is each other.
So I built them a protocol: a shared coordination file in the repo. Every session registers a lane, claims the paths it will touch, and logs what it did. It works. It also outgrew itself fast. On uBixCore alone it reached 20 lanes, 307 log entries, 32 git worktrees (some long dead) and two tag races in two days, where two sessions each took the same next version.
And every message between those sessions went through me. “That MR merged.” “Is the pipeline green yet?” A log pasted from one window into another. The agents idled until I typed. The protocol was right; the medium had run out.
Enter uBixShepherd
uBixShepherd is one point of contact between me and a whole swarm of agents: Claude, Gemini, whatever comes next. I talk to Shepherd. Shepherd hands out the work, keeps the agents from stepping on each other, holds the decisions that are mine for me, and reports back in one thread.
The rule I’m building it on: the shepherd is not a sheep. The control plane is plain, deterministic code: state machines, schemas, git. The models do the work; Shepherd decides who works where and checks the result. It’s the same idea as uBixCore’s typed boundaries, applied to agents: you can’t make an LLM deterministic, but you can make everything around it strict.
Update: v0.3.0-beta.1 (2026-10-11)
The day I wrote the rest of this post, “not released yet” was true. It isn’t any more: the first beta is out on GitHub, and v0.3.0-beta.1 follows it. Here is what has been added since launch.
A web UI, served by the daemon. The chat page is the front desk’s thread with a composer, and decisions are answered inline. Beside it, a backlog rail lists what waits on me, most urgent first: needs you, broken, idle, working, to review. The screenshots on this page are from a stub with made-up data, but the pages are the real ones.

A timeline. The day’s work at once: a track per lane grouped by repo, a bar per run coloured by agent, a lantern on everything waiting on me, a tick for each merge, and the spend against the daily budget along the bottom. This is the page I open to see what the swarm did while I wasn’t looking.

A next-up list. Work that is planned but not being acted on now lives in an ordered list: approved, planned, deferred. My order is the priority. Approving, deferring and dropping are mine: the daemon refuses them from the front desk unless I started the turn. Opening a lane for an item links the two, and the item reads as done when its merge request merges.

Lane diff. shepherd lane diff reads what a lane holds against its base in one go: the commits, the committed and uncommitted changes, and each file marked inside or outside the lane’s scope. It is bounded and redacted before it is cut, and it’s open to me and the front desk but not to an agent’s own token.

Smaller things that landed alongside:
- OpenCode as an agent:
shepherd lane run --agent opencodefor small mechanical edits on a local model. Not for tests in a typed codebase. - The front desk is run by the daemon, and it rotates its own session when the context gets large, seeding the next one with a summary Shepherd builds from its own records.
- Usage stats and run diagnoses: tokens and context per run, and a one-line, deterministic reason (with suggested fixes) when a run ends badly.
What works today
It’s one Go binary for macOS, Linux and Windows: a daemon, a CLI, and an MCP server. You point it at a directory of repos, not a single repo, because real work crosses projects.
shepherd init ~/git # pick which repos Shepherd manages
cd ~/git/myrepo
shepherd lane open feat/login --scope 'src/auth/**'
A lane is one stream of work: its own branch, cut from a fresh fetch of the base, its own worktree, and a declared scope. The scope is a lease. Ask for a lane whose scope overlaps another lane’s and Shepherd refuses, naming who holds the paths. That’s before any work starts, not at rebase time.
Then it enforces the scope where every agent has to pass, whatever its instructions said: git. A pre-push hook asks Shepherd about each push from a lane, and a commit that strays outside the scope doesn’t leave the machine.
And because the daemon speaks MCP, a Claude Code session at the root of ~/git can drive all of it in plain words: “open a lane in uBixCore for the login fix, scoped to src/auth.” The first time I watched a session do that through Shepherd’s own tools, the coordination file started to look like history.
What’s next
Two of the three things I listed at launch have shipped, so the list is shorter and harder:
- Tag reservations are in:
shepherd tag reserveallocates versions against remote tags and live reservations, and the hook refuses an unreserved release tag. - Proofs from the forge are in for GitLab: a merge closes a lane using the forge’s merge commit as proof, and a failed pipeline’s logs go back to the lane’s agent.
- Still to build: workspace-wide leases (scopes are per repo today), typed cross-repo work orders so that a work order goes in and a merged, tagged MR comes out without me relaying,
verified-on:<env>proofs, and GitHub mirror proofs.
Where it stands
Beta, and it says so. The first release is on GitHub, macOS and Linux are the tested platforms, public interfaces may change between releases, and there has been no independent security review. It works for me on my own repos, and it’s still being built the way it’s meant to be used: by a swarm of agents, in lanes. A page on ubixsys.com with the rest of the uBix family comes with it.
