Beads Setup Guide

Beads is a Dolt-backed, dependency-aware issue tracker designed for AI agent workflows. It pairs with Thrum to give agents persistent task memory that survives session boundaries.

Upgrading from bd 0.62 or earlier? bd 1.0 switched the default backend from a separate dolt sql-server process to an embedded, single-writer store and can't read the old on-disk layouts. If you have existing bd data, follow the Beads Migration to Embedded Mode guide before running any bd commands — several commands (bd dolt push, bd dolt start, bd backup --force) have been removed or replaced.

Why Beads with Thrum

Thrum handles communication — messages, presence, coordination. Beads handles task state — what needs doing, what's blocked, what's done. Together they solve the two halves of the agent context-loss problem:

Installation

bd 1.0+ ships with an embedded Dolt store baked into the binary. There is no separate dolt prerequisite for the default install — you just need bd. (The dolt CLI is only needed if you want to run raw SQL against the embedded database, or for some advanced backup/migration workflows.)

Minimum versions: bd 1.0.0+

# Option A: Homebrew
brew install beads

# Option B: Install script (installs to /usr/local/bin)
curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash

# Verify
bd version    # must be 1.0.0+

Already have bd installed at 0.62 or earlier? Upgrade is machine-wide (the bd binary lives in a shared path like /usr/local/bin/bd) and will break every unmigrated repo on the machine at once. Before running brew upgrade beads or the install script, follow the migration guide — it walks through inventorying your repos, capturing each one's data via dolt dump or JSONL export, and loading everything back into the fresh embedded store.

Initialize in Your Project

cd your-project
bd init

bd init in bd 1.0+ creates an embedded Dolt store inside the repo — no background server, no port coordination, no dolt-server process to manage. All writes go through a single-writer file lock.

The .beads/ directory it creates:

Path Purpose
config.yaml Team-level config (committed to git)
metadata.json Local state: backend, mode, database name (gitignored)
.gitignore Ignores lock files and internal dolt data
interactions.jsonl Interaction log
README.md Quick reference
embeddeddolt/<prefix>/ Embedded Dolt database (single-writer, file-locked)

bd init also creates AGENTS.md in the repo root with agent instructions.

Tradeoff: Embedded mode is single-writer. Multiple concurrent bd processes serialize through the file lock. For Thrum's agent topologies (14-ish agents, serial coordinator-driven writes) this is fine. For heavy concurrent workloads, opt in to server mode explicitly by setting dolt.mode: server in .beads/config.yaml — but the server-mode lifecycle commands (bd dolt start/stop/push) are gone in 1.0, so you'd be managing dolt sql-server directly.

Core Workflow

Create issues

# Create an epic (groups related tasks)
bd create --title="Add user authentication" --type=epic --priority=1

# Create tasks under it
bd create --title="Implement JWT middleware" --type=task --priority=2
bd create --title="Write auth tests" --type=task --priority=2

# Set dependencies (tests depend on middleware)
# bd dep <blocker> --blocks <blocked>: blocker must close before blocked becomes ready
bd dep <middleware-id> --blocks <tests-id>

Find and claim work

# Show tasks ready to work (no blockers)
bd ready

# See what's blocked and why
bd blocked

# Claim a task
bd update <id> --status=in_progress

Complete work

# Close a task
bd close <id>

# Close multiple at once
bd close <id1> <id2> <id3>

# Check progress
bd stats

Sync Setup (bd 1.0+ embedded mode)

Beads stores its state inside the embedded Dolt database at .beads/embeddeddolt/<prefix>/.dolt/. For off-machine sync, bd 1.0 offers two complementary mechanisms:

Typical private-repo setup (Dolt ref sync, no tracked files):

# 1. Turn on auto-commit (required for auto-push to have anything to push)
bd config set dolt.auto-commit on

# 2. Turn on auto-push
bd config set dolt.auto-push true

# 3. Run one initial manual push to establish the remote baseline
cd .beads/embeddeddolt/<prefix>
dolt push origin main
cd -

# Verify the ref is live:
git ls-remote origin 'refs/dolt/*'
# Expected: <hash>  refs/dolt/data

Typical public-repo setup (external backup script, no dolt-ref sync):

# .beads/config.yaml — don't publish the hidden dolt ref publicly
backup:
  git-push: false

bd 0.62 sync commands removed in 1.0. bd dolt push, bd dolt pull, bd dolt start, bd dolt stop, and bd dolt commit no longer exist in embedded mode. If your scripts or CLAUDE.md reference them, update to bd config set dolt.auto-push true (or run dolt push origin main directly from inside .beads/embeddeddolt/<prefix> when you need an explicit push). The migration guide has the full before/after command table.

