Skip to main content
Beads uses Dolt as its storage backend. Dolt provides a version-controlled SQL database with cell-level merge, native branching, and two deployment modes.

Why Dolt?

  • Native version control — cell-level diffs and merges, not line-based
  • Multi-writer support — server mode enables concurrent agents
  • Built-in history — every write creates a Dolt commit
  • Native branching — Dolt branches independent of git branches
  • Single-binary option — embedded mode for solo users (no server needed)

Getting Started

Install Dolt (Server Mode Only)

Embedded mode includes everything in the bd binary; no separate Dolt install is needed. Install the standalone dolt CLI only when you want to run server mode or work directly with the database via dolt sql. Install a specific version. Do not install releases/latest — see Which Dolt version to install for the version to use and why the pin exists.
brew install dolt installs whatever version the Homebrew formula currently points at, which is not pinned. If you install that way, check dolt version against the pin below.

Which Dolt version to install

Beads pins Dolt to 2.2.0. CI installs that same pin with scripts/ci/install-dolt.sh, which records the per-version measurements and the criterion for raising it; raise the pin here and in that script together. This pin is about the standalone dolt CLI, which only server and proxied-server mode use. Embedded mode is unaffected either way: it links the Dolt engine into bd at the version in go.mod, currently the commit tagged v2.2.0 upstream, no matter which dolt CLI is on your PATH. Dolt 2.3.0 (released 2026-08-13) regressed CALL DOLT_RESET('--hard'). A few percent of freshly created databases come up with that procedure unusable — every call answers Error 1105 (HY000): context canceled, from any session and any new connection, for the life of that server process. Nothing else about the database looks wrong: SELECT 1, CALL DOLT_CLEAN(), CALL DOLT_CHECKOUT('.'), CALL DOLT_COMMIT() and soft resets all work normally, so the damage is invisible until something needs a hard reset. Measured by creating fresh databases and immediately calling the procedure: Versions after 2.3.1 have not been measured. Raise the pin only once a newer release is confirmed clean by that same measurement — not because it is newer. Pin rather than track latest for a second, independent reason: the upstream releases/latest URL resolves to the most recently created release, not the highest version, so it can move backwards — v1.88.2 was created on 2026-08-17, after both v2.2.4 and v2.3.0.

If you are already running 2.3.x

Whether a database is affected is decided per database, when it is created — two databases on the same server can differ — so check each one you care about, against the server that is actually serving it:
Step 2 succeeding while step 3 answers Error 1105 (HY000): context canceled is the discriminating result — that database is affected. Both succeeding means it is not. The breakage lives in the running server process, not on disk, so restarting dolt sql-server clears it — verified by re-running the check on an affected database after a restart, with a healthy database on the same server as the control. A restart re-rolls the dice for every database, though, so the durable fix is to move to the pinned version. This matters because bd flatten and the Dolt-history compaction in bd admin compact both finish by hard-resetting main onto a temporary branch, and the merge-settle path behind bd dolt pull / bd sync falls back to a hard reset when it has to abandon a merge. See Maintenance.

New Project

Migrate from SQLite (Legacy)

If upgrading from an older version that used SQLite:
Note: The bd migrate --to-dolt command was removed in v0.58.0. For pre-0.50 installations with JSONL data, use the migration script:
See Troubleshooting if you encounter connection errors after migration.
Migration creates backups automatically. Your original SQLite database is preserved as beads.backup-pre-dolt-*.db.

Modes of Operation

Embedded Mode (Solo / Standalone)

In-process Dolt engine — no separate server needed. This is the default for standalone Beads users. The bd binary includes everything; just bd init and go.
  • Single-writer (one process at a time)
  • Data lives in .beads/embeddeddolt/ alongside your code
  • Push to GitHub with bd dolt push — code and issues in one repo
  • Zero ops: no server, no ports, no PID files

Server Mode (Multi-Writer / Orchestrator)

Connects to a running dolt sql-server for multi-client access.
Configure the connection with flags or environment variables: Unix domain sockets: Use --server-socket to connect via a Unix socket instead of TCP. This avoids port conflicts between concurrent projects and is useful in sandboxed environments (e.g., Claude Code) where file-level access control is simpler than network allowlists. The Dolt server must be started with dolt sql-server --socket <path>. Auto-start is not supported in socket mode. Switch to server mode when you need:
  • Multiple agents writing simultaneously
  • Orchestrator multi-rig setups
  • Federation with remote peers

Maintenance — bd prune and bd purge

bd prune permanently deletes closed non-ephemeral beads to reclaim storage and shrink auto-exports. bd purge does the same for ephemeral beads (wisps, transient molecules). Both require --force to execute.
Reference-aware protection: bd prune automatically skips closed beads whose ID appears in the description, notes, or comments of any open or in-progress bead. This prevents accidental deletion of ADR, decision, and verification beads that downstream work still cites. Use --ignore-references to override when cleaning up known-stale references:
bd purge is unaffected — ephemeral beads’ references are themselves transient. For full Dolt storage reclaim after deleting many rows, follow with bd flatten. On Dolt 2.3.x, storage-reclaim operations can fail partway. bd flatten and the Dolt-history compaction in bd admin compact both build a temporary branch and then hard-reset main onto it, and the merge-settle path behind bd dolt pull / bd sync falls back to a hard reset when it abandons a merge. On an affected database that hard reset returns Error 1105 (HY000): context canceled: bd flatten and bd admin compact stop at that step, and an abandoned merge is left without its rollback. See Which Dolt version to install for the check and the fix.

Migrating Between Backends

You can migrate data between embedded mode and server mode using bd backup. Both directions preserve full Dolt commit history. bd export is not a substitute for this flow. JSONL exports contain issue records from the issues table for migration and interoperability; they do not capture Dolt branches, full commit history, working-set state, or non-issue tables. Use bd backup or a manual Dolt backup when you need a restorable database backup.

Server → Embedded

  1. Create a backup from the server-mode project:
  2. Create a new embedded-mode project and restore:
    --force overwrites the freshly-initialized database with the backup contents. The restore automatically:
    • Updates metadata.json to match the restored project identity
    • Registers the backup directory for future bd backup sync
    • Backfills the embedded migration tracker (schema_migrations)
  3. Verify:

Embedded → Server

  1. Create a backup from the embedded-mode project:
  2. Create a new server-mode project and restore:
  3. Verify:

Backup Commands Reference

Notes

  • Data locations differ between modes: .beads/embeddeddolt/ (embedded) vs .beads/dolt/ (server)
  • The backup directory is a full Dolt backup, not an issues.jsonl export — it can be on a local drive, NAS, or DoltHub
  • You can also migrate via Dolt remotes (bd dolt push / bd dolt pull) if both projects share a remote
The sections below are the canonical backend migration reference.

Federation (Peer-to-Peer Sync)

Federation lets independent Dolt-backed workspaces (“towns”) sync issues directly with each other via bd federation add-peer/sync/status, without a central hub. Credentials are AES-256 encrypted and stored locally. See Federation Setup Guide for the full setup guide, including peer configuration, sovereignty tiers, sync/status/topology details, and troubleshooting.

Dolt Remotes

Use bd dolt remote add to configure remotes. This ensures the running Dolt SQL server sees the remote immediately. Remotes added directly with the dolt CLI are written to filesystem config and may not be visible to the server until restart.

Push/Pull

bd dolt remote add registers the remote through the Dolt store API. SQL remotes are the source of truth for bd dolt remote list, bd dolt push, and bd dolt pull. For git-protocol remotes, credentialed external-server remotes, and cloud remotes whose credentials are only present in the current shell, bd dolt push and bd dolt pull automatically materialize a matching local CLI remote before using the dolt CLI transport. The CLI remote is a local transport mirror, not a separate configuration source. If you are upgrading from an older beads version and previously added remotes with raw dolt remote add, re-register them with bd dolt remote add <name> <url> so they are visible through SQL. bd doctor reports legacy CLI-only or mismatched CLI remotes under Dolt Remote Migration.
Sharing a Git repo: Dolt stores data under refs/dolt/data, separate from standard Git refs (refs/heads/, refs/tags/). You can safely point a git+ssh:// remote at the same repository as your project source code. See Dolt Git Remotes.

List/Remove Remotes

Contributor Onboarding (Clone Bootstrap)

When someone clones a repository that uses Dolt backend:
  1. Run bd bootstrap in the clone
  2. If the git remote has refs/dolt/data (pushed via bd dolt push), bd bootstrap auto-detects it and clones the database from the remote
  3. Work continues normally — all existing issues are available
No manual steps required beyond bd bootstrap. The auto-detect:
  • Probes origin for refs/dolt/data
  • Clones the Dolt database from the remote (instead of creating a fresh one)
  • Configures the Dolt remote for future bd dolt push/pull
If sync.remote is set in .beads/config.yaml, that takes precedence over auto-detection. Any Dolt-compatible remote URL is supported (DoltHub, S3, GCS, file, or git). On brand-new projects, bd init auto-detects git origin and persists it as sync.remote, so the first bd dolt push publishes Dolt history to refs/dolt/data on the same git remote.

Verifying Bootstrap Worked

Troubleshooting

Server Not Running

Symptom: Connection refused errors when using server mode.
Fix:

Bootstrap Not Running

Symptom: bd list shows nothing on fresh clone. Check:
Force bootstrap:

Database Corruption

Symptom: Queries fail, inconsistent data. Diagnosis:
Recovery options:
  1. Repair what’s fixable:
  2. Rebuild from remote:

Already Committed .beads/dolt/ to Git

If you accidentally committed a Dolt data directory:
  1. Update gitignore: bd doctor --fix
  2. Remove it from git tracking: git rm --cached -r .beads/dolt/ (or .beads/embeddeddolt/)
  3. Commit the removal: git commit -m "fix: remove accidentally committed dolt data"
  4. To purge from history, use BFG Repo-Cleaner or git filter-repo

Lock Contention (Embedded Mode)

Symptom: “database is locked” errors. Embedded mode is single-writer (enforced via file lock). If you need concurrent access, switch to server mode. See Migrating Between Backends.

Configuration Reference

Environment Variables

Credentials File

For multi-server setups, you can store passwords in an INI-style credentials file instead of juggling environment variables per project. Passwords are looked up by [host:port] section, so each project automatically gets the right password based on its configured server. Password resolution order:
  1. BEADS_DOLT_PASSWORD env var (highest priority, existing behavior)
  2. Credentials file lookup by [host:port] (using the resolved runtime port)
  3. Empty string (no password)
Port resolution note: The [host:port] used for credential lookup matches the resolved runtime port (from the port file, env var, or config — in that priority order), not necessarily the port stored in metadata.json. This matters when using IAP tunnels: if your tunnel maps remote:3307 to localhost:3308, store your password under [127.0.0.1:3308] and the credentials file will match the actual connection. Default location: ~/.config/beads/credentials (Linux/macOS), %APPDATA%\beads\credentials (Windows) Override location: Set BEADS_CREDENTIALS_FILE env var. File format:
Permissions: On Linux/macOS, a warning is printed to stderr if the file is readable by group or others (mirrors ssh behavior). Set permissions with:

Dolt Version Control

Dolt maintains its own version history, separate from Git:

Auto-Commit Behavior

In embedded mode (standalone default), each bd write command creates a Dolt commit:
In server mode (orchestrator), auto-commit defaults to OFF because the server manages its own transaction lifecycle. Firing DOLT_COMMIT after every write under concurrent load causes ‘database is read only’ errors. Override for batch operations (embedded) or explicit commits (server):

Server Management (Orchestrator)

The orchestrator provides integrated Dolt server management:
Server runs on port 3307 (avoids MySQL conflict on 3306).

Standalone-to-managed-city handoff

When an existing standalone project is later added to a managed city or orchestrator, avoid letting two Dolt servers become sources of truth for the same beads database name. A common split-brain symptom is that .beads/dolt-server.port points at the old standalone server while the shell environment points bd at the managed server with BEADS_DOLT_PORT or BEADS_DOLT_SERVER_PORT. Check before migrating:
bd doctor warns when the runtime managed port differs from the local port file. The warning is intentionally diagnostic only; do not delete the local port file until the standalone store has been exported and imported into the managed server. Safe manual handoff:
After bd doctor shows one healthy store and the imported issue count is correct, archive the old local Dolt data directory instead of deleting it immediately. Keep the backup until the managed city has been pushed or otherwise snapshotted.

Shared Server Mode

On machines with multiple beads projects, each project normally starts its own Dolt server. Shared server mode runs a single Dolt server at ~/.beads/shared-server/ that serves all projects:
Benefits:
  • No port conflicts between projects (single server on port 3308, avoids orchestrator on 3307)
  • Reduced resource usage (one process instead of many)
  • Automatic database isolation (each project uses its own database name)
How it works:
  • Server state files (PID, port, lock, log) live in ~/.beads/shared-server/
  • Dolt data directory: ~/.beads/shared-server/dolt/
  • Each project’s database is stored as a subdirectory (e.g., ~/.beads/shared-server/dolt/myproject/)
  • The file lock mechanism ensures safe concurrent access from multiple projects
  • Default port is 3308 (not 3307) to avoid conflict with the orchestrator. Override with BEADS_DOLT_SERVER_PORT or dolt.port in config.yaml
Important: Each project on a shared server must have a unique prefix (database name). Two projects with the same prefix share the same database — if this happens accidentally, the project identity check will detect the mismatch and refuse to connect, preventing silent data corruption. Always use distinct prefixes when running bd init --shared-server.

Data Location (Orchestrator)

Central Dolt Server (macOS LaunchAgent)

If you do not use the orchestrator but still want a single persistent Dolt server for multiple projects on macOS, run a custom LaunchAgent instead of spawning per-project embedded instances.

Why Not brew services start dolt?

After installing Dolt with brew install dolt, the natural next step is brew services start dolt. However, the Homebrew formula runs dolt sql-server without the --config flag, and Dolt does not auto-discover config.yaml from its working directory. The config file must be passed explicitly with --config <file>.

Setup with a Custom LaunchAgent

Install Dolt and initialize its data directory. Check the installed version against the pin — Homebrew’s formula is not pinned:
Configure Dolt for port 3307:
Create the LaunchAgent plist:
Load and verify the service:
Point beads at the central server:
Manage the service:

Advanced Dolt Usage

The dolt CLI lets you operate directly on the database for power-user workflows. The data directory depends on your mode: .beads/embeddeddolt/ (embedded) or .beads/dolt/ (server).

Branching

Time Travel

Diff and Blame

Migration Cleanup

After successful migration from SQLite, you may have backup files:
These are safe to delete once you’ve verified Dolt is working:
Recommendation: Keep backups for at least a week before deleting.

See Also