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.
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.
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:
*.darcfiles = 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 start5:__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.
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.
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 underrefs/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.jsonlexport 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.
# 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