Setting Up Beads from an Existing Clone (legacy bd 0.59–0.63 server mode)

This procedure applies to bd 0.59–0.63 server mode only. On bd 1.0+ embedded mode, a fresh clone is usually bd init followed by dolt pull origin main from inside .beads/embeddeddolt/<prefix>/ (if the remote has a refs/dolt/data ref) or bd import <jsonl-file> (if the data travels as .beads/backup/*.jsonl tracked files). If you're on bd 1.0 and want to bootstrap from an existing remote, see the migration guide — the bd init → data load → verify flow is the same shape as a fresh migration.

The steps below are preserved for teams still on bd 0.59–0.63 server mode. They assume bd 0.61.0 and dolt 1.81.8+. Follow the steps in order — each step depends on the previous one.

Prerequisites

Step 0: Confirm your remote has beads data

git ls-remote origin | grep dolt
# Expected output: <hash> refs/dolt/data
# If you don't see this, the remote has no beads data — use bd init normally.

Step 1: Initialize beads

bd init

This creates the .beads/ directory structure, config files, and an empty dolt database. It will print a note suggesting bd bootstrap — as of bd 0.61.0, bd bootstrap may handle the full setup automatically. Try it first and skip to Step 7 if it succeeds.

The dolt server may or may not start successfully during init. Either way, we need to replace the empty database with the remote data, so continue below.

Step 2: Stop the dolt server

bd dolt stop

If the server didn't start during init, you'll see "Dolt server is not running" — that's expected, continue to the next step.

Step 3: Find your database name and remove the empty database

# Check your database name (look for "dolt_database")
cat .beads/metadata.json

The dolt_database field is your <dbname>. For a repo named myproject, it will typically be myproject.

# Remove the empty database that bd init created
rm -rf .beads/dolt/<dbname>/

This must be done before cloning. If you skip this step, dolt clone will fail because the target directory already exists.

Step 4: Clone the dolt data from your git remote

cd .beads/dolt
dolt clone git@github.com:org/repo.git <dbname>
cd ../..

Dolt automatically reads from refs/dolt/data on the git remote. This downloads all beads issue data. For HTTPS remotes, use https://github.com/org/repo.git instead.

You must cd back to the repo root before running any bd commands — they need to discover the .beads/ directory from the project root.

Step 5: Start the dolt server

bd dolt start

This starts a background dolt sql-server process. You should see output like:

Dolt server started (PID <num>, port <num>)

If it fails, check .beads/dolt-server.log for errors. A common cause is a corrupted database from a previous failed attempt — go back to Step 3 and start over.

Step 6: Run schema migrations

bd migrate --yes

This upgrades the database schema if the remote data was created with an older version of beads. If the schemas already match, it updates just the version marker. Safe to run even if no migrations are needed.

Step 7: Ensure the remote is registered

dolt clone may or may not preserve the remote configuration (behavior varies across dolt versions). Both the dolt CLI and the SQL server need to know about the remote for bd dolt push and bd dolt pull to work.

Run these commands — they are safe if the remote already exists (you'll see "remote already exists" errors, which you can ignore):

# Add to dolt CLI (run from inside the dolt database directory)
cd .beads/dolt/<dbname>
dolt remote add origin git@github.com:org/repo.git
cd ../../..

# Add to SQL server
bd sql "CALL dolt_remote('add', 'origin', 'git@github.com:org/repo.git')"

"remote already exists" errors on either command mean dolt clone already set it up — that's fine, move on.

Step 8: Verify

bd dolt test          # should print: ✓ Connection successful
bd dolt remote list   # should show: origin <your-remote-url>
bd list               # should show your issues

If bd list shows your issues, you're done.

Why this process is necessary

You cannot simply run bd dolt pull after bd init. A freshly initialized database and the remote have completely separate histories with no common ancestor. Dolt's pull (and fetch + reset) either fails with "no common ancestor" or corrupts the local database. Deleting the empty database and cloning fresh is the only reliable path.

After setup

Use the normal sync workflow to keep your issues in sync:

bd dolt commit    # commit working set changes
bd dolt push      # push to remote
bd dolt pull      # pull from remote (must commit first)

Agent Integration with Thrum

The standard agent workflow combines both tools:

# 1. Agent starts — check for assigned work
thrum inbox --unread
thrum sent --unread
thrum message read --all       # Mark all messages as read
bd ready

# 2. Claim a task and announce it
bd update <id> --status=in_progress
thrum send "Starting work on <id>: <title>" --to @coordinator

# 3. Do the work...

# 4. Complete and announce
bd close <id>
thrum send "Completed <id>, tests passing" --to @coordinator

# 5. Find next task
bd ready

Worktree Support

If you use git worktrees (common in multi-agent setups), Beads supports sharing a single Dolt server across worktrees via a redirect file:

# In each worktree, point to the main repo's .beads/
mkdir -p /path/to/worktree/.beads
echo "/path/to/main/repo/.beads" > /path/to/worktree/.beads/redirect

All worktrees share the same Dolt server via the redirect — issues created in any worktree are immediately visible everywhere.

If your project includes the Thrum worktree setup script, this is handled automatically:

./scripts/setup-worktree-thrum.sh ~/.workspaces/project/feature feature/name

Claude Code Plugin

Install the Beads plugin for Claude Code to get slash commands (/beads:ready, /beads:create, etc.) and an MCP server for native tool integration:

# In Claude Code
/plugin marketplace add steveyegge/beads
/plugin install beads

Restart Claude Code after installation. See the Beads plugin docs for the full command reference.

CLAUDE.md Configuration

For agents that don't use the plugin (or as a supplement), add these instructions to your CLAUDE.md:

## Task Tracking

Use `bd` (beads) for all task tracking. Do not use TodoWrite, TaskCreate, or
markdown files for tracking.

- `bd ready` — find available work
- `bd update <id> --status=in_progress` — claim a task
- `bd close <id>` — mark complete
- `bd stats` — check project progress

The Thrum Claude Code plugin automatically detects Beads and includes task context in the pre-compact hook, so agents recover their task state after context compaction.

Common Errors and Fixes

bd dolt ... errors with "not supported in embedded mode" Expected on bd 1.0+. Use bd config set dolt.auto-push true or run dolt push origin main directly from inside .beads/embeddeddolt/<prefix>/. See the migration guide for the full before/after command table.

"no common ancestor" on push Stale refs/dolt/data from a previous database. Clear the remote ref and retry:

# Delete the stale remote ref:
git push origin :refs/dolt/data

# Re-push from the embedded store:
cd .beads/embeddeddolt/<prefix>
dolt push origin main

"database is locked" or "lock file already exists" Another bd process is already writing. Embedded mode is single-writer via file lock. Wait for the other process to exit, or inspect .beads/embeddeddolt/<prefix>/.dolt/ for a stale lock if no process is running.

bd doctor says "not yet supported in embedded mode" Known placeholder on bd 1.0. Use bd migrate (no args) for the schema/metadata health check and ls -la .beads/embeddeddolt/ to verify the database exists.

bd ready errors with column "no_history" could not be found Schema drift from a very old bd version's data being loaded into a fresh bd 1.0 store. The migration guide Step 6C has the ALTER + CREATE TABLE fixes.

brew / dolt / bd not found over SSH Homebrew on ARM64 Mac installs to /opt/homebrew/bin, not in the default SSH PATH. Use a login shell: ssh host 'bash -lc "bd version"'

Commands Reference

Command Purpose
bd ready Tasks with no blockers
bd list All open issues
bd list --status=in_progress Active work
bd blocked Blocked issues with reasons
bd show <id> Full issue detail
bd stats Project health overview
bd create --title="..." --type=task --priority=2 Create an issue
bd update <id> --status=in_progress Claim work
bd update <id> --claim Atomic claim (assign + in_progress)
bd close <id> Mark complete
bd close <id> --suggest-next Close and show newly unblocked work
bd dep <blocker> --blocks <blocked> Blocker must close before blocked is ready
bd dep tree <epic-id> Show dependency graph
bd epic status <epic-id> Progress on epic children
bd comments add <id> "msg" Add comment (subcommand before ID)
bd search "query" Search issues by text
bd import <file.jsonl> Load issues from a JSONL file
bd export --all -o <file.jsonl> Export all issues to JSONL
bd config set dolt.auto-commit on Auto-commit dolt writes (recommended)
bd config set dolt.auto-push true Auto-push embedded store to refs/dolt/*
bd migrate Schema/metadata health check

bd 0.62 commands removed or replaced in 1.0+: bd dolt start, bd dolt stop, bd dolt push, bd dolt pull, bd dolt commit, bd dolt status, bd backup --force, bd sync, bd onboard, bd doctor (as a health check). See the migration guide for the full before/after mapping.

Comments syntax note: The correct syntax is bd comments add <id> "msg" — subcommand comes before the issue ID.

Further Reading