Beads: Durable Memory for Coding Agents
Reference: gastownhall/beads — MIT · Go
Beads is a command-line memory layer for AI coding agents. Instead of a markdown TODO list the agent forgets, it stores work as a version-controlled graph of small issues ("beads") linked by dependencies. The agent queries it with bd ready to find unblocked tasks, so a long project survives every context reset.
What problem does beads actually solve?
A coding agent has no memory between sessions. The plan it wrote two hours ago is gone the moment its context window clears, and the only thing it can recover is whatever happens to be written on disk when it wakes up. Beads turns that recovered file into a queryable graph instead of a forgettable note.
Steve Yegge, the author of beads, names the failure directly: "The problem we all face with coding agents is that they have no memory between sessions — sessions that only last about ten minutes. It's the movie Memento in real life, or Fifty First Dates."1 An agent boots up, reads whatever file is in front of it, and starts over.
The usual fix — a PLAN.md or TODO.md the agent updates — fails for a subtle reason. The launch post's appendix — Claude Sonnet 4.5 writing as the agent — names it: "The core problem with markdown plans: They're write-only memory for agents."2 The agent can append to the list, but 200 messages into a session it cannot reliably read it back: either the file is still in the context window or it is not. Markdown is a document, not a queryable store.
Beads replaces that document with a database. The README states the goal plainly: it "provides a persistent, structured memory for coding agents. It replaces messy markdown plans with a dependency-aware graph, allowing agents to handle long-horizon tasks without losing context."3 The repo has drawn 25,113 stars and roughly 340 contributors since October 20254 — fast for what Yegge describes as "a tool that AI has built for itself."1
What is a "bead"? The data model
A bead is an issue. The core Issue struct in internal/types/types.go is recognizable to anyone who has used a tracker — title, description, status, priority, assignee, timestamps — but two fields make it agent-native: a typed list of dependencies that forms the graph, and a compaction level that lets old work decay into summaries. Everything else is conventional.
type Issue struct {
ID string `json:"id"` // e.g. "bd-a3f2dd"
Title string `json:"title"`
Status Status `json:"status,omitempty"` // open / in_progress / closed ...
Priority int `json:"priority"` // 0 = P0/critical
// ... timestamps, assignee, acceptance_criteria ...
Dependencies []*Dependency `json:"dependencies,omitempty"`
CompactionLevel int `json:"compaction_level,omitempty"`
}
The Dependencies field is the graph. Each edge has a type, and beads ships a rich vocabulary of them — not just "blocks." From the source (abridged):
const (
DepBlocks DependencyType = "blocks"
DepParentChild DependencyType = "parent-child"
DepRelated DependencyType = "related"
DepRelatesTo DependencyType = "relates-to" // Loose knowledge graph edges
DepDuplicates DependencyType = "duplicates"
DepSupersedes DependencyType = "supersedes"
)
Yegge describes the shape this creates: "issues linked together by dependencies, like grapes on a vine. Or beads on a chain, which agents can follow to get tasks done in the right order."5 blocks and parent-child edges drive scheduling; relates-to, duplicates, and supersedes turn the tracker into a knowledge graph the agent can traverse for context.
graph TD
A[bd-a3f8 Epic] -->|parent-child| B[bd-a3f8.1 Task]
A -->|parent-child| C[bd-a3f8.2 Task]
D[bd-c1d2 Setup] -->|blocks| B
B -->|relates-to| E[bd-9f0a Note]
subgraph agent[Coding Agent]
Q["bd ready --json"]
end
Q -.reads.-> A
Q -.returns unblocked.-> C
Figure: a beads dependency graph — an epic linked to two tasks by parent-child edges, a setup issue that blocks one of them, and a loose relates-to note; the agent's bd ready --json query walks the graph and returns only the unblocked task.
How does the agent use it? The critical path
The agent never edits a file by hand. It runs CLI commands, and every command speaks JSON so the output is machine-readable rather than prose to be parsed. The loop is small and the same every session: ask what is ready, claim a task, do the work, close it, record any insight worth keeping. Here is that loop:
bd ready --json # tasks with no open blockers
bd update bd-a1b2 --claim # atomically take a task (assignee + in_progress)
bd close bd-a1b2 "Fixed" # mark done; unblocks dependents
bd remember "auth uses JWT" # persist an insight for next session
bd ready is the heart of it. Rather than asking the agent to reason about what is unblocked, beads computes it: an issue is ready when none of its blocks, conditional-blocks, or waits-for dependencies point at a still-open issue. The BuildReadyExplanation function even attaches a reason — "N blocker(s) resolved" — so the agent knows why a task surfaced.
This matters at scale. Beads benchmarks ready-work computation on 10,000- and 20,000-issue datasets6, and the project's own regression suite records the cost of getting it fast: one ready-work filtering change (PR #4001) cut a 5,000-issue query from 3,257 ms to 131 ms — a 96% time gain by the project's measurement7. Ready-work is a hot path because the agent calls it constantly.
Standout design decision 1: hash-based IDs
Multiple agents on multiple branches create issues at the same time. Sequential IDs (#1, #2) collide the instant two branches merge, because each branch independently hands out the next number. Beads sidesteps the whole problem by deriving the ID from the issue's own content instead of a counter, so two agents can never mint the same identifier.
// GenerateHashID: SHA256 of title + description + created timestamp + workspace ID.
// Caller extracts hash[:6] initially, then hash[:7], hash[:8] on collisions.
func GenerateHashID(prefix, title, description string, created time.Time, workspaceID string) string {
h := sha256.New()
h.Write([]byte(title))
h.Write([]byte(description))
h.Write([]byte(created.Format(time.RFC3339Nano)))
h.Write([]byte(workspaceID))
return hex.EncodeToString(h.Sum(nil))
}
An ID like bd-a3f2dd is derived, not assigned, so two agents never fight over the same number. The source documents the trade-off honestly: at 6 hex characters, 1,000 issues carry a "~2.94% chance" of collision and 10,000 issues a "~94.9% chance" — so beads extends the hash to 7 or 8 characters progressively, and notes that "97% stay at 6 chars."8 You get short, readable IDs in the common case and guaranteed uniqueness in the rare one.
Standout design decision 2: Dolt, not SQLite or git
The storage layer is the boldest call. Beads is "powered by Dolt"3 — a version-controlled SQL database. The architecture is two synchronized layers: a CLI layer of Cobra commands, and a single Dolt database under .beads/ that auto-commits on every write.
The reasoning, from the architecture doc: Dolt gives "queries complete in milliseconds with full SQL support" while adding "native version control — every write is automatically committed to Dolt history." And "cell-level merge resolves conflicts automatically."9 Paired with the hash-based IDs behind the README's "Zero Conflict" promise3, that is what makes concurrent multi-agent writes safe: when two branches each edit a different field of the same issue, Dolt merges the cells instead of flagging the whole row.
A plain SQLite file could not version or merge; a pile of markdown files in git would conflict constantly. Dolt is the unusual middle path — git's branching and merging, but for rows and cells.
What it teaches
The reusable idea is not "use Dolt." It is that agent memory wants database semantics, not document semantics. A markdown plan is write-mostly; you cannot ask it "what is unblocked?" without re-reading everything. Model work as typed nodes and typed edges instead, and three things fall out for free: a ready query, conflict-free concurrent writes, and a traversable graph.
The second lesson is interface discipline. Every beads command emits JSON, and the agent is told to "Run bd prime for workflow context" and "Do not use markdown TODO lists for task tracking." Memory only works if there is exactly one place to write it and one place to read it — a principle worth borrowing whether you build with Dolt, SQLite, or a flat file.
We have made the same argument for running a personal vault as a git-backed database, for modeling agent memory on the brain, and for treating markdown notes as an AI's memory.
Verdict
Beads is worth studying and, if you run long agent sessions, worth using. The data model is small, the ready-work computation is the genuinely clever part, and the Dolt bet trades a heavier dependency for branching and merging that markdown can never offer. It is MIT-licensed Go, moving fast, and the design holds up under reading.
Frequently Asked Questions
What is beads (bd)?
Beads is a command-line tool that gives AI coding agents persistent, structured memory. It stores work as a graph of issues ("beads") linked by typed dependencies in a version-controlled database, replacing markdown TODO files the agent forgets between sessions. The CLI is bd.
How does beads give an agent persistent memory?
The agent stores plans, tasks, and insights as issues in a Dolt database under .beads/ rather than in its context window. After a reset it runs bd ready and bd prime to recover the full plan and resume — the memory lives on disk in queryable form, not in the chat.
How is beads different from a markdown TODO list? A markdown list is — as the Claude-written appendix to the launch post puts it — "write-only memory": easy to append to, hard to query mid-session. Beads is a database, so the agent can ask "what is unblocked?" and get a computed answer, track dependencies, and merge concurrent edits without conflicts.
Does beads work without git?
Yes. Set BEADS_DIR to a directory and run bd init --stealth; all core commands work with zero git calls. The README lists non-git VCS (Sapling, Jujutsu), monorepos, and CI as cases where the Dolt database is the only storage backend needed.
How does beads avoid merge conflicts between agents?
Issue IDs are content hashes like bd-a3f2dd, derived from title, description, timestamp, and workspace — so concurrent agents never assign the same number. The underlying Dolt database resolves field-level edits with cell-level three-way merge, so two branches editing different fields of one issue merge cleanly.
What database does beads use?
Dolt, a version-controlled SQL database. Embedded mode runs Dolt in-process under .beads/embeddeddolt/ with single-writer file locking; server mode connects to an external dolt sql-server for multiple concurrent writers. Every write auto-commits to Dolt history.
Is beads only for Claude Code?
No. bd setup installs guidance and hooks for several agents — Claude Code, Codex CLI, Factory.ai Droid, Cursor, and more — and any agent that reads an AGENTS.md file can use the documented bd ready / bd show / bd close workflow.
Memory is not a longer prompt — it is a place to write things down that you can query later.
Want the same idea for your own notes? mnmnote.com keeps every note local and in plain Markdown, so what you write stays yours.
Footnotes
-
Steve Yegge, "Introducing Beads: A Coding Agent Memory System," Medium. https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a (Wayback: https://web.archive.org/web/20260521045436/https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a) ↩ ↩2
-
Claude Sonnet 4.5, "An AI Agent's Perspective: Why Beads Feels Different," Appendix A of Steve Yegge, "Introducing Beads: A Coding Agent Memory System," Medium. https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a (Wayback: https://web.archive.org/web/20260521045436/https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a) ↩
-
README, gastownhall/beads. https://github.com/gastownhall/beads/blob/main/README.md ↩ ↩2 ↩3
-
GitHub REST API, repos/gastownhall/beads (stars 25,113; ~340 contributors), accessed 2026-07-06. https://github.com/gastownhall/beads ↩
-
Steve Yegge, "Introducing Beads: A Coding Agent Memory System," Medium. https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a (Wayback: https://web.archive.org/web/20260521045436/https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a) ↩
-
BENCHMARKS.md, gastownhall/beads. https://github.com/gastownhall/beads/blob/main/BENCHMARKS.md ↩
-
BENCHMARKS.md, gastownhall/beads (PR #4001 ready-work filtering, project measurement). https://github.com/gastownhall/beads/blob/main/BENCHMARKS.md ↩
-
internal/types/id_generator.go, gastownhall/beads (GenerateHashID doc comment). https://github.com/gastownhall/beads/blob/main/internal/types/id_generator.go ↩
-
docs/ARCHITECTURE.md, gastownhall/beads ("Dolt for versioned SQL"). https://github.com/gastownhall/beads/blob/main/docs/ARCHITECTURE.md ↩