field guidemain · attested greentoolchain pins ↗shippeddirectionproposed
02 How work flows

The mental model in one breath

You've run pipelines like this with humans in every box. The difference to look for: every hand-off is a record, and nothing passes a gate on vibes.

Every repo is a hive — its own beads database, served by bd's shared local Dolt server and kept out of your tracked tree under .beads/ until you furnish the hive. Issues carry a short, stable prefix(acme-api-1) derived from the stable part of identity (org + repo); the parts that can change (provider, org) live in labels. Issue history publishes torefs/dolt/data on the repo's own git remote — a separate ref namespace that never touches branches or PRs, so there is nothing hosted to run. A workspace-level aggregate (the hub) pulls every hive into one read view, so you can ask "what's ready to work on anywhere?"; HQ is the separate, authoritative fleet store.

bh is deliberately a thin orchestrator: bd (beads) owns issues,git owns history, git-workspace owns cloning. What bhadds is the process — bh work drives a bead through its lifecycle so agents never improvise raw git / gh pr for the lifecycle itself.

The tenets

⬢Planes, kept separate

Control governs the factory. Planning turns ideas into molecules. Development — the CLI still calls it Integration — executes them. Release proves a version and publishes it. Each plane has its own verbs and seats; they hand off sequentially and never step into each other's role. Assurance is the one exception — a cross-cutting gate layer, not a sequential plane.

⬢Merging is not releasing

Development is high-frequency and dirty: each bead gets its own worktree and lands on an always-green line. Release is a separate, deliberate, gated act — preflight, bump, attest, await, push — described below.

⬢Lossless history

Agents do the merging, so history is audited: merge --no-ff at the boundary, never squash there. Workers squash only their own local checkpoints into clean conventional digests before submit (tiered retention).

⬢Unit of work = a bead

Worktree → implement → refine → check → submit → review → merge. One bead, one branch (wt/bead/issue/<id>), one reviewable change.

The ring

Six phases, one ring — and one edge nobody closes

A car factory isn't successful because the car left the line — it's successful if the car survives the road. Software is no different: what happens in production is the only signal that says whether the last decision was any good, so it has to come back round to the next one.

agentic planningdesign → tasksagentic developmentframeworksSRE & DevOpsagentsscopecodeverifymergedeploytriagefeedbackIdeaPlanBuildReviewIntegrateProduction
Clockwise from Idea. Vertices are phases; edges are the function that carries you to the next one. The outer arcs are the agent product categories now reaching market — three of them, three separate data stores, none able to see the whole ring. An agent working this line shouldn't need six places to look. And note where the arcs stop: feedback is the edge no category sells, which is why it's dashed, and the edge Beadhive is built to close.
The four planes

Ideation → Planning → Development → Release

Control governs the sequence; Assurance gates across it. Each plane is a state machine with named re-entry doors — the full map shows every state. This is the skeleton.

CONTROL supervisor · director · custodian · controller
Ideationreport → triage → adoptintake ships · plane is directionPlanningidea → gated moleculeshippedDevelopmentbead → merged · CLI: integrationshippedReleaseattested tree → atomic pushverbs shipped · seat roadmap
ASSURANCE security gate, parallel to review, warden-only · Observation and Feedback: named, not specified
The pipeline

Inside two planes: planning → dispatch → develop → review → merge

The full state machine, with its three feedback loops: the spike loop (settle feasibility before implementation beads exist), the bounce loop(review → changes-requested → resume), and the replan door (a mid-execution blocker re-enters planning). Hexagons are gates — nothing passes one without the right seat resolving it.

