Skip to main content
How to upgrade bd and keep your projects in sync.

Checking for Updates

Short Version

  1. With your current bd, sync remote-backed databases before installing the new binary: bd dolt push bd dolt pull
  2. Back up before migration: bd export --all -o .beads/backup/pre-migrate-$(date +%Y%m%d).jsonl
  3. Upgrade using the command that matches your install method.
  4. After upgrading: bd info --whats-new bd hooks install bd version
  5. If crossing a schema migration on a remote-backed database, only the designated migrator runs: bd migrate bd dolt push
Other clones should install the new binary and run bd bootstrap, not independently migrate. The full procedure is below.

Upgrading

Use the command that matches your install method.

Quick install script (macOS/Linux/FreeBSD)

PowerShell installer (Windows)

Homebrew

If you still have the old tap formula installed as bd, switch to the Homebrew core formula:

go install

From Source

After Upgrading

Important: After upgrading, update your hooks:
Why update hooks? Git hooks are versioned with bd. Outdated hooks may miss export refresh, legacy fallback, or safety fixes.

Database Migrations

After major upgrades, check for database migrations:

Remote-backed databases and multiple clones

bd refuses to silently apply pending schema migrations to a database that has a Dolt remote configured. Migrating more than one clone of a shared remote independently forks the schema, after which bd dolt pull can no longer merge — the break is silent and, across a primary-key-reshaping migration, unrecoverable (#4259). The supported flow is: one machine migrates and publishes; every other clone re-clones the migrated database. This applies to every upgrade that crosses a pending migration on a remote-backed database — the same procedure whether you are moving to a prerelease or to a stable release. The gate is state-aware by default (#4516): before blocking, bd consults the remote’s cached schema state and
  • auto-migrates when the remote is at the same schema version as this clone — no one has migrated yet, so this clone is a safe first-mover (concurrent first-movers converge to identical tables). It reminds you to bd dolt push afterwards.
  • stops and directs you to adopt (bd bootstrap) when the remote has already been migrated by another clone.
  • stops for a human decision when this clone and the remote applied different content for the same migration (a genuine fork), or when the remote’s schema state cannot be read from the cached ref.
Set BD_SMART_GATE=0 to opt out and make the gate block unconditionally. The recipes below are the explicit path and work the same in either mode. Important ordering: once the new binary is installed, a database with pending migrations is gated on every open — bd dolt push and bd dolt pull are refused too, not just bd migrate. So do all syncing with your current binary, before you install the new one. Back up before you migrate. Schema migrations assume the database matches the shape the previous migrations left behind; real databases sometimes drift (interrupted writes, tooling bugs, very old bootstraps). A JSONL export is cheap, issue-complete, and importable by any bd version:
bd export captures issues, not Dolt history or config — for a full snapshot also copy the .beads directory (or dolt backup in server mode) while no bd command is running. Single clone (including a solo user with a remote):
If bd’s remote-migrate gate blocks the run, it prints the available options — migrating here as the designated migrator, adopting the remote’s already-migrated database, or recovering a fork — and asks for an explicit operator decision. Follow the guidance it prints. For scripted or CI upgrades where nobody reads the prompt, BD_ALLOW_REMOTE_MIGRATE=1 bd migrate (any boolean true value works) declares this clone the designated migrator and bypasses the gate entirely — including its already-forked checks — so wire it into exactly one clone’s upgrade job, never all of them. Multiple clones sharing one remote:
bd bootstrap replaces the local database, so any work not pushed in step 1 is lost — that is why step 1 publishes everything first. If a clone was instead migrated independently and bd dolt pull later fails with cannot merge because table dependencies has different primary keys in its common ancestor, the schema has already forked — follow the recovery playbook: the pk-fork-refused runbook.
bd doctor includes a migration-content-skew check that flags a forked schema against the cached remote ref — a useful post-upgrade verification. It runs in both server and embedded modes.

Cross-era Upgrades

If you’re upgrading from a much older version of bd, inspect the storage layout and metadata before running the current binary. A .beads/dolt/ directory alone does not identify a legacy workspace: supported current server mode uses that directory too. Current bd evaluates explicit server metadata, the presence of that local root, and the bounded .local_version witness together. An explicit server selection is not overridden by a stale .beads/embeddeddolt/ repository. The witness is whatever bd held in its own version string when it last touched the workspace, so it may be a plain release, a release candidate, a build carrying metadata, or a Go pseudo-version; all of those are read as the version they name. A witness that is present but unreadable is not treated as a legacy marker — no pre-v1 bd could have written one — so bd warns and continues rather than refusing every command. A missing witness stays ambiguous and is still refused. Current bd refuses recognized historical SQLite and legacy Dolt layouts before opening storage or rewriting metadata. This is intentional: preserve the source and complete the matching explicit migration below. PostgreSQL and MySQL are removed backends, not supported cross-era upgrade paths. Current bd refuses metadata that selects either backend, and the sealed bridge below accepts SQLite sources only.

.beads/embeddeddolt/: direct upgrade

Upgrade the binary and run:
If the project was initialized before bd init automatically wired git origin as the Dolt remote, verify the remote after upgrading:
When the list is empty, fix it on the machine whose local database is authoritative:
Commit the resulting .beads/config.yaml change so other clones can run bd bootstrap or bd dolt pull.

Historical Dolt server mode: explicit migration

Do not run current bd init --force when .beads/dolt/ has missing metadata or persisted dolt_mode is blank/embedded. Those old embedded layouts are never current embedded storage. The same explicit path applies when metadata selects backend: dolt, dolt_mode: server and .local_version records v0.55.4 through v0.62.0. First take a native snapshot while every writer is stopped. Restore that snapshot to a disposable workspace, export it with the verified historical binary, then import the export into a fresh current project. Keep the original and snapshot unchanged until the cutover has been reviewed. The SQLite sealed-copy helper below does not start or manage a Dolt SQL server. Explicit server metadata with a v0.55.4–v0.62.0 witness is always refused, including when there is no local .beads/dolt/ root. When that root does exist, the guard admits explicit server mode only with a syntactically valid witness whose major version is 1 or newer; a missing, malformed, or pre-v1 witness fails closed. Without the local root, a missing, malformed, or non-historical witness is admitted only as a compatibility layout. The configured shared-server compatibility path applies only when persisted metadata is missing or leaves dolt_mode blank/embedded; it does not override an explicit server selection with a local root. Compatibility admission cannot prove that a workspace is modern. If you know it was created by v0.55.4 through v0.62.0, use this explicit bridge even when its witness was lost or damaged. Otherwise, follow the normal bd migrate --dry-run and bd migrate flow for an admitted server workspace.

One .beads/*.db file: sealed SQLite bridge

The old binary stored data in SQLite. The new binary uses Dolt. Recommended: use the sealed-copy bridge (requires jq): Stop every process that can write the old workspace before starting. Run this from a source checkout at the exact commit you intend to run; installed binaries do not include repository scripts. Record that commit with git rev-parse HEAD before executing the script. Download the old bd asset only from the official gastownhall/beads release and verify the asset with its published SHA-256:
On macOS or BSD, use shasum -a 256 on the downloaded archive and compare the result with that archive’s entry in checksums.txt.
For a source older than v0.49.6, also supply an authenticated v0.49.6 binary:
Verify the historical binary against its official release checksum before running the bridge. The script verifies each binary’s reported version, rejects Dolt and ambiguous layouts, retains a sealed source copy, and compares the candidate export with the canonical historical export. Activate the cutover manually only after reviewing those retained artifacts.

Troubleshooting Upgrades

Hooks out of date

Database schema changed

Recovery after upgrade

If you need to restore from a backup:
Or pull from a Dolt remote: