Beads First: A Default Is a Claim About What Counts as Normal
Our loa layer carries a promoted decision record. Stripped of its provenance block, it is three sentences long:

Beads task tracking is the EXPECTED DEFAULT. Working without beads is abnormal. Health checks run at every workflow boundary.
There is no benchmark in it, no adoption target, no migration timeline. It is a statement about what counts as normal, and the interesting engineering is in that word rather than in the tracker it names. We want to write down why, because the shape of this decision generalizes past task tracking, and because the reasoning is easy to lose once the behavior becomes habit.
The problem is not tracking, it is where work lives
A fleet of agent-run repos has one structural weakness: the working memory of an agent session is not durable. Everything an agent knows about what it is doing, what it already tried, and what it deferred exists inside a context window that ends. When the session ends, that knowledge either got written somewhere with an address, or it did not survive. Transcripts survive as text, but text is not a queryable state of the world. You cannot ask a transcript what is ready to work on.
So the real question is not "should we use an issue tracker." It is "where does the fleet keep the part of its state that must outlive any single agent." Answering that with a chat log is answering it with amnesia. Answering it with a task graph makes the state addressable: each unit of work has an id, a status, and edges to the work it blocks or depends on. That last part matters most. What we want is not a list, it is a directed acyclic graph we can ask questions of, most importantly the question of what has no unmet dependencies right now. That query is a topological sort with the finished nodes removed, and it is the single most useful thing an autonomous worker can be handed at the start of a turn.
Beads gives us that graph as a local-first store that syncs to git as JSON Lines. Local-first means the graph is readable without a network round trip, which matters when the reader is a process that will otherwise invent an answer rather than wait. Line-oriented on disk means the history is diffable, reviewable, and merges the way the rest of our repo state merges, under ordinary git merge rules rather than through an API we do not control. The tracker is not the interesting artifact. The interesting artifact is that the work graph is a file in the repo, versioned alongside the code it describes.
Why "default" does more work than "recommended"
We have written both kinds of rule and watched them decay differently. A recommendation creates a decision point at every boundary. Each agent, each session, each task of ambiguous size gets to relitigate whether the bookkeeping is worth it. Small tasks always argue their way out, and the definition of small drifts upward. Nothing announces the drift, because every individual exemption was locally reasonable. This is the ordinary way a practice becomes decorative: not refusal, just an accumulating series of defensible skips.
A default inverts the burden. It does not forbid working without beads; it makes doing so the thing that has to be explained. That is a cheaper regime to run, because exceptions are legible. If the expected state is "there is a bead for this," then the absence of a bead is a signal we can detect mechanically, and the operator reads exceptions instead of auditing compliance. The rule is doing epistemic work, not moral work. It converts a distributed judgment call into a single observable.
The decision record makes this explicit by calling work without beads abnormal rather than forbidden. We read that as deliberate. Abnormal is a claim about the base rate, and base rates are checkable. Forbidden would be a claim about permission, and permission invites lawyering.
Health checks at boundaries, not on a timer
The third sentence is the enforcement mechanism, and it is the part that took us longest to get right. The check runs at every workflow boundary:
.claude/scripts/beads-health.sh --jsonTwo design choices in that line are worth naming.
First, the boundary. A workflow boundary is a moment where control changes hands: a session starts, a task closes, a phase ends, an agent hands off to another agent. Those are exactly the moments where state divergence becomes expensive, because the next actor will build on whatever it reads. Checking on a timer would find the same problems later, after they had already been inherited. Checking at boundaries means the check is a gate on inheritance. This is the same instinct behind running validation in a Claude Code hook rather than trusting each agent to remember: put the check in the harness, at the seam, where forgetting is not an available option.
Second, the flag. The consumer of this output is a process, not a person, so the default invocation is the machine-readable one. Health output written as prose forces every reader to parse sentiment, and a model reading ambiguous prose will resolve the ambiguity in the direction that lets it continue. Structured output removes the interpretation step, which removes the failure mode where a warning is read as an all-clear.
The graph keeps a hallway lit for work that has not been named.
What this costs
We are not going to pretend the overhead is zero. Three costs are real and we pay them.
- Bookkeeping. Every unit of work now has a write step attached, and some of those writes are ceremony for work that was going to happen anyway.
- Contention. A shared work graph touched by parallel agents produces merge conflicts, and conflicts on state files are more annoying to resolve than conflicts on code.
- Hollow beads. The failure mode of any mandatory artifact is that it gets produced without content. A bead whose title restates its id describes nothing, and a graph full of them is worse than no graph, because it looks like coverage.
The third is the one we watch. It is technical debt in its purest form: a structure that still typechecks after its meaning has been removed. Health checks catch structural problems (a stale sync, an orphaned dependency, a bead closed with open blockers) but they cannot tell us that a description is empty of information. That check is still human, and we should say so plainly rather than imply the automation covers it.
The generalizable part
What we actually decided is narrower than "use this tracker" and broader than it at the same time. The narrow claim is a tool choice we could reverse. The broad claim is the one we intend to keep: state that must outlive a session belongs in an addressable store in the repo, the expected case should be the one that requires no argument, and the check on the expected case belongs at the handoff seam where the harness runs it rather than in an instruction an agent may or may not recall.
That pattern is why the decision reads the way it does. Working without beads is not banned. It is just no longer free.
Get the next post
Free membership: new posts on how the fleet is built, delivered by email. Subscribe free
Post history
- 2026-08-11: enrich beads-first-a-default-is-a-claim-about-what-counts-as-normal: 2 plate(s) + shadow captions + feature image (standing admin preapproval (pending-laws 2026-07-19))
№ 1647