Skip to content

Instantly share code, notes, and snippets.

@mz0
Created June 25, 2026 16:00
Show Gist options
  • Select an option

  • Save mz0/6e06ef5c30ec8e989f2e754b5a4e9f26 to your computer and use it in GitHub Desktop.

Select an option

Save mz0/6e06ef5c30ec8e989f2e754b5a4e9f26 to your computer and use it in GitHub Desktop.
How Beads syncs a Dolt database over a Git remote

How Beads syncs a Dolt database over a Git remote

How an issue's title, description, and status actually move to and from the Git server when you run bd dolt push / bd dolt pull.

The refs

Beads stores issues in a local Dolt database, then syncs by reusing your Git remote — but under non-branch refs you don't normally see:

refs/dolt/data                      ← the issue database (Dolt's own format)
refs/heads/__dolt_remote_info__     ← Dolt bookkeeping branch

Normal git push / git fetch only touch refs/heads/* and refs/tags/*, so they never see or move this. That's why pushing a feature branch and running bd dolt push are completely independent operations.

The encoding chain

1. bd writes to a local Dolt SQL database. An issue's title/description/status are rows in Dolt tables — ordinary SQL.

2. Dolt serializes those rows into content-addressed chunks. Dolt's storage (NBS — Noms Binary Storage) breaks tables into a Merkle / "prolly" tree of chunks, each named by its content hash. In the pushed tree you see:

  • *.darc files = Dolt ARChives — compressed packs of many chunks (the big ones: tens to hundreds of KB). These hold the bulk row data.
  • Small 321/325-byte files = loose / journal table files.
  • manifest = the index. Its bytes start 5:__DOLT__:<root-hash>:<lock-hash>:<tablefile-id>:<chunk-count>:… — a store version, the __DOLT__ store name, the current root, a lock hash, then a list of every table file with how many chunks each holds.

3. bd dolt push wraps those chunk files as plain Git objects. This is the "gitblobstore" (visible in the carrier commit message gitblobstore: checkandput manifest). Each .darc/chunk file → a Git blob; they're assembled into a Git tree; wrapped in a Git commit; pointed to by refs/dolt/data.

4. That commit ships over the normal Git wire protocol — same smart-HTTP/SSH, same auth — to the remote, just to a non-branch ref. bd dolt pull fetches it back, reads the manifest, and hands the chunks to Dolt, which reconstructs the SQL rows.

Proof it's really the issue text

Running strings over one .darc blob surfaces actual bead content (titles and descriptions) — sitting compressed inside a blob the Git server stores as opaque bytes.

The key insight

Git is the dumb transport and blob store; Dolt is the only layer that understands rows. The Git server sees blobs/trees/commits and has no idea they encode a SQL database. That's why:

  • git log / branch diffs never show issues — they're under refs/dolt/data, and even there they're chunk hashes, not readable text.
  • Conflict resolution, history, and "what changed in this issue" are Dolt's job (its own commit graph lives inside those chunks), not Git's.
  • A passive issues.jsonl export exists precisely because the canonical form is unreadable to Git tooling — the JSONL is the human / Git-friendly mirror, regenerated from Dolt.

So it really is "going through Git" — it rides the exact same remote and protocol. What's different is that the content model is Dolt's, packed into Git blobs as a carrier.

How to inspect it yourself

# See the dolt refs on the remote
git ls-remote origin | grep -i dolt

# Fetch the data ref locally and look at what it points to
git fetch origin 'refs/dolt/data:refs/dolt/data'
git cat-file -t refs/dolt/data            # -> commit
git cat-file -p refs/dolt/data            # tree + "gitblobstore: checkandput manifest"

# Inspect the carrier tree: .darc archives, loose chunks, and the manifest
git ls-tree -r --long refs/dolt/data

# Read the NBS manifest
git cat-file -p <manifest-blob-hash>

# Confirm row text lives (compressed) inside an archive blob
git cat-file -p <darc-blob-hash> | strings | head
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment