{"slug": "beads-bd-migration-guide-any-pre-1-0-install-sqlite-era-server-mode-dolt-jsonl-1", "title": "Beads (bd) migration guide: any pre-1.0 install (SQLite-era, server-mode Dolt, orphaned JSONL) → bd 1.0 embedded mode.", "summary": "This article provides a migration guide for upgrading any pre-1.0 version of the \"beads\" (bd) database tool—including SQLite-era, server-mode Dolt, and orphaned JSONL installs—to bd v1.0.0+ embedded mode. It details two recovery paths (JSONL import or raw Dolt SQL dump) and covers schema drift repair, auto-commit/push setup, and sync re-establishment for private repos, warning that the upgrade is not automatic and can silently produce empty databases if not handled correctly.", "body_md": "# Beads: Any-Source to Embedded Mode Migration (→ bd 1.0)\n\nHow to upgrade any pre-1.0 beads install — **SQLite-era (bd < 0.55)**,\n**server-mode Dolt (bd 0.55–0.63)**, or **orphaned JSONL export** — to\nbd v1.0.0+ (embedded Dolt, no server).\n\n## How this guide came to be\n\nI maintain beads databases across a lot of repositories — personal\nprojects, work repos, experiments, backups, and a couple of long-lived\nones that have been around since the bd 0.54 / SQLite era. When bd\n1.0.0 landed and I did a machine-wide upgrade, **every single one of\nthose repos broke at the same time**. bd 1.0 defaults to embedded mode\nand cannot read the old layouts: it doesn't understand SQLite, it\ndoesn't understand the server-mode `.beads/dolt/<dbname>/` layout, and\nrunning `bd backup restore` on the `.beads/backup/*.jsonl` files (which\nturn out to be Dolt-native `.darc` archives, not full snapshots)\nsilently produced empty databases.\n\nWorking through them one at a time, I ran into a progression of\ndifferent source states, each with its own quirks:\n\n- Repos that had a clean bd 0.62 server-mode install — the \"easy\" case,\n  but still needed careful dump-and-reload through raw `dolt` because\n  bd 1.0 can't read the old server layout.\n- Repos from older bd versions whose dolt schema was missing columns\n  (`no_history`) and tables (`custom_statuses`, `custom_types`) that\n  bd 1.0 now requires at query time — these needed manual ALTER\n  statements to repair after the dump replay.\n- Repos still on the SQLite backend (bd ≤ 0.54), including one that\n  was mid-migration from SQLite to Dolt but had stalled with an empty\n  `.beads/dolt/` directory and no actual dolt data.\n- Orphan `dolt sql-server` processes accumulating on the machine\n  because the upgrade removed the server-lifecycle commands bd 1.0\n  uses to clean them up.\n- Divergent `refs/dolt/data` git refs left over from prior installs\n  causing \"no common ancestor\" push errors when trying to re-establish\n  sync for private repos.\n\nSomewhere in the middle of that sweep I discovered that bd 1.0 actually\nships a `bd import <file.jsonl>` command that makes the SQLite case\ntrivial — you just export to JSONL, `bd init`, and `bd import`. That\nobsoleted the older SQLite → Dolt guide (which required spinning up a\ntemporary `dolt sql-server` on a chosen port). So this guide collapses\n**everything** — SQLite era, server-mode Dolt, old-schema drift,\norphaned JSONL exports, sync re-establishment — into a single\nsource-state-aware procedure. The two recovery paths below correspond\nto the two genuinely different cases; the rest of the guide is shared.\n\nIf you have more than one unmigrated repo, read the\n**\"Before you start: inventory ALL bd repos on the machine\"** section\nbefore touching any of them. Upgrading bd is machine-wide. All your\nstale repos break at once. Work through them in order.\n\nThis migration is **not automatic**. bd 1.0.0 defaults to embedded mode on a\nfresh install and cannot read a v0.62 server-mode layout, a SQLite\n`.beads/beads.db`, or the Dolt-native incremental archives (`.darc` files\nunder `.beads/backup/`). `bd backup restore` on the `.darc` files against a\nfresh embedded db reports success but produces an empty database. It's a\nsilent failure that will burn you if you don't know to look for it.\n\nTwo recovery paths:\n\n- **Path A — `bd import` from JSONL.** The simple path. Works when a current\n  `.beads/issues.jsonl` exists (bd 0.55+ auto-exports one; SQLite-era repos\n  often have one too), or when you can regenerate one from SQLite via\n  `sqlite3`. Preserves all issues, dependencies, comments, labels, and\n  memories. No raw dolt surgery.\n- **Path B — raw `dolt sql dump` + replay.** Only needed when the source is\n  server-mode Dolt **without** a usable JSONL and you can't run `bd export`\n  because bd was already upgraded. Works directly against the\n  content-addressable Dolt store, preserves everything, but has more steps\n  and more ways to go wrong.\n\nPick your path in [Step 3](#step-3-choose-your-recovery-path-a-or-b) after\ninventorying what you have.\n\n---\n\n## ⚠ STOP — Read this first if bd has already been upgraded machine-wide\n\n**If `bd version` already prints 1.0.0 or higher, DO NOT run any `bd`\ncommands against this repo until you have completed Steps 1–3 manually with\nraw `dolt` only.**\n\nThe `bd` binary is machine-wide (usually at `/usr/local/bin/bd`). When you\nupgrade it (via `brew upgrade beads` or the install script), **every repo on\nthe machine that was on bd 0.62 server mode breaks at once**. The wrong move\nnow is running `bd` commands against the stale data — bd 1.0 can't read the\n0.62 server-mode layout and will give you misleading errors like:\n\n```\nError: failed to open database: embeddeddolt: init schema:\n  creating schema_migrations table: Error 1105: no database selected\nwarning: no beads configuration found in .beads/dolt/.beads\n```\n\nor\n\n```\nError: 'bd dolt start' is not supported in embedded mode (no Dolt server)\n```\n\nThese errors do **not** mean your data is gone. Your data is at\n`.beads/dolt/<dbname>/.dolt/` (the REAL database dir — not\n`.beads/dolt/.dolt/`), and raw `dolt` can still read it fine. You just\nhave to bypass bd for the export step.\n\n### The safe order of operations when bd is already 1.0\n\n1. **Do not run `bd stop`, `bd dolt stop`, `bd backup`, `bd backup --force`,\n   `bd export`, `bd dolt push`, `bd doctor`, or any other `bd` command\n   against the unmigrated repo.** They'll either fail or make bd think the\n   repo is broken — it isn't, bd just can't see into the old layout.\n2. **Kill any stale dolt server processes manually** (Step 1 below).\n3. **Capture your data before touching anything bd-managed.** How depends\n   on what you have:\n   - **SQLite-era / has `.beads/issues.jsonl`** → **Path A**. The JSONL is\n     already your export. If you need to regenerate it from SQLite, do that\n     with plain `sqlite3` (Step 3A-2). No dolt surgery needed.\n   - **Server-mode Dolt, no usable JSONL** → **Path B**. Run `dolt sql\n     dump` directly against the content-addressable store at\n     `.beads/dolt/<dbname>/`. The dolt binary is separate from bd and reads\n     the old layout just fine.\n4. **Rename `.beads/` aside**, then run `bd init` to create a fresh\n   embedded db.\n5. **Load the data into the new embedded db:**\n   - **Path A**: `bd import <path-to-issues.jsonl>` — clean, committed,\n     auto-pushed if configured. Use this if you can.\n   - **Path B**: `dolt sql < dump.sql` against the embedded store, then\n     manually commit the working set (`dolt add -A && dolt commit -m ...`)\n     — see Step 6B + Step 7 for why this matters. Do NOT use\n     `bd backup restore` against `.beads/backup/*.jsonl` — those are\n     Dolt-native `.darc` archives and silently restore nothing.\n6. Verify with `bd stats` and `bd ready`. Now bd is safe to use.\n\n### Why this matters if you have multiple unmigrated repos\n\nIf bd got upgraded while you had several repos still on 0.62 server mode,\nevery one of them is in this broken-but-recoverable state. The dolt binary is\nseparate from bd and can still read the old server-mode data at\n`.beads/dolt/<dbname>/.dolt/` — so the data is never at risk as long as you\ndon't run destructive `bd` commands against it. Go repo by repo, use raw dolt\nfor the export step only, and each repo will come up clean on the new embedded\nbackend.\n\nIf bd has NOT been upgraded yet (still v0.62.x), you can follow the guide top\nto bottom normally — `bd dolt stop`, `bd export`, etc. will all work because\nbd still understands server mode at that point.\n\n---\n\n## Why migrate\n\n- **bd 1.0 stable release.** v1.0.0 completes the embedded Dolt migration\n  that started in v0.55. Server mode still works but isn't the default\n  anymore and has known version-skew issues.\n- **No server lifecycle.** Embedded mode kills the separate `dolt sql-server`\n  process entirely. No port coordination, no stale server pids, no\n  \"`bd dolt push` spawns a fresh process on a different port than the running\n  server\" class of bugs. That last one was especially annoying.\n- **Simpler layout.** One binary, one lock file, one data directory.\n\n**Tradeoff:** Embedded mode is single-writer (enforced via file lock). Multiple\nconcurrent `bd` processes serialize through the lock. For Thrum's 14-agent\ntopology this is fine — bd operations are fast and mostly serial from the\ncoordinator. For heavy concurrent workloads, stay on server mode with\n`dolt.mode: server` explicit in `config.yaml`.\n\n## Prerequisites\n\n- Any pre-1.0 bd install. Supported source states:\n  - **SQLite-era** (bd ≤ 0.54): `.beads/beads.db` SQLite file, often with a\n    `.beads/issues.jsonl` export alongside it.\n  - **Transitional SQLite → Dolt** (bd 0.55 when migration stalled):\n    `.beads/beads.db` plus an empty `.beads/dolt/config.yaml` but no actual\n    dolt data directory.\n  - **Server-mode Dolt** (bd 0.55–0.63): `.beads/dolt/<dbname>/.dolt/` with\n    a separate `dolt sql-server` process.\n  - **JSONL only**: orphaned `.beads/issues.jsonl` from a deleted or\n    corrupted database.\n- `dolt` CLI 1.81+ (only needed for **Path B**; `dolt dump` / `dolt sql`)\n- `sqlite3` CLI (only needed for **Path A** when migrating a SQLite-era\n  source that has no `.beads/issues.jsonl`)\n- A working git checkout of the project repo\n- Enough disk space to keep `.beads/` aside as a safety copy\n\nVerify versions before starting:\n\n```bash\nbd version\ndolt version\nwhich bd\nwhich dolt\n```\n\nThe paths tell you which channel to use for upgrades:\n\n- `/usr/local/bin/bd` → installed via the [quick-install script](https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh)\n- `/opt/homebrew/bin/bd` or `/usr/local/homebrew/bin/bd` → installed via Homebrew\n- `/opt/homebrew/bin/dolt` → installed via Homebrew\n\n## Before you start: inventory ALL bd repos on the machine\n\nIf you have multiple bd 0.62 repos on this machine, **upgrading bd is\nmachine-wide** and breaks all of them at once. Before migrating any single\nrepo, build a list of every stale install so you can work through them\nin order.\n\nA minimal discovery one-liner — lists every `.beads/` directory\nunder your common dev roots and classifies it:\n\n```bash\nfor beads in $(find ~/dev ~/work /srv -type d -name .beads 2>/dev/null); do\n  if   [ -f \"$beads/redirect\" ];            then mode=redirect\n  elif [ -d \"$beads/embeddeddolt\" ];        then mode=embedded\n  elif [ -d \"$beads/dolt\" ];                then mode=server\n  elif [ -f \"$beads/metadata.json\" ];       then mode=unknown\n  else                                          mode=nonbd\n  fi\n  printf '%-9s %s\\n' \"$mode\" \"$beads\"\ndone\n\n# Cross-reference orphan dolt servers with their data directories:\nfor pid in $(pgrep -f 'dolt sql-server'); do\n  cwd=$(lsof -p \"$pid\" 2>/dev/null | awk '$4==\"cwd\"{print $NF; exit}')\n  echo \"PID $pid  cwd=$cwd\"\ndone\n```\n\nMode meanings:\n\n| Mode | Meaning | Action |\n|---|---|---|\n| `server` | Old bd 0.62 layout with `.beads/dolt/`. Needs migration. | Run this guide. |\n| `embedded` | Already migrated to bd 1.0 `.beads/embeddeddolt/`. | Done. |\n| `redirect` | Worktree pointing at another `.beads/` via `.beads/redirect` file. | Follows the target repo's state. |\n| `unknown` | bd-managed (has metadata.json) but neither `dolt/` nor `embeddeddolt/`. | Investigate — partial init? |\n| `nonbd` | Directory happens to be named `.beads` but is not a bd install. | Ignore. Hidden by default; use `--show-nonbd` to list. |\n\nThe script also lists every orphan `dolt sql-server` process and\ncross-references each one with the repo that owns it. You can see at a\nglance which repos still have a stale background server and which processes\nare pointing at deleted or trashed paths that can be killed outright.\n\n**Pick a migration order:**\n\n1. Repos you actively work in, most important first\n2. Then the rest, in any order\n\nOrphan processes for already-deleted repos (e.g. cwd inside\n`~/.Trash/dolt` or a path that `ls` says doesn't exist) are safe to\nkill immediately — they're holding nothing useful.\n\n---\n\n## Step 1: Stop any running bd / dolt server\n\n**Critical.** The old bd server can't be holding the dolt database open\nwhen you dump it.\n\n```bash\n# If bd is still 0.62.x (has `bd dolt stop`):\nbd dolt stop 2>/dev/null || true\n\n# If bd has already been upgraded to 1.0+, skip the bd command entirely\n# and go straight to killing orphan dolt processes.\n```\n\n### Orphan `dolt sql-server` processes across the machine\n\nOn a machine with multiple bd 0.62 repos, upgrading to 1.0 leaves\n**one orphan `dolt sql-server` per unmigrated repo** running in the\nbackground. bd 1.0 has no concept of the server lifecycle, so it can't\nclean them up. They keep running indefinitely and can block dolt dumps if\nthey still hold a file lock on the data directory.\n\nList them:\n\n```bash\nps aux | grep '[d]olt sql-server'\n```\n\nTypical output looks like:\n\n```\nyouruser  <pid1>  ... /opt/homebrew/bin/dolt sql-server -H 127.0.0.1 -P <port1>\nyouruser  <pid2>  ... /opt/homebrew/bin/dolt sql-server -H 127.0.0.1 -P <port2>\n...\n```\n\nFigure out which process belongs to which repo by checking its working\ndirectory:\n\n```bash\nfor pid in $(pgrep -f 'dolt sql-server'); do\n  cwd=$(lsof -p $pid 2>/dev/null | awk '$4==\"cwd\"{print $NF; exit}')\n  echo \"PID $pid  cwd=$cwd\"\ndone\n```\n\n**For this migration**, kill ONLY the process whose `cwd` is the repo you're\nmigrating. Leave the others running until you migrate their repos — killing\nthem now just means bd would fail to read their data if it tried (which it\nwon't, since you're not running bd in those repos until they migrate).\n\n```bash\nkill <pid-for-this-repo>\n```\n\nVerify:\n\n```bash\nps aux | grep '[d]olt sql-server'  # should no longer show this repo's pid\n```\n\n### If you have many repos to migrate\n\nUse the discovery one-liner in the **\"Before you start\"** section to\ninventory every `.beads/` directory before touching any of them. Work\nthrough the `server`-mode entries one at a time, killing each repo's\norphan `dolt sql-server` process as part of its own migration.\n\n## Step 2: Locate the real database directory\n\nThis is where every manual recovery goes wrong. In bd 0.62 server mode, the\ndata layout is:\n\n```\n.beads/\n├── dolt/                     # bd's dolt data root\n│   ├── config.yaml           # dolt server config\n│   ├── .dolt/                # ← server-level config (empty branches)\n│   └── thrum/                # ← THIS is the actual database\n│       └── .dolt/            # ← THIS is the real content-addressable store\n│           └── noms/         # ← dolt data blocks\n```\n\n**The database lives at `.beads/dolt/thrum/`, not `.beads/dolt/`.** The\nouter `.beads/dolt/.dolt/` is just the dolt-sql-server workspace config with\n`\"branches\": {}` — it's not a Dolt database. Run `dolt sql` or `dolt status`\nfrom `.beads/dolt/` and you'll get confusing errors like\n`database not found: thrum` (show databases lists it, but use fails) or\n`non-string column in 'SELECT active_branch()'`.\n\nConfirm the real location:\n\n```bash\nls .beads/dolt/<project-name>/.dolt/\n# Should contain: noms/, repo_state.json, config.json\n```\n\nReplace `<project-name>` with your bd database name (check the\n`\"dolt_database\"` field in `.beads/metadata.json`).\n\n### Git worktrees: per-worktree migration vs shared DB via redirect\n\nIf your project has git worktrees that each have their own `.beads/dolt/`\ndirectory, you have two options post-migration:\n\n1. **Per-worktree embedded dbs.** Run this whole guide inside each worktree\n   independently. Each ends up with its own `.beads/embeddeddolt/<prefix>/`\n   — no shared state, no coordination cost, but diverged issue histories\n   per branch.\n\n2. **Shared db via `.beads/redirect`** (recommended for most setups).\n   Migrate only the main repo, then in each worktree create a\n   `.beads/redirect` file pointing at the main repo's `.beads/` directory.\n   All worktrees read/write the same database:\n\n   ```bash\n   # In the main repo (already migrated to embedded):\n   MAIN_BEADS=\"$(cd <main-repo>/.beads && pwd)\"\n\n   # In each worktree:\n   cd <worktree>\n   rm -rf .beads         # remove the old server-mode .beads/dolt/\n   mkdir .beads\n   echo \"$MAIN_BEADS\" > .beads/redirect\n   bd ready              # sanity check — should list the main repo's issues\n   ```\n\n   This is the bd 1.0 worktree pattern (see `docs/ADVANCED.md` in the\n   beads repo: \"Database Redirects\"). Single-level redirects only; the\n   target `.beads/` must exist and have a valid embedded database.\n\nIf you went with option 2, each worktree's old `.beads/dolt/` can be safely\ndeleted after the main repo migration is verified — no safety backups needed\nfor the worktree deletions, since the data all lives in the main repo now.\n\n## Step 3: Choose your recovery path (A or B)\n\nThe `.beads/backup/` directory contains dolt-native incremental archives\n(`.darc` files plus a manifest referencing dolt commit hashes). These are\n**NOT full database snapshots**. `bd backup restore` on them against a fresh\nembedded db will report success and restore nothing. Don't rely on them\nas your only backup. The two working paths are:\n\n| Path | When to use | Mechanism | Preserves |\n|---|---|---|---|\n| **A** | SQLite-era source, OR you have a current `.beads/issues.jsonl`, OR you can regenerate one from SQLite | `bd init` + `bd import <file.jsonl>` — cleanest, one command to load everything | Issues, dependencies, comments, labels, memories. Commits automatically under auto-commit=on. |\n| **B** | Server-mode Dolt without a usable JSONL, and you can't run `bd export` because bd was already upgraded | Raw `dolt sql dump` from the content-addressable store, then `dolt sql <` replay into the fresh embedded db | Everything in the source Dolt — full row-level fidelity, but raw; requires manual schema-drift fixes and a manual `dolt commit` on the working set (Step 6B) |\n\n**Path A is strongly preferred** whenever a JSONL export is available or can\nbe produced. It's simpler, auto-commits, and avoids schema-drift surprises\nfrom very old bd versions (see Troubleshooting: \"`bd ready` errors with\ncolumn `no_history` could not be found\"). If you have a JSONL, use it.\n\n### Step 3.1: Move the entire `.beads/` directory aside (filesystem snapshot) — COMMON\n\nSame for both paths. This is your ground-truth recovery point if anything\ngoes wrong later.\n\n```bash\ncp -a .beads .beads.server-backup\n# or (saves space, only if you're confident):\n# mv .beads .beads.server-backup\n```\n\nKeep the safety copy until the new embedded install has been exercised\nfor at least a day.\n\n### Step 3A: Produce a JSONL export (PATH A)\n\nIf `.beads.server-backup/issues.jsonl` already exists and is current —\nline count matches the source database's issue count — you can skip ahead to\n[Step 6A](#step-6a-import-the-jsonl-into-the-new-embedded-database-path-a).\nOtherwise regenerate it.\n\n#### Verify an existing `.beads/issues.jsonl`\n\n```bash\n# Count lines (= number of issue records):\nwc -l .beads.server-backup/issues.jsonl\n\n# Spot-check against the source database if possible. For SQLite-era:\nsqlite3 .beads.server-backup/beads.db \"select count(*) from issues;\"\n\n# For server-mode dolt — count via the old store:\ncd .beads.server-backup/dolt/<dbname>\ndolt sql -q \"select count(*) from issues;\"\n```\n\nIf the counts match, the JSONL is usable — proceed to Step 4. If it's\nstale or missing, regenerate it:\n\n#### Regenerate the JSONL from SQLite (bd ≤ 0.54 source)\n\nbd 1.0 can read its own `bd export` JSONL format but can't read the old\nSQLite directly. The re-export path is plain `sqlite3`:\n\n```bash\nsqlite3 .beads.server-backup/beads.db \"SELECT json_object(\n  'id', id,\n  'title', title,\n  'description', description,\n  'design', coalesce(design, ''),\n  'acceptance_criteria', coalesce(acceptance_criteria, ''),\n  'notes', coalesce(notes, ''),\n  'status', status,\n  'priority', priority,\n  'issue_type', issue_type,\n  'assignee', coalesce(assignee, ''),\n  'created_at', created_at,\n  'updated_at', updated_at,\n  'closed_at', closed_at,\n  'close_reason', close_reason\n) FROM issues ORDER BY created_at;\" \\\n  > .beads.server-backup/issues.jsonl\n\nwc -l .beads.server-backup/issues.jsonl   # should equal SQLite issue count\n```\n\nThis gives you a minimal but `bd import`-compatible JSONL. Dependencies and\ncomments need separate SELECTs if you want them — in practice most SQLite-era\nrepos are small enough (< 100 issues) that losing dep/comment history is\nacceptable. If you do need them, add `dependencies` and `comments` table\nSELECTs following the same pattern.\n\n#### Regenerate the JSONL from server-mode Dolt (bd 0.55–0.63 source)\n\nIf the old install has a `.beads/issues.jsonl` exported by `bd export` at\nany point, use that file — it already has the full schema. If you only have\nthe Dolt data directory and the JSONL is missing, use Path B instead. Raw\ndolt → JSONL conversion isn't worth the effort when `dolt sql dump` works\nend-to-end.\n\n### Step 3B: Produce a full SQL dump via raw dolt (PATH B)\n\nThe fallback path. `dolt dump` writes a complete SQL file — every table\nschema and every row.\n\n> **⚠ Do NOT write the dump to a shared path like `/tmp/doltdump.sql`.**\n> If you're migrating more than one repo — even sequentially, let alone in\n> parallel — every repo would dump to the same file and clobber each other.\n> In a real multi-repo migration I ran, a 3 MB dump was silently overwritten\n> by a smaller dump from a different repo mid-verification because another\n> session was running a parallel migration to the same path.\n>\n> **Always write the dump INSIDE `.beads.server-backup/` with a repo-scoped\n> name.** That way there's no collision with other repos and the dump gets\n> cleaned up automatically when you `rm -rf .beads.server-backup/` in\n> Step 12.\n\n```bash\ncd .beads.server-backup/dolt/<project-name>\n\n# Derive the repo name from git (or set REPO_NAME manually)\nREPO_NAME=$(git -C ../../.. rev-parse --show-toplevel 2>/dev/null | xargs basename)\nREPO_NAME=${REPO_NAME:-$(basename \"$PWD\")}\n\n# Write the dump into .beads.server-backup/ (two levels up from dolt/<dbname>/)\ndolt dump -f -fn \"../../${REPO_NAME}-bd-dump.sql\"\n\n# Output: \"Successfully exported data.\"\nDUMP_PATH=\"$(cd ../.. && pwd)/${REPO_NAME}-bd-dump.sql\"\nls -lh \"$DUMP_PATH\"\nhead -5 \"$DUMP_PATH\"\n# Should start with: CREATE DATABASE IF NOT EXISTS `<project-name>`; USE `<project-name>`;\n```\n\nVerify the dump contains your current state by grepping for a recent issue\nID you know exists:\n\n```bash\ngrep -c \"your-issue-id\" \"$DUMP_PATH\"\n```\n\nHold onto the `$DUMP_PATH` value — [Step 6B](#step-6b-load-the-dolt-sql-dump-into-the-new-embedded-database-path-b) needs it.\n\n## Step 4: Upgrade bd and dolt\n\nUse the channel that matches your current install.\n\n### bd via quick-install script (path: `/usr/local/bin/bd`)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash\n```\n\nThe installer detects your platform, downloads and verifies the release\nchecksum, installs the binary in place (overwrites `/usr/local/bin/bd`), and\ncreates a `beads` alias.\n\n### bd via Homebrew\n\n```bash\nbrew upgrade beads\n```\n\n### dolt via Homebrew\n\n```bash\nbrew upgrade dolt\n```\n\n### Verify\n\n```bash\nbd version   # should print 1.0.0 or later\ndolt version # should print 1.86.0 or later\n```\n\n## Step 5: Initialize the new embedded database\n\n`bd init` creates a fresh `.beads/` directory in embedded mode. Since the\nold `.beads/` has been moved aside, bd sees nothing and initializes cleanly.\n\n```bash\ncd <project-root>\nbd init --prefix=<your-prefix> --non-interactive --role=maintainer\n```\n\nReplace `<your-prefix>` with your original issue prefix (e.g. `thrum`,\n`my-project`, `MYPROJECT`). Check `.beads.server-backup/metadata.json` if\nyou can't remember it.\n\n`bd init` will:\n\n- Create `.beads/embeddeddolt/<prefix>/.dolt/` (the new embedded store)\n- Create `.beads/metadata.json` with `\"dolt_mode\": \"embedded\"`\n- Create `.beads/config.yaml` (template with all options commented out)\n- Install git hooks (pre-commit, post-merge, etc.)\n- Add a beads section to `CLAUDE.md` / `AGENTS.md` (see Step 9 caveat)\n- Register a Claude Code SessionStart/PreCompact hook in `.claude/settings.json`\n- Set a dolt remote pointing at the current git origin\n\nVerify the init:\n\n```bash\nbd version\nbd stats\n# Expected: 0 total issues (the db is empty at this point)\n```\n\n## Step 6: Load your data into the new embedded database\n\n### Step 6A: Import the JSONL into the new embedded database (PATH A)\n\nFrom the project root, with the fresh embedded db in place:\n\n```bash\ncd <project-root>\nbd import .beads.server-backup/issues.jsonl\n# Output: \"Imported N issues from .beads.server-backup/issues.jsonl\"\n```\n\n`bd import` is the bd 1.0 replacement for the old `bd init --from-jsonl`\nflow. It creates or upserts issues from the file, auto-detects memory\nrecords (`\"_type\":\"memory\"`) and imports them as persistent memories\n(equivalent to `bd remember`), then commits the new rows to the embedded\nDolt working set. If you set `dolt.auto-commit=on` before importing\n(recommended — see Step 7), the import commits automatically. Otherwise it\nsits in the working set and you'll need to commit it manually like Path B\n(see Step 6C).\n\nVerify the import:\n\n```bash\nbd stats\nbd ready\nbd show <known-issue-id>\n```\n\nIf `bd ready` and `bd show` both work and the issue count matches the\nsource, **skip ahead to [Step 7](#step-7-verify-dolt-auto-commit-and-commit-the-working-set-if-needed)**.\nPath A is done for this repo.\n\n### Step 6B: Load the dolt SQL dump into the new embedded database (PATH B)\n\nThe new embedded db is a standard dolt database, so `dolt sql` works against\nit directly. Load the dump produced in Step 3B:\n\n```bash\ncd .beads/embeddeddolt/<your-prefix>\n# $DUMP_PATH was set in Step 3B; the file lives inside .beads.server-backup/\ndolt sql < \"$DUMP_PATH\"\n# Silent on success. Takes 5–30 seconds for a typical project.\n```\n\n> **⚠ Database name mismatch when prefix contains a dash.** If your\n> prefix has a dash (e.g. `my-project`), the dump's `CREATE DATABASE\n> IF NOT EXISTS` / `USE` statements use the dashed name — that's what the\n> old server-mode dolt used — but `bd init` may have created the embedded\n> db under an underscore-normalized name (e.g. `my_project`) or a short name\n> like `MP`. The dump will then fail silently or create an unlinked orphan\n> database. Fix with a one-liner sed on the dump before loading:\n>\n> ```bash\n> # Edit the dump's CREATE DATABASE / USE lines to match the embedded db name.\n> # Replace <old-dash-name> and <new-name> with the actual names for your repo:\n> sed -i '' 's/`<old-dash-name>`/`<new-name>`/g' \\\n>   .beads.server-backup/<your-repo>-bd-dump.sql\n> ```\n>\n> Then re-run `dolt sql < $DUMP_PATH`. Verify with `dolt sql -q \"show\n> databases;\"` — there should be exactly one project database.\n\nVerify the load worked:\n\n```bash\ndolt sql -q \"select count(*) from issues;\"\n# Should match the count from the old database\n\ndolt sql -q \"select id, status, title from issues where id like '<your-prefix>%' order by id;\"\n# Substitute your own recent-work prefix\n```\n\n### Step 6C: Patch schema drift from very old bd versions (PATH B, old sources only)\n\nIf the source dolt data came from a very old bd version (pre-0.60ish),\nthe loaded schema will be missing columns and tables that bd 1.0 requires\nat query time. Symptoms:\n\n```bash\nbd ready\n# Error: get ready work: fetch issues: get issues by IDs from issues:\n#   Error 1105: column \"no_history\" could not be found in any table in scope\n```\n\nor\n\n```bash\nbd close <id>\n# Error: resolving ID <id>: failed to search issues: search wisps (merge):\n#   search wisps: Error 1105: column \"no_history\" could not be found in any table in scope\n```\n\nThe dump replayed the old CREATE TABLE DDL, which overwrote the fresh\nbd 1.0 schema with the old one. Patch in place against the embedded store:\n\n```bash\ncd .beads/embeddeddolt/<your-prefix>\n\n# Add missing columns to issues and wisps:\ndolt sql -q \"ALTER TABLE issues ADD COLUMN no_history TINYINT(1) DEFAULT 0;\"\ndolt sql -q \"ALTER TABLE wisps ADD COLUMN no_history TINYINT(1) DEFAULT 0;\"\n\n# Add missing tables (bd 1.0 expects them to exist, even if empty):\ndolt sql -q \"CREATE TABLE IF NOT EXISTS custom_statuses (\n  name varchar(64) NOT NULL,\n  category varchar(32) NOT NULL DEFAULT 'unspecified',\n  PRIMARY KEY (name)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin;\"\n\ndolt sql -q \"CREATE TABLE IF NOT EXISTS custom_types (\n  name varchar(64) NOT NULL,\n  PRIMARY KEY (name)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin;\"\n```\n\nThe leftover `crystallizes` and `quality_score` columns from the old\n`issues` schema are harmless — bd 1.0 ignores unknown columns. Leave them\nalone; dropping them is unnecessary risk.\n\nTo diff an old-source schema against a known-good bd 1.0 schema (e.g.\nfrom a freshly-initialized reference repo):\n\n```bash\n(cd <reference-repo>/.beads/embeddeddolt/<prefix> && dolt sql -q \"describe issues;\") > /tmp/good.txt\n(cd .beads/embeddeddolt/<your-prefix> && dolt sql -q \"describe issues;\") > /tmp/mine.txt\ndiff /tmp/good.txt /tmp/mine.txt\n```\n\nRe-run `bd ready` and `bd close <id>` after the ALTERs to confirm the\ndrift is fixed.\n\n## Step 7: Verify dolt auto-commit and commit the working set if needed\n\n**bd 1.0 defaults `dolt.auto-commit` to `off`.** After a Path B migration\n— or any Path A migration where you didn't set auto-commit *before*\nrunning `bd import` — the loaded rows are sitting in the dolt **working\nset**. They're queryable by bd, but never committed to dolt history and\nnever pushed to any remote. Subsequent bd writes will also stay in the\nworking set until you either turn auto-commit on or commit manually.\n\nFix in this order:\n\n```bash\ncd <project-root>\n\n# 1. Tell bd to commit to dolt on every write from now on:\nbd config set dolt.auto-commit on\n\n# 2. Commit the existing working set (the Path B data or pre-auto-commit Path A data):\ncd .beads/embeddeddolt/<your-prefix>\ndolt status   # should show modified tables: issues, wisps, events, etc.\ndolt add -A\ndolt commit -m \"migrate: import historical data from bd <old-version> <mode>\"\ndolt log --oneline | head -5   # should now show your migrate commit at HEAD\ncd -\n```\n\n> **auto-commit values:** `bd config set dolt.auto-commit <value>` accepts\n> `off`, `on`, or `batch`. Default is `off`. `on` commits synchronously\n> after every bd write. `batch` defers commits to `bd dolt commit` but\n> flushes on SIGTERM/SIGHUP. For migrated repos, use `on` unless you have\n> a specific reason to batch.\n\nNow verify bd can read the restored data end-to-end:\n\n```bash\ncd <project-root>\nbd stats\nbd ready\nbd show <some-issue-id>\nbd migrate   # confirms schema version is current\n```\n\nAll of these should succeed. `bd migrate` with no subcommand is a schema\ncheck — no-op if everything is current — and should print:\n\n```\nDolt database version: 1.0.0\n✓ Version matches\n✓ All metadata fields present\n```\n\n## Step 8: Configure backup and sync per repo\n\nbd 1.0 has two sync mechanisms that got conflated in pre-1.0 docs:\n\n- **`backup.git-push`** (`.beads/config.yaml`) — enables JSONL auto-export\n  to `.beads/backup/*.jsonl` and **git push of those files** when a git\n  remote is detected. Useful when beads data should travel as tracked files\n  in the repo. Leave `false` if you already have an external backup script\n  handling off-machine backup.\n- **`dolt.auto-push`** (`bd config set`) — enables background **dolt push**\n  of the embedded store to a hidden `refs/dolt/data` git ref on the remote.\n  This is the native Dolt sync path; the hidden ref is invisible to\n  `git log` / `git clone` but travels with `git push --all` /\n  `git fetch origin 'refs/dolt/*'`. Interval is controlled by\n  `dolt.auto-push-interval` (default 5m). Useful for private repos where you\n  want beads history to sync across machines without living in tracked files.\n\n**Public repos / external backup workflow** (e.g. thrum):\n\n```yaml\n# .beads/config.yaml\nbackup:\n  git-push: false\n```\n\nDon't set `dolt.auto-push=true` on a public repo unless you want the\nhidden dolt ref published to the public git remote.\n\n**Private repos with no external backup script** (most personal\nrepos):\n\n```bash\n# .beads/config.yaml:\nbackup:\n  git-push: true\n\n# And via bd config (stored in-db):\nbd config set dolt.auto-push true\n# (dolt.auto-commit=on was already set in Step 7)\n```\n\n**Initial push to establish the remote baseline:**\n\nAfter `bd init` auto-configures the dolt remote and you commit the working\nset in Step 7, run one initial manual push. `dolt.auto-push` only fires on\nan interval, so the remote won't have your data until the first scheduled\npush — don't wait for that:\n\n```bash\ncd .beads/embeddeddolt/<your-prefix>\ndolt push origin main\n# Expect: \"[new branch] main -> main\" on first run\n```\n\nIf the push fails with `unknown push error; no common ancestor`, the remote\nalready has a divergent `refs/dolt/data` ref from a prior install. See\nTroubleshooting: \"dolt push fails with 'no common ancestor'\".\n\n**Verify the remote ref:**\n\n```bash\ncd <project-root>\ngit ls-remote origin 'refs/dolt/*'\n# Should show a single hash next to refs/dolt/data\n```\n\n## Step 9: Clean up `CLAUDE.md` / `AGENTS.md` integration\n\n`bd init` adds a \"Beads Issue Tracker\" section to `CLAUDE.md` (between\n`<!-- BEGIN BEADS INTEGRATION -->` and `<!-- END BEADS INTEGRATION -->`\nmarkers). In embedded mode, the boilerplate session-close workflow in that\nsection references `bd dolt push`, which is **server-mode only**:\n\n```bash\ngit pull --rebase\nbd dolt push        # ← invalid in embedded mode\ngit push\n```\n\nRemove that line, or the whole section if you maintain your own. It's safe\nto edit inside the markers — bd won't regenerate the section on subsequent\n`bd init` runs unless you pass `--force`.\n\n## Step 10: Smoke test\n\n```bash\n# Read path\nbd ready\nbd show <some-open-issue>\n\n# Write path (create a throwaway test issue)\nbd create --title=\"migration smoke test\" --type=task --priority=4\n# Note the ID, then:\nbd close <that-id>\n\n# Dependency path\nbd dep --help\n```\n\n## Step 11: Audit your agent memory for stale bd guidance\n\n**This step is easy to skip and will bite you later.** If you have any AI\nagent with persistent memory — `MEMORY.md` files, Claude Code memory,\n`bd remember` entries, CLAUDE.md project instructions, user global CLAUDE.md,\nnotes in `.claude/`, or equivalent in other runtimes — those memory stores\nalmost certainly contain bd 0.62-era commands that won't work anymore. Future\nsessions will confidently quote them and burn time debugging why `bd dolt push`\nfails or why `bd import` doesn't exist.\n\nGrep your memory stores for stale bd patterns and fix each hit:\n\n```bash\n# Adjust paths to match where your agent keeps persistent memory.\n# Include global agent definitions — they apply to ALL projects on the\n# machine and almost always contain stale bd guidance.\ngrep -rn \"bd backup --force\\|bd import\\|bd sync\\|bd onboard\\|bd dolt push\\|bd dolt start\\|bd dolt stop\\|bd dolt status\\|bd dolt show\" \\\n  ~/.claude/projects/*/memory/ \\\n  ~/.claude/CLAUDE.md \\\n  ~/.claude/*.md \\\n  ~/.claude/agents/*.md \\\n  ~/.codex/ \\\n  ~/.config/opencode/ \\\n  .claude/ \\\n  CLAUDE.md \\\n  AGENTS.md \\\n  .beads/memories/ 2>/dev/null\n```\n\n### ⚠ Global agent definitions: hold until ALL repos on the machine are migrated\n\nFiles under `~/.claude/agents/*.md` (and equivalent global agent definitions\nin other runtimes) apply to **every project on the machine**, not just this\none. If you still have other repos stuck in bd 0.62 server mode,\n**updating the global files now will break them** — they depend on the old\ncommands like `bd sync` and `bd dolt push`.\n\nTwo safe orderings:\n\n1. **Migrate all repos first, then update global files.** Run the discovery\n   script (Step 1) to find every stale repo, migrate each one, then do the\n   global memory audit last. Cleaner if you have ≤10 repos.\n2. **Update global files immediately, but annotate them** with \"requires\n   bd 1.0+ embedded mode; see\n   `dev-docs/beads_server_to_embedded_migration_guide.md`\". Unmigrated\n   repos will still break, but you won't accumulate drift across future\n   sessions.\n\nProject-level files (`.claude/`, project CLAUDE.md, `AGENTS.md`) are\n**always safe to update immediately** — they only affect this repo, which\nis now on bd 1.0.\n\nPatterns to fix:\n\n| Stale (bd 0.62) | Replace with (bd 1.0+) |\n|---|---|\n| `bd backup --force` | `bd export --all -o <path>` |\n| `bd import < file.jsonl` (shell-redirect form) | `bd import file.jsonl` (positional arg — the command still exists in 1.0, syntax changed) |\n| `bd sync` | Removed — no replacement, delete the line |\n| `bd onboard` | `bd prime` |\n| `bd dolt push` / `bd dolt pull` | Removed in embedded mode. Delete from session-close workflows. For private repos wanting dolt sync, use `bd config set dolt.auto-push true` or run `dolt push origin main` directly from `.beads/embeddeddolt/<prefix>`. |\n| `bd dolt start` / `bd dolt stop` | Removed in embedded mode |\n| `bd dolt status` / `bd dolt show` | Removed in embedded mode; use `bd stats` and `bd migrate` |\n| `bd doctor` (as a health check) | `bd migrate` (no args) — `bd doctor` is a no-op placeholder in embedded mode |\n| \"dolt server on port X\" | No server. Single binary, file lock. |\n| `.beads/dolt/` as the data path | `.beads/embeddeddolt/<prefix>/.dolt/` |\n\nAlso update:\n\n- Any **session-close scripts** that call `bd dolt push` before `git push`.\n- Any **worktree setup scripts** that initialize bd via `bd import`.\n- Any **tooling notes** that describe the beads backend as \"Dolt via sql-server\".\n- Any **backup scripts** that pipe through `bd backup --force` — these\n  fail silently with `|| true` and produce stale backups without telling you.\n\nIf your memory system has index files (e.g. `MEMORY.md` listing topic\nfiles), update the one-line descriptions so future memory-recall picks up\nthe refreshed content rather than the stale entries.\n\n## Step 12: Clean up the safety copy\n\n**Only after** you've exercised the new install for at least a day and are\nconfident nothing is missing:\n\n```bash\nrm -rf .beads.server-backup\n# If you also took a .beads.pre-migration/ copy (double-safety), remove it too:\nrm -rf .beads.pre-migration 2>/dev/null || true\n```\n\nThe dump file lives inside `.beads.server-backup/` (per Step 3b), so\nremoving the directory removes the dump too. No `/tmp/` cleanup needed.\n\nKeep them longer if you have any doubt. Disk is cheap; re-migrating is not.\n\n### .gitignore the safety copies\n\nBefore committing anything post-migration, add the safety copies to your\nignore list so they don't get accidentally staged:\n\n```bash\ncat >> .git/info/exclude <<'EOF'\n# Beads 0.62 → 1.0 migration safety copies (see migration guide Step 12)\n.beads.server-backup/\n.beads.pre-migration/\nEOF\n```\n\n`.git/info/exclude` (per-clone, untracked) is better than `.gitignore`\nfor temporary entries — otherwise the `.gitignore` entry lingers in\nhistory forever.\n\n---\n\n## Troubleshooting\n\n### `bd doctor` says \"No dolt database found\" but one exists\n\n`bd doctor` in 1.0.0 isn't supported in embedded mode. It prints a\nplaceholder pointing you at manual checks:\n\n```\nNote: 'bd doctor' is not yet supported in embedded mode.\n  • Verify database exists:  ls -la .beads/embeddeddolt/\n  • Check bd version:        bd version\n  • Reinitialize if needed:  bd init --force\n```\n\nUse `bd migrate` (no args) instead — it verifies the schema version and\nmetadata fields.\n\n### `bd dolt start` / `bd dolt push` / `bd dolt status` all error\n\nExpected. Embedded mode has no dolt server, so all\n`bd dolt <server-lifecycle>` commands return:\n\n```\nError: 'bd dolt ...' is not supported in embedded mode (no Dolt server)\n```\n\nThat includes `bd dolt push`. For dolt-native off-machine backup in\nembedded mode, use `bd backup sync` (writes to a local directory or DoltHub\nremote) or run `dolt` directly against the embedded store.\n\n### `bd backup restore <path>` succeeds but database is empty\n\nThe `.beads/backup/*.jsonl` files from a v0.62 server-mode install are\n**Dolt archive `.darc` format**, not full snapshots. `bd backup restore`\ndoesn't extract row data from them against a fresh embedded db — it reports\nsuccess and inserts nothing. This one is especially annoying to discover\nafter you thought you were done.\n\nUse one of:\n\n- **Path A** (preferred): regenerate a JSONL via `bd export` (if the source\n  bd version can still open the database) or via raw `sqlite3` for\n  SQLite-era sources, then `bd import` it. See Step 3A and Step 6A.\n- **Path B**: raw `dolt sql dump` against the content-addressable store\n  directly. See Step 3B and Step 6B.\n\n### `bd ready` errors with `column \"no_history\" could not be found`\n\nFull error:\n\n```\nError: get ready work: fetch issues: get issues by IDs from issues:\n  Error 1105: column \"no_history\" could not be found in any table in scope\n```\n\nPath B only, and only when the source dolt data came from a very old bd\nversion (pre-0.60ish). The dump replayed the old CREATE TABLE DDL, which\noverwrote the fresh bd 1.0 schema with the old one. Fix with the ALTER +\nCREATE TABLE statements in\n[Step 6C](#step-6c-patch-schema-drift-from-very-old-bd-versions-path-b-old-sources-only).\n\nWrite operations show the same symptom:\n\n```\nError: resolving ID <id>: failed to search issues: search wisps (merge):\n  search wisps: Error 1105: column \"no_history\" could not be found in any table in scope\n```\n\nSame fix — the `wisps` table needs the column too.\n\n### `dolt push origin main` fails with `unknown push error; no common ancestor`\n\nThe remote already has a `refs/dolt/data` ref from a prior install. The\nfreshly-migrated local dolt history has no commits in common with it.\n\nFix:\n\n```bash\ncd <project-root>\n\n# Verify the stale remote ref exists:\ngit ls-remote origin 'refs/dolt/*'\n# e.g.: abc1234def5678...  refs/dolt/data\n\n# Delete the remote ref (destructive — but this is a migrated repo,\n# and the old ref is no longer reachable from any current install):\ngit push origin :refs/dolt/data\n\n# Confirm it's gone:\ngit ls-remote origin 'refs/dolt/*'\n# (no output)\n\n# Now the dolt push will establish a new baseline:\ncd .beads/embeddeddolt/<your-prefix>\ndolt push origin main\n# Expect: \"[new branch] main -> main\"\n```\n\nSafe if you're the only active consumer of that beads database. If multiple\nmachines still have copies pointing at the old ref, migrate them all before\ndeleting the remote ref.\n\n### `dolt push origin main` says `Everything up-to-date` but local has uncommitted data\n\n`dolt push` only pushes committed data. If you loaded data via Path B's\n`dolt sql < dump.sql` and didn't commit the working set, the push sees\nno new commits to send. Exit code is 0, the remote looks current, but the\nissues you just loaded are stranded locally in the dolt working set.\n\nVerify:\n\n```bash\ncd .beads/embeddeddolt/<your-prefix>\ndolt status\n# If it shows \"Changes not staged for commit\" on issues/wisps/events/etc.,\n# you have uncommitted data in the working set.\n\ndolt log --oneline\n# HEAD should be at a \"migrate: ...\" commit, not at \"bd init\"\n```\n\nFix: commit and push.\n\n```bash\ndolt add -A\ndolt commit -m \"migrate: import historical data\"\ndolt push origin main\n```\n\nSet `bd config set dolt.auto-commit on` (Step 7) so future writes don't\naccumulate in the working set.\n\n### `dolt sql -q \"use <dbname>;\"` says \"database not found\" but `show databases` lists it\n\nYou're running dolt from the wrong directory. The actual database is at\n`.beads/dolt/<dbname>/.dolt/`, not `.beads/dolt/.dolt/`. The outer `.dolt/`\nis a dolt-sql-server workspace config with no branches.\n\n```bash\ncd .beads/dolt/<dbname>\ndolt status          # should show branch info, not nil-column error\ndolt sql -q \"select count(*) from issues;\"\n```\n\n### `dolt dump` fails with \"The current directory is not a valid dolt repository\"\n\nSame cause: you need to be inside `.beads/dolt/<dbname>/` (or\n`.beads.server-backup/dolt/<dbname>/`), not its parent.\n\n### `.beads/dolt/` only contains `config.yaml` — no database subdirectory\n\nThis is a **transitional SQLite → Dolt** source: bd 0.55 was installed and\nstarted setting up dolt (creating `.beads/dolt/config.yaml`) but the actual\n`bd migrate --to-dolt` step never ran. All the issue data is still in\n`.beads/beads.db` (SQLite). Don't use Path B — there's nothing to dump.\nUse **Path A**:\n\n1. Check for an existing `.beads/issues.jsonl`. If its line count matches\n   `sqlite3 .beads/beads.db \"select count(*) from issues;\"`, use it as-is.\n2. If not, regenerate via raw `sqlite3` (see Step 3A).\n3. Proceed to Step 4 (upgrade) → Step 5 (`bd init`) → Step 6A\n   (`bd import`).\n\n### `dolt dump -d /path` or `dolt dump --data-dir` errors\n\n`dolt dump` doesn't support global data-dir flags. Run from inside the\ndatabase directory and use `-fn /path/to/output.sql` instead:\n\n```bash\ncd .beads.server-backup/dolt/<dbname>\ndolt dump -f -fn /tmp/doltdump.sql\n```\n\n### `bd init` says \"database 'thrum' already exists\"\n\nThe embedded store at `.beads/embeddeddolt/<prefix>/` already has schema\nand schema_migrations rows. Pass `--force`:\n\n```bash\nbd init --force --prefix=<your-prefix> --non-interactive --role=maintainer\n```\n\nOr delete `.beads/embeddeddolt/` first.\n\n### `bd backup restore --force /tmp/dump` says \"Error 1105: database already exists, use --force\"\n\nThat error refers to the dolt database itself, not the backup destination.\nPass `--force`:\n\n```bash\nbd backup restore --force /path/to/backup\n```\n\nOnly useful for restoring from a proper `bd backup sync` destination, not\nfrom the old server-mode `.beads/backup/` directory.\n\n### `bd dolt pull` fails with merge conflict on the `issues` table (pre-upgrade)\n\nThis is usually what triggers the migration in the first place. When an\nold server-mode bd 0.62 client and a freshly-upgraded bd 1.0 client share\nthe same `.beads/dolt/` data, they talk to the server on different ports\nand the remote sync can drift. Complete the migration from Step 2 onward —\ndon't force-merge.\n\n### `/tmp/doltdump.sql` got overwritten mid-migration\n\nAnother session (or a parallel migration loop) writing to the same hardcoded\npath. Two dumps racing to the same file is not fun. The fix is baked into\nStep 3b: write to `.beads.server-backup/<repo>-bd-dump.sql` instead, so\neach repo's dump lives inside its own safety directory. If you already hit\nthis, re-run Step 3b with the corrected path — the source data in\n`.beads.server-backup/dolt/<dbname>/` is still intact.\n\n### Orphan `dolt sql-server` processes accumulating over time\n\nEvery unmigrated bd 0.62 repo on the machine has exactly one orphan\n`dolt sql-server` process that bd 1.0 can't stop. They're **safe but\npointless**: they hold locks on their `.beads/dolt/` directories and\nconsume a tiny bit of RAM. They don't interfere with bd 1.0 operations in\nother repos (each server listens on a different port).\n\nTo clean them up, run the discovery script (see Step 1) to cross-reference\neach PID with its repo, then migrate repos one by one. Each migration\nnaturally kills its own orphan in Step 1.\n\nIf you find an orphan whose `cwd` points at a deleted directory or the\ntrash, just kill it — nothing depends on it:\n\n```bash\nlsof -p <pid> 2>&1 | grep cwd  # sanity check the cwd first\nkill <pid>\n```\n\n### Worktrees still have old `.beads/dolt/` directories\n\nSee the worktree subsection after Step 2: per-worktree migration vs shared\nDB via `.beads/redirect` file. The redirect option is the bd 1.0 documented\npattern for sharing a database across worktrees.\n\n### The dolt remote bd init created is pointed at the wrong place\n\n`bd init` on a repo with a git remote auto-configures a dolt remote pointed\nat the git origin. In an offline-backup workflow (where you have your own\nexternal script) this is harmless noise. But if it causes confusion:\n\n```bash\n# Remove the auto-configured dolt remote:\nbd dolt remote remove origin 2>/dev/null || true\n\n# Or disable auto-push in .beads/config.yaml:\n# (covered in Step 8 of this guide)\n```\n\n### Backup scripts break: `bd backup --force` no longer exists\n\nIn bd 0.62 your script probably does:\n\n```bash\n(cd \"$PROJECT\" && bd backup --force 2>/dev/null || true)\ncp \"$PROJECT/.beads/backup/\"*.jsonl \"$BACKUP_DEST/\" 2>/dev/null || true\n```\n\nThe `|| true` silently swallows the error, and the `cp` copies whatever\nJSONL files happen to be lying around — which after the migration may be\n**empty or stale**. Update the script to use `bd export`:\n\n```bash\n(cd \"$PROJECT\" && bd export --all -o \"$PROJECT/.beads/backup/issues.jsonl\") \\\n  2>/dev/null || true\ncp \"$PROJECT/.beads/backup/\"*.jsonl \"$BACKUP_DEST/\" 2>/dev/null || true\n```\n\n`bd export` writes a single JSONL containing all issues (and memories,\ndependencies, comments, labels, etc.) in a format that's human-readable and\ngreppable — which is usually what these backup scripts actually want.\n\n---\n\n## References\n\n- Beads docs: `docs/INSTALLING.md`, `docs/DOLT.md`, `docs/DOLT-BACKEND.md`\n  in the [beads repo](https://github.com/steveyegge/beads)\n- Changelog entries for the 0.55 → 1.0 embedded-mode transition:\n  search the beads CHANGELOG.md for \"embedded\" and \"schema version\"\n- Originating incidents:\n  - **First session (Path B discovery):** recovery of a recently-filed\n    epic in the `thrum` public repo via raw `dolt sql dump` after `bd\n    backup restore` on the `.beads/backup/*.jsonl` files produced an\n    empty database. That incident produced Step 6B / Step 3B and made\n    clear that the `.darc` archives in `.beads/backup/` are not full\n    snapshots.\n  - **Second session (multi-repo migration sweep):** systematic\n    migration of several personal and work-private repos across a\n    range of source states — SQLite-era (bd ≤ 0.54), transitional\n    SQLite → Dolt, old-schema server-mode (bd 0.55 range), and clean\n    server-mode (bd 0.62). That sweep turned up: (1) `bd import\n    <file.jsonl>` exists in bd 1.0 and is the preferred path for any\n    source with a JSONL or SQLite backend, (2) very old server-mode\n    sources have schema drift (missing `no_history` column, missing\n    `custom_statuses` / `custom_types` tables) that the dolt dump\n    replays back onto the fresh embedded schema, (3) `dolt.auto-commit`\n    defaults to `off` in bd 1.0 so loaded data sits in the working set\n    and is never pushed until committed manually, and (4) a stale\n    `refs/dolt/data` on the remote from a prior install causes\n    `no common ancestor` push errors that must be cleared with\n    `git push origin :refs/dolt/data` before the fresh baseline will\n    push.\n", "url": "https://wpnews.pro/news/beads-bd-migration-guide-any-pre-1-0-install-sqlite-era-server-mode-dolt-jsonl-1", "canonical_source": "https://gist.github.com/leonletto/606e8afbb3603870d14b4123707416a2", "published_at": "2026-04-10 23:06:21+00:00", "updated_at": "2026-05-22 12:38:46.032876+00:00", "lang": "en", "topics": ["developer-tools", "data", "open-source", "enterprise-software"], "entities": ["Dolt", "SQLite", "beads", "JSONL"], "alternates": {"html": "https://wpnews.pro/news/beads-bd-migration-guide-any-pre-1-0-install-sqlite-era-server-mode-dolt-jsonl-1", "markdown": "https://wpnews.pro/news/beads-bd-migration-guide-any-pre-1-0-install-sqlite-era-server-mode-dolt-jsonl-1.md", "text": "https://wpnews.pro/news/beads-bd-migration-guide-any-pre-1-0-install-sqlite-era-server-mode-dolt-jsonl-1.txt", "jsonld": "https://wpnews.pro/news/beads-bd-migration-guide-any-pre-1-0-install-sqlite-era-server-mode-dolt-jsonl-1.jsonld"}}