PLANNING PLANE — HUMAN-INTERACTIVE · OUTPUTS BEADS + DECISION RECORDS, NEVER CODEDEVELOPMENT PLANE (CLI NAME: INTEGRATION) — DISPATCHER · DEVELOPER · REVIEWER · MERGERideateframe + triageresearchanalyst agentsarchitecturedecisions / ADRsdecomposespec · check · previewPLANbh plan fileKICKOFFbh plan approveroots surfacebd readya dispatcher picks it upopen GO / NO-GO?file spike moleculetag:spike + decision beadverdict landsdecision bead close reasonspikes dispatch like any moleculeGO → replanNO-GO → ADR, closenothing orphanedstart <epic>disp/ opens containerassign--to dev/<name>claimidentity + signingimplementwt/bead/issue/<id>show · refinesquash → digestscheckvalidate_cmdsubmitopens gatesREVIEWhuman · timer · gh:*SECURITYwarden/ onlyparallel gates — both must clearapprovemerge · merger seat--no-ff → container · merge-slotbounce · changes-requestedresumere-attach + read feedbacknext ready bead — parallel devs, serial mergefinish <epic>all children closed · validate assembled containerone --no-ff merge bubbleblocker / discovery → replan (the one re-entry door)main — always greenmerging ≠ releasing — the release gate runs on the bump tree, below
gate (bd gate — seat-resolved)approval / verdictfeedback loopalways-green integration lineforward flow
The two-gate planning exit is deliberate: plan approval gates whether the decomposition is right; kickoff approval gates whether the work should start now. Inside a molecule, every bead forks off the epic's container branch (wt/bead/epic/<id>) so bead B sees bead A's merged work; the container lands on main only when the whole molecule is done — one recursive rule that scales to N tiers (issue → epic → workstream → main).

The branch tree a molecule leaves behind

The pipeline above is the state machine; this is what it does to git. One workstream, one epic under it, three ways a bead can reach the container, and the twofinish lands that carry the result up a tier at a time.

TIME →wt/bead/issue/bh-ws.2.1leaf · developer dev/alicewt/bead/issue/bh-ws.2.2leaf · developer dev/bobwt/batch/same-filebeads .3 .4 .5 · dispatcher @ batchwt/bead/epic/bh-ws.2epic container · disp/ seat worktreewt/bead/epic/bh-wsworkstream = epic of epics · disp/mainintegration branch · always greenbh work start bh-ws --as disp/start bh-ws.2 — forks off its integration_baseclaim → implement → refine → check → submitmerge --no-ffforks after .1 landed → sees its workone commit per bead · submit --group · merge --groupparallel work, serial merge — one merge slotfinish bh-ws.2one no-ff bubble, one tier up;the seat worktree is torn downfinish bh-ws → mainsame rule, last tier:fixed forward, never rewrittenintegration_base climb: bh-ws.2.1 → bh-ws.2 → bh-ws → main · the dotted id is the tier · nearest started container wins
integration branchcontainer branch — a dispatcher seat at any tierleaf / batch branch — a developer or collapsed seatfork (claim / start)
Two namespaces, one rule. Every container lives atwt/bead/epic/<id> and every leaf at wt/bead/issue/<id>; a bead forks from — and bh work merge lands on — the nearest started container above it, falling back to main. A batch is the one exception to one-bead-per-worktree: cohesive beads share wt/batch/<group> and complete as a unit. An intermediate, unpushed container can still roll back losslessly if a re-validation fails; only the final land onto main is fixed forward. A second epic under the same workstream (bh-ws.3) runs the identical loop on its own container, dispatched to a nested dispatcher.

What keeps the line green

  • Serialized merges. Merge is a separate seat (the merger) gated bybd merge-slot — parallel developers, one merge at a time.
  • The conflict ladder. clean → rebased → union → bounce: try a clean --no-ff, then rebase-and-retry, then path-whitelisted union merge (append-only files only, re-validated), else bounce with the branch restored. No work is ever lost.
  • Validation modes. Every bead validates in isolation at submit;relaxed / conservative / loose tune how often thecombination is re-tested. If a re-validation fails on a safe-to-rewrite branch, the tip is rolled back before anyone can observe it; a shared branch escalates for a forward fix instead.
  • Evidence is keyed to the tree. A green result is stored against the exact tree hash and command that produced it. A fresh exact match may be reused where the caller allows it; a graph-derived attest key may carry across a change only when its whole input closure is unchanged. Unknown impact fails closed to the full run, and a reused key is never a claim that the whole tree is green — how reuse works.
  • The batch exception. Cohesive linear chains can run as one sharedwt/batch/<group> worktree, merged once — guarded by cohesion, a size cap of 5, no conflicting model preferences, one review gate. A batch fails and bounces as a unit; per-bead commits stay bisectable inside the bubble.

