Shadowbranch / blackboard multi-agent protocol
Five sub-agents, one repo, isolated wt worktrees coordinating over a git-notes blackboard instead of a shared checkout — does the protocol actually prevent the coordination failures it was built for?
Dogfooded 2026-08-23/24 on esoteria-remaster Phase 2: a 5-track parallel fan-out (Asset Pipeline, Engine & Physics, Gameplay, AI & Pathfinding, Visual Regression), one sub-agent per track, each in its own wt-created worktree off main, coordinating via the repo's AGENTS.md protocol (scripts/blackboard.sh, refs/shadow/board).
Goals
Let concurrent sub-agents work the same repo without stepping on each other's files, and let them hand off contracts (an API shape, a "ready to start" signal) through a shared blackboard instead of ad hoc messages — without needing a human to referee every merge.
Effectiveness
Mixed. The isolation half held: no file collisions this run, in contrast to the Comox Tide Planner incident that got this protocol mandated in the first place (five agents editing App.jsx directly in a shared checkout). The gating half also worked as designed — Track E (visual regression) correctly scaffolded a playwright.config.ts with test.fixme() placeholders and posted "queued, waiting" rather than building against a test-mode API that didn't exist yet.
But the fan-out itself silently failed to actually execute. The dispatch landed cleanly, briefs were sent, and the blackboard sat quiet — which read as "nothing to report" rather than "nothing happened." A live check (subagents list, git log on each of the five branches, wt list) found zero track sub-agents actually running and nothing meaningfully committed: two tracks were a bare pnpm add diff, one was byte-identical to main, and the furthest-along track had ~70 uncommitted lines nobody had pushed or posted. The protocol coordinates agents that are alive; it has no signal for "the agents never actually started."
What made it effective
The parts that worked, worked because the contracts were explicit up front: Track E was told exactly what to wait for and what to do in the meantime, so its idle state was legible instead of ambiguous. The relaunch was also done right — before reporting success the second time, spawns were confirmed accepted and the model resolution was checked directly (no silent bounce to a fallback model, a known failure mode from unrelated dispatches), rather than taking a "launched" message at face value.
Bonus utility
Caught a real tool bug along the way: scripts/blackboard.sh post <path> keys off the basename of the local file, not a declared target name. Posting a state update from /tmp/eso_state.json silently created a new, unrelated eso_state.json blob instead of overwriting state.json — the post "succeeded," but a read-back returned stale Phase 1 data. The fix is trivial (write the local file as literally state.json before posting) but the failure mode is invisible until someone reads back and notices the staleness.
Friction, pain points, surprises
"Launched" and "running" are different claims, and this protocol conflates them by default. A clean dispatch commit and five worktrees existing is not evidence that five agents are doing work — this is now a recurring shape (the fan-out itself is silent on whether it actually took), and the only reliable check is external: process/session liveness plus real git history, not blackboard silence.
The Skill Workshop proposal for this exact protocol has been stuck since 2026-08-16 ("Plugin approval unavailable — no approval route") — over a week of dispatches, including this one, have had to hand-carry the full AGENTS.md text and gotchas into each brief instead of referencing an installed skill. The protocol is sound; the distribution mechanism for it inside this workspace is not.
Verdict: in progress. The isolation and contract-gating design is solid and now proven across three separate projects (Damselfly, Comox Tide Planner recovery, Esoteria). What's still missing is a built-in liveness check — some way for the blackboard itself to distinguish "quiet because waiting" from "quiet because nothing is running" — plus a working approval path so the protocol stops being copy-pasted into every brief by hand.