Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#6603·beads

bd init under $TMPDIR silently plants the embedded store at the OS temp root's own .beads instead of the target directory

Author: athosmartinsCreated Sep 18, 2026Updated Sep 18, 2026

Summary

bd init --non-interactive --prefix <x> at a target directory under the OS temp root (os.TempDir() — e.g. macOS's $TMPDIR, /var/folders/.../T/) silently plants the new embedded Dolt store at the temp root's own .beads/embeddeddolt/<prefix> instead of locally at <target>/.beads/embeddeddolt/<prefix> — even on an otherwise-clean machine with no pre-existing .beads anywhere, and even with a brand-new, never-before-used --prefix. This makes every mktemp -d-based hermetic bd fixture in ANY caller's test suite silently alias into one shared, ever-growing store instead of getting its own isolated one.

Once this has happened once, it compounds: findParentConfig's ancestor search (cmd/bd/bootstrap.go) has no ceiling at the OS temp root (only at $HOME), so every subsequent bd -C <any-subdir-of-tmpdir> call — init, create, count, list — finds the now-existing temp-root .beads and reuses it, regardless of the target directory's own path or configured prefix.

Environment

  • bd version 1.1.0 (861fd98b9)
  • macOS (Darwin 25.6.0), embedded Dolt mode (dolt_mode: embedded)
  • No BEADS_DOLT_SHARED_SERVER, no dolt.shared-server config — confirmed IsSharedServerMode() is false; this is not the shared-server codepath.

Reproduction

bash
S="$(mktemp -d)"          # e.g. /var/folders/xx/.../T/tmp.XXXXXXXX
mkdir -p "$S/store-a" "$S/store-b"
( cd "$S/store-a" && bd init --non-interactive --prefix rta )
( cd "$S/store-b" && bd init --non-interactive --prefix rtb )
bd -C "$S/store-a" create "fixture A" -t task -q
bd -C "$S/store-b" create "fixture B1" -t task -q
bd -C "$S/store-b" create "fixture B2" -t task -q

bd -C "$S/store-a" count --json   # {"count": 3}  -- expected 1
bd -C "$S/store-b" count --json   # {"count": 3}  -- expected 2, SAME as store-a

# Check where it actually landed:
ls -d "$S/store-a/.beads" 2>&1    # No such file or directory
ls -d "${TMPDIR%/}/.beads" 2>&1   # <- exists; dolt_database in its
                                  #    metadata.json is "rta", the FIRST
                                  #    prefix ever used, not "rtb"

Even a brand-new prefix that's never been used before gets silently discarded — creates land under whatever prefix the temp root's .beads already has:

bash
S2="$(mktemp -d)"
mkdir -p "$S2/solo"
( cd "$S2/solo" && bd init --non-interactive --prefix zzq9999 )
bd -C "$S2/solo" create "solo" -t task -q
bd -C "$S2/solo" list --json | jq -r '.[0].id'   # rta-xxxxxx, NOT zzq9999-xxxxxx

Root cause (as far as I traced it)

  1. Trigger: when bd init has to perform its own internal git init (i.e. no .git exists yet at the target), something in the init flow falls back to placing the new embedded store's physical files under os.TempDir() instead of the target directory — reproducible from a fully clean state, not merely a reuse of pre-existing ancestor state. Workaround confirmed deterministic across repeated fresh-machine-state runs: pre-creating the git repo with a separate git init -q call before invoking bd init avoids the misbehavior entirely — bd init then correctly creates .beads locally at the target. This points at an ordering/caching issue around git-root detection immediately after bd's own git init step, though I did not locate the exact line.
  2. Compounding factor (confirmed in source): findParentConfig in cmd/bd/bootstrap.go walks up from a directory's parent looking for an ancestor .beads, with no ceiling at the OS temp root — only at $HOME:
    go
    for dir := start; dir != "/" && dir != "."; {
        candidate := filepath.Join(dir, ".beads")
        ...
        if homeDir != "" && dir == homeDir { break }
        ...
    }
    Once (1) has planted a .beads at the temp root once, this walk finds it from literally any mktemp -d subdirectory forever after (until someone manually removes it), for any caller, any prefix.

Impact

Any test suite that builds "isolated" bd fixtures under mktemp -d — a very common, otherwise-idiomatic pattern — can silently get cross-fixture aliasing instead of isolation, with no error and no warning. We hit this for real in a Gas Town regression test (dolt-compact-routine.selftest.sh) whose entire job is to catch exactly this class of aliasing bug in a downstream caller's own code — the test's own fixture harness had quietly become subject to the identical bug it exists to detect, which meant it could no longer be trusted to catch a real regression. Root-cause writeup and the observed store (accumulated to 40+ stray "fixture bead" rows from repeated affected test runs) confirmed live 2026-09-18.

Suggested direction (not prescriptive — happy to be told this is wrong)

  • bd init should never place a newly created store's files outside the exact directory it was asked to initialize, regardless of git-detection state at the time it runs.
  • Separately, findParentConfig's ancestor walk arguably should stop at (or never enter) os.TempDir()'s own value — a .beads sitting directly at the OS-managed temp root can never legitimately correspond to a real project someone meant to nest under.

Workaround for callers today

git init -q at the target directory before calling bd init --non-interactive avoids the misbehavior. (Also worth defensively verifying <target>/.beads/metadata.json exists locally right after bd init, in case some other trigger of the same class exists that this workaround doesn't cover.)

Source: gastownhall/beads

View original on GitHubView discussion on GitHub