Gate phases × strictness

Seven places a tree can be asked to prove itself between a developer's worktree and the remote. work.validation picks which of them are owed; the tree-keyed ledger decides whether an owed gate must actually run.

THE LAND PATH — EVERY CHECKPOINT A BEAD CAN MEETsubmitbead branch · handoffmergebead → containermerge-mainad-hoc bead → mainunionbatch branchmoleculecontainer → mainpostlandmain tip after landpush-maingit push hooka bead meets 5 or 6 of these:merge → container inside amolecule, or merge-main whenit has no molecule at allwork.validationrelaxeddefault · combination at main boundariesgate runsskippedgate runsgate runsgate runsif main movedverdict lookupconservativethe tip after every mergegate runsgate runsgate runsgate runsgate runsgate runsverdict lookuploosetrust the submits · warn if main movedgate runsskippedskippedgate runsskippedskippedverdict lookupIf a re-validation goes redsafe-to-rewrite branch (private container, unpushed main): the tip is reset while themerge slot is still held, so no broken tip is ever observable; the bead bounces.shared, pushed branch: never rewritten — loud escalation and a forward fix.Any required gate may resolve as a lookupIt skips the run when the exact tree already holds a fresh green verdict for that command,keyed (tree, cmd_hash). Strictness says whether a gate is owed;tree-keyed evidence says whether it has to run.
gate requiredverdict lookup first — full gate inline on any missonly if main moved underneathskipped
Every bead is validated in isolation at submit in every mode; the modes only govern how often the combination is re-tested. relaxed pays at the two main-boundary gates (molecule, merge-main) plus a staleness backstop when main moved under the land; conservative also re-tests the container after each bead merge; loose trusts the submits. push-main is the one checkpoint a git hook resolves: it asks for a fresh verdict on the exact tree being pushed and runs the full gate itself on any miss, stale entry, red record, or missing bh — no path treats an absent attestation as a pass. Per-boundary commands are overridable (work.validate.<phase>), so the fast tier runs everywhere and the full tier only where main is touched.
Where the ideas come from. directionThe pipeline starts at ideate, which quietly assumes someone showed up with an idea — capping the whole factory at one person's imagination on a given afternoon. What ships upstream of planning today is intake and triage. The ideation plane is meant to add a loop that doesn't wait for someone to show up: read the repo's own vision and strategy documents, derive candidate topics from how those documents are actually structured rather than from a generic checklist, then generate against each topic in parallel — deliberately blind to the others, so the batch stays divergent instead of converging on the same three obvious ideas. Survivors are deduplicated, judged against the vision, and filed throughbh plan file like any other molecule, so nothing skips the kickoff gate. Its states and seat are not defined yet.
Merge order

Merge order is planned, not first-come-first-served

Landing approved beads in whatever order they clear review is fine until a molecule mixeskinds of change — a hotfix for the released version, additive features that should ship as one clean minor bump, and a breaking change that must not leak into a patch. Review order produces a history nobody can version cleanly. So a bead can carry its semantic-version impact, and the merge sequence is computed from it:

  • release: — breaking, feature or fix. A fixed vocabulary, identical in every hive, so the ordering means the same thing everywhere.
  • wave: — a free-form label grouping additive features that should land together as one bump. Distinct from the worktree batching label.

The default strategy, stable-versioning, orders in four tiers: fixes for the released version flush first, up to a churn budget; then additive features, grouped by wave; then any fixes past that budget; then breaking changes last, so they never leak into a patch or minor window early. Both knobs are per-hive configuration (release.strategy, release.fix_churn_budget).

bh release order   # the strategy-preferred merge sequence, read-only

It is advisory. It decides sequence and nothing else — it never claims, merges or mutates anything, and the scheduler consults the same scorer so dispatch and merge never disagree about the order. The one hard counterpart is opt-in per hive: withrelease.enforce_hold on, a release:breaking bead gets arelease-hold: gate that blocks its merge until a releaser resolves it — and only a releaser can.

Cutting the version: the guarded bump shipped

Ordering decides what lands; the bump decides what ships. The rule that makes it safe: the release gate runs against the exact tree the bump creates, not the tree that was green before it.

  1. preflightrequires green proof for the current tree before anything moves
  2. bumpcz bump writes version metadata and a local tag — a new, unproven tree
  3. attestruns the push-main gate on that exact tree
  4. awaitblocks until the verdict; red refuses, green permits
  5. pushone atomic push moves main and the tag together
bh release preflight   # green proof for the current tree, or refuse
cz bump                # new tree + local tag — unproven
bh release attest      # the push-main gate against that exact tree
bh release await       # block until GREEN, then push main + tag atomically
bh release recover     # after a failed push: measure the remote before deciding

The tag reaching the remote is the point of no return. Before it, recovery can undo locally; after it, roll forward — published history is never rewritten.

THE GUARDED BUMP — GREEN IS PROVEN BEFORE THE LAST REVERSIBLE MOMENT, NEVER INSIDE THE PUSHremotethe tag on the remoteis the point of no returnmain tip · tree Tverdict from the landmolecule / merge-mainalready proved T greenbh release preflightreads the verdict for TREFUSES the bump withoutone — never runs the gatecz bumptree T′ + local tagpyproject · changelog · lock:UNATTESTED by constructionbh release attestpush-main gate on T′fires now, detached;writes T′ verdictbh release awaitblocks on the verdictGREEN ⇒ goRED ⇒ refuse, undo locallyatomic pushgit push --atomicboth refs or neither;roll forward from herered: nothing has left — the local bump and tag are still undoable to a clean slateTHE PRE-PUSH HOOK — ONE VERB, ONE-DIRECTIONAL SAFETYgit push origin mainlefthook pre-pushbh hive hook push-mainfresh green for the EXACT tree + command?exit 0 · hit → push proceeds (~ms)anything else → full gate inlinemiss · stale · red · malformed · unconfigured · a differentcommand · no hive · no bh on PATH · any exception:the gate runs, exactly as before the hook existed.No path treats a missing attestation as a pass.AFTER A FAILED PUSH — bh release recover DECIDES ON ONE MEASURED FACTgit ls-remoteagainst the actual remote —never a local tracking ref,never an assumption.Returns a code, not a boolean,because the fourth answer is"I could not tell" and thatmust never become an undo.tag publishedroll forward — never delete; published history is never rewrittentag absent, bump not on the remotethe undo is safe — locally reset the bump and tag to a clean slatemain landed without its taga half-done release — finish it, push the tag; do not undo. Unreachable via the atomic push, measured for anywaycould not read the remoteconclude nothing — a history rewrite on a network blip is the one outcome worse than doing nothing
proven green / permittedrefused / unproventhe lookup
Merging is not releasing, and the release gate runs on the tree the bumpcreates, not the one that was green before it. The ordering is the design: the bump is the last safely reversible moment, so preflight demands existing proof for the current tree and refuses to establish it late; attest then proves the bump tree itself; await holds the push until that verdict is green, while a red one still leaves everything local and undoable. One atomic push moves main and the tag together, and the tag reaching the remote is the boundary between undo and roll-forward. The pre-push hook is the same idea applied where a slow gate hurts most: a --no-ff land onto an unmoved main yields a tree byte-identical to the one the land already tested, so the push has nothing left to prove — and every other outcome degrades to the full gate, never to an ungated push. What landsbefore the bump is ordered by the advisory bh release order and, opt-in, arelease-hold: gate that only a releaser can clear on a breaking change.
Verbs ship; the seat is roadmap. directionThe commands above run today. The releaser seat that owns them in the org chart — changelog authorship, the release plane as a staffed stage — is still marked roadmap in the reference docs, so a human runs the bump.