Beads v1.3.0
v1.3.0-rc.1 — release candidate for v1.3.0. Changelog section dated 2026-08-28; cut from
release/1.3.0 at b3ef65c8.
Beads 1.3.0 is the first tested release off main since the 1.1 line.
v1.2.2 was a
recovery release that re-shipped the v1.1.2 code under a higher version number,
so a v1.2.2 user is running 1.1-era code and meets everything below at
once: the changes listed here, plus the [1.2.1] changes that release
deliberately withheld. Read the upgrading notes before installing.
Highlights
- One guided, crash-resumable migration from v53 to v66. On an embedded or
local store, the first invocation after installing migrates your schema in
place — 13 main-series migrations plus 15 clone-local ones, about 28
migrations, with the counter visibly restarting partway through (that is
the clone-local series, not a loop). Back up first, with the binary you have
now. - A shared Dolt sql-server is never auto-migrated. Migrating one promotes
the schema for every attached client at once, so a version bump there now
waits for explicit consent —bd migrate schemaafter the fleet is upgraded,
orBD_ALLOW_REMOTE_MIGRATE=1in scripted use (#5920, #6048). The gate also
runs on the proxiedbd serveopen path, which had been migrating shared
databases on every open, reads included (#6055), and is scoped so a server bd
auto-starts for a single workspace still migrates on open as it always has
(#6088). Write commands respect aMIGRATION-FREEZEsentinel with a
dedicated exit code 14 (#6043), andbd doctorhonors--readonlyand the
freeze instead of--fix-ing through them (#6056). - Data-integrity heals across the Dolt plane. Duplicate typed dependency
edges merge instead of aborting the rekey half-applied (#6045), a legacy
tracked migration-cursor table is untracked at open sobd dolt pull
unwedges (#6046),bd deleteno longer wedges auto-export forever (#6059),
an ignored-series sentinel gap no longer replays the whole clone-local chain
and restamps wisp timestamps (#6054), and server-modeDOLT_ADD/DOLT_COMMIT
now run after the SQL transaction commits, ending concurrent lost updates
(#6040, carrying @nova-submodules' #5740). - JSON contracts fixed before 1.3.0 freezes them. String revision tokens,
--set-metadatascalar typing, andbd create --jsonnano timestamps
(#6053);--storage-classwired through the proxied, markdown, and graph
create paths (#6060); journal delete and cascade rows carry the request actor
(#6061); andGET /v0/beads/issuesgainssortwith order-bound cursors
(#5666). - Errors tell the truth.
bd bootstrapprobes git remotes for Dolt data
instead of rejecting them, and exits non-zero when it declines (#6037);
proxied/gatewaybd initattributes identity safely and classifies access
denials honestly (#6062); the legacy-backend tombstone names the exact heal
instead of destructive advice (#6044); a Homebrew--HEADversion stamp is
recognized rather than misread as0.0.0and routed into a.dolt-deleting
recovery (#6079);bd primesays when the memory plane could not be read
(#5877). - Security posture for the tag. The Go toolchain moves to 1.26.7, closing
seven stdlib advisories reachable from the shippedbdbinary, alongside
dependency bumps clearing all 25 open advisories with per-cluster
reachability verdicts (#6047). - The upgrade path is tested where it bites. A new wisp-plane upgrade
corpus seeds and asserts the clone-local plane — wisps, leases, events, the
ignored-migration cursor — that the 1.3.0 chain actually rewrites (#6049).
Upgrading Notes
-
On an embedded or local store, the first invocation migrates your schema,
in place, from v53 to v66. A v1.2.2 (or any 1.1.x) database sits at
main-series schema v53; this binary knows v66, so the first command that
opens the store applies 13 main-series migrations,0054_add_lease_columns
through0066_add_events_journal_actor. Two of those passes rewrite rows
rather than just reshaping tables — the aux-row id rekey and theevents
dolt_ignore flip described under Changed — so on a large store the first
invocation is noticeably slower than the ones after it. It is
crash-resumable and picks up where it left off, but do not interrupt it if
you can avoid it. -
A shared
dolt sql-serveris never auto-migrated (#5920, #6048).
A server-mode database is served to every client attached to it, so migrating
it promotes the schema for all of them at once and locks out anything still
on an older binary. Upgrade that server's clients first, then consent once:# 1. upgrade bd on every client of the server; reads keep working throughout bd version # on each client, confirm the new version # 2. once, from a workspace already set up against this server: bd migrate schema # add --global for the shared global database # 3. confirm bd doctor
Between steps 1 and 2 an upgraded client reads normally and its writes are
refused with the gate's guidance — nothing is silently promoted, so there is
no deadline, but keep the window short.BD_ALLOW_REMOTE_MIGRATE=1is the
scripted, auditable standing consent, and a client joining a behind-schema
server is refused before its workspace is written, so join and migrate in one
step withBD_ALLOW_REMOTE_MIGRATE=1 bd init …. If the shared server also
has a Dolt remote, step 2 is not enough: two hazards apply at once and bd
requires the stronger designated-migrator consent (bd migrate --forcefrom
exactly one machine, thenbd dolt push). Recipes in
Shared servers. -
The counter restarts partway through, and that is not a loop. The
clone-local (dolt_ignored) series runs after the main one, through the same
printer and its own numbering, and it moves 0011 → 0026 on this upgrade. So
the run is about 28 migrations, not 13, and what you see on stderr is 13
lines counting up to 0066 followed by 15 lines starting again at 0012:Applying migration 0065: widen_wisp_comments_text… Applying migration 0066: add_events_journal_actor… Applying migration 0012: create_leases… ← clone-local series, not a restartA counter that jumps backwards is the signature operators kill runs over.
Let it finish. Progress prints only when stderr is a terminal — piped and CI
runs see nothing at all, which is deliberate: a silent-looking CI upgrade is
not a stuck one. -
Back up first, with the binary you have now. Take the backup before
you install 1.3.0. Under the new binarybd exporttriggers the
auto-migration before it exports, so a snapshot taken afterwards is a
post-migration snapshot and cannot protect you against the migration going
wrong. On a remote-backed store, finish syncing with the old binary too:
once 1.3.0 is installed the pending-migration gate refusesbd dolt push
andbd dolt pullas well, not justbd migrate.# with your CURRENT bd, before installing 1.3.0: bd dolt push # remote-backed stores only bd export --all -o .beads/backup/pre-1.3.0-$(date +%Y%m%d).jsonl
A JSONL export is cheap, issue-complete, and importable by any bd version.
If you want a Dolt-native snapshot that keeps history and config, configure
a destination and sync it — barebd backuptakes no backup, it is a
command group that prints help and exits 0:bd backup init <path-or-dolthub-url> # once, to configure a destination bd backup sync # take the snapshot
-
Upgrade every client that shares a store, together. The forward
schema-skew guard means an older co-resident binary — a secondbdearlier
inPATH, a long-runningbd serve, another clone's cron job — refuses a
database migrated past what it knows, rather than proceeding blind. That is
the guard working, not a bug, but it makes a mixed-version fleet a broken
fleet: one machine running 1.3.0 takes the whole store forward and every
1.2.2 client stops. Runwhich -a bdafter installing, and on a
remote-backed store follow the designated-migrator procedure (one clone
migrates and pushes; the rest pull or re-clone). See
Upgrading for the
per-install-method recipes and the multi-clone flow. -
If you need to go back, the rollback is a schema-cursor rollback, not a
downgrade of the data: the procedure is written up in the
recovery runbook
(repo copy:docs/recovery/accidental-1-2-1-release.md). Its worked example
is the v53↔v65 case from the accidental 1.2.1 release; the steps are the
same for v66, with the version numbers adjusted. -
After upgrading,
bd upgrade reviewprints exactly the entries between
the version you were running and this one. Prefer it to
bd info --whats-new, which dumps the entire release history. Several
commands changed defaults, so read it before your first session.
Breaking changes for v1.2.2 users
This is a highlights list, not the complete set. A v1.2.2 user is crossing
two releases at once, and the breaks below are the ones most likely to stop a
script or a service. The full set is the [1.2.1] section of the
CHANGELOG
plus the Changed section here — read [1.2.1] in full before upgrading,
since v1.2.2 withheld it and v1.2.1 itself was pulled, so nobody on the
supported line has seen it.
Carried from [1.2.1], never shipped to v1.2.2 users:
bd update --status <done-status>now enforces close policy — open
children or a live direct blocker refuse the move, matchingbd close.
Override withbd update --force; an unforced refusal rolls back the entire
batch.bd searchincludes closed issues by default (bd-t5yex). Narrow with
--status openfor the old behavior;bd listkeeps its open-only default.- The no-ID "last touched issue" fallback on
bd update/bd closeis
interactive-only (#4839). A scriptedbd update $ID …with an empty$ID
now refuses instead of mutating whatever was touched last. Set
BD_LAST_TOUCHED_FALLBACK=1if a script genuinely relied on it. bd human listhides done/frozen and pinned beads by default, and
validates--status(#5332). A--statustypo is now an error rather than
an empty list.bd dolt pushandbd syncno longer adopt a git-origin-derived Dolt
remote without consent (#5068). Adoption now prompts (defaulting to no)
and fails closed non-interactively;--yes/-yconsents ahead of time.bd --readonly serveis refused instead of binding a server that cannot
do what it advertises. Anything scripted as a "safe" read-only server does
not start after this upgrade — drop the flag. Worth checking before you
restart a long-runningbd serveas part of the fleet upgrade above.bd config listandGET /v0/beads/configno longer enumerate thekv.
plane, which is wherebd remembermemories live — that closed an
unauthenticated endpoint handing out every stored memory. Usebd kv/
bd rememberinstead.- The published
backendpackage drops orphan handling (bd-gwryr). A Go
consumer that namesbackend.OrphanHandlingor its constants no longer
compiles.
New in 1.3.0 (full entries under Changed):
- An explicitly configured Dolt server port now outranks the ambient
BEADS_DOLT_PORTenvironment variable. - Actor matching decodes an exact
--run to/instead of collapsing it to
a generic separator, sogastown--mayormatchesgastown/mayorand stops
matchinggastown__mayor.
Added
- The events journal records WHO performed each mutation.
bd_events_journalgains anactorcolumn (migration 0066 plus its
ignored-series twin 0025), stamped inside the mutating transaction with the
same identity the audit-events table resolves.bd events tail/
bd events exportJSON gains an additive, omit-when-emptyactorfield —
empty means the path had no actor, never a user. Delete and cascade
dep_removerows carry the request actor too, and reading a disabled journal
now says so instead of returning silence (#6061, #5985). sortonGET /v0/beads/issues(#5666). Two values, and the set is
closed:created(the existing order, now spellable) andpriority
(bd list's flagless ordering) — measured over a 1400-row store at the
200-row page an HTTP client actually uses,?sort=priorityturns a
7-request page-and-resort walk into 1 request. Cursors are nowv2tokens
that carry their order, and a cursor replayed under a differentsortis
refused asinvalid_cursorinstead of silently paging a different total
order; outstandingv1tokens stay readable, so no traversal in flight has
to restart. Absentsortstill meanscreated, permanently.bdwarns when it stores a label containing a space (#5813).-l 'good first issue'is stored as asked, but a missed comma looks identical at the
point of writing, so a stderr line catches it at the keystroke:⚠ Stored "auth backend" as ONE label — it contains a space.Advice, not an error;
--quietsilences it.bd doctorgains a matching warn-onlyLabel Whitespacecheck, andbd doctor --fixrepairs damage already in the
database.bd staleandbd blockedgain--label,--label-anyand
--exclude-label(#5822), with the same meanings they already have on
bd listandbd ready. Filtering happens in SQL ahead ofLIMIT, so
--label x --limit 10returns ten matching issues.- New
*.gate.lockfiles appear next to and inside.beads(#5046,
#5093). A two-level cooperative flock gate serializes operations that cannot
safely overlap — ordinary commands take it shared, maintenance like
bd backup restoretakes it exclusive. The files are the lock's name, not
its state: created once and deliberately never deleted. Both are covered by
the*.gate.lock*gitignore patternbd doctormaintains. - A wisp-plane upgrade corpus (#6049). Neither upgrade harness had ever
seeded a wisp, so the clone-local plane the 1.3.0 chain rewrites —wisps,
wisp_dependencies,wisp_comments,leases,events, and the
ignored-migration cursor — used to reach the candidate binary empty. A new
lane seeds those classes and asserts them across the upgrade, including
detection of an ignored-track replay the old harness was structurally blind
to.
Changed
- Shared stores refuse version-bump migration without explicit consent
(#5920, #6048, #6055, #6088; closes the gate leg of #5043). Embedded and
single-user databases still auto-migrate silently, and fresh databases still
migrate on creation — creating a database is consent for its schema. But a
shareddolt sql-serveraccepts co-resident clients by construction, so a
version bump there refuses instead of taking the whole fleet's schema forward
as a side effect of one upgraded client; the smart gate's "safe first-mover"
and auto-fast-forward arms are embedded-only for the same reason (#4516). The
gate now also runs on the proxiedbd serveopen path, which had been
migrating shared databases on every open — including from read commands —
since v1.2.2: read commands warn and continue, writes refuse,bd serve
fails to start until the schema is reconciled,bd migrate schemaworks in
proxied mode instead of refusing, and gate failures print their full
actionable block instead of one truncated line. "Shared" is drawn
deliberately (#6088): shared-server mode, an operator-managed server, a
remote host, a TLS endpoint, a unix socket, or no workspace at all — a server
bd auto-starts for a single workspace is a database no other client can
observe, and migrates on open as it always has. bd doctorrespects--readonlyand the migration freeze (#6056; fixes
#6028).bd doctor --fixpreviously mutated workspaces that strict
--readonlyand an active freeze had both declared off-limits — and plain
bd doctor, with no--fixat all, could rewrite.local_versionor
auto-migrate a frozen store as a side effect of diagnosis. Both bypasses are
closed, with no doctor-side override, and both gates key on the directory
doctor was pointed at rather than only the one it was launched in.- Write commands refuse to run while a
MIGRATION-FREEZEmarker is
present (dc-6jaq, #6043). Discovery is generic: the marker is found in the
workspace directory, the working directory, or any ancestor of either, and
BD_MIGRATION_FREEZE_FILEis authoritative when set. Every write command
(~120 call sites,bd qincluded), plusbd init --reinit-localand
bd bootstrap, prints⛔ workspace is frozen for migrationnaming the
marker's own path and exits 14 (ExitMigrationFrozen) instead of a
generic 1. Read commands keep working, and bd's own maintenance stands down
with them — auto-migration, JSONL auto-import, Dolt auto-commit, auto-backup,
auto-export and auto-push are all skipped, so a frozen store is never
rewritten just because someone ran a read. A runningbd serveis not
gated: stop it before freezing. - Migration 0061 rekeys every events, comments, snapshot and
compaction-snapshot row to a content-derived id (#5150). Random UUIDv7 ids
never converged under newest-wins replication; ids are now UUIDv5 over the
row's own content, so the same fact derives the same id everywhere. Existing
rows are converted by a one-time, crash-resumable bulk rekey on the first
open after upgrade — the main reason that invocation is slower. Any
external reference to an event, comment or snapshot id taken before the
upgrade will not resolve afterwards. - The
eventsaudit table is now clone-local (#5162). Migration 0062
moveseventsonto the dolt_ignored plane, preserving every row. Events
keep full SQL durability locally andbd history <id> --eventsstill reads
them, buteventsrows no longer replicate — minting a versioned Dolt
commit per audit row was the dominant source of commit churn on a busy
store. Comments stay versioned. - The
interactions.jsonlaudit sidecar is opt-in (#4688).
audit.enableddefaults to false andbd initno longer creates the file;
the database-backed replacement isbd history <id> --events. - Auto-backup defaults to off under a Dolt sql-server (wy-zrmqr) — on one
shared server, ~31 clients had each independently decided to back up the
same database. Embedded mode is unchanged; an explicitbackup.enabled
always wins, andbd config get backup.enablednow prints the effective
value with its source. --profileis now--cpu-profile, with no alias (#5126). The old
spelling fails as an unknown flag instead of silently doing nothing.bd importrefuses a redirected stdin rather than quietly ignoring it
(#5171).bd import < file.jsonllooked likebd import -and behaved like
barebd import; it now errors and names both fixes.bd hooks install --chainand--forceare accepted no-ops (#5284).
Managed marker sections always preserve content outside them and always keep
an existing hook running alongside the bd section; symlinked and git-tracked
hook paths are refused before anything is written.- An explicitly configured Dolt server port now outranks the ambient
BEADS_DOLT_SERVER_PORT/BEADS_DOLT_PORTenvironment variables (GH#4052).
A port asserted by the user —bd init --server-port, config, a library
caller — is no longer silently replaced by whatever the surrounding shell
exported, and the legacyBEADS_DOLT_PORTspelling no longer overrides
configured ports. Ports bd resolved for itself stay overridable by either
spelling, and a stale.beads/dolt-server.portleft by a crashed server no
longer makes auto-start refuse over a port nobody configured. - The legacy-backend tombstone rejection is truthful (#6044). A workspace
whosemetadata.jsonstill says"backend": "sqlite"(v1.2.x opened these
as Dolt anyway) is still refused fail-closed, but when live Dolt data is
detected the message now carries the exact one-field heal instead of
advising an export/reinit that would have destroyed a database one edit from
healthy. Detection helper ported from @steveyegge's #4740. - The new exported Go packages are marked experimental before the tag freezes
them (#6036).backend,beadserrors,issueops,journalops,
memoryops,schemaand the conformance profiles ship usable but explicitly
unfrozen — the extension door for out-of-tree backends stays open without a
v2 to walk back through. Pin an exact beads version and re-run the
conformance suite on every bump. bd showlabelscreated_byasCreated by:, notOwner:(be-ss66);
bd dep addnames the implicittype=blocksdefault to interactive
operators (#5854);bd reclaimsummarizes replica-guard skips in one line
instead of one line per stranded lease (wy-sp2l4);beads_dirand
repo_rootbecome OPTIONAL inContextResponse(bd servestill publishes
both — the relaxation is a promise to clients, not a switch on the server);
and actor matching decodes an exact--run to/(be-p7dzx).
Fixed
- Convergent dependency rekey (#6045; fixes #5268). A database can legally
hold the same logical edge twice under different typed columns; the rekey
derived the same UUIDv5 for both, died on the duplicate primary key, and —
because the cursor commits per step — left the store half-applied. The
planner now orders convergible states and merges duplicate typed edges, the
rename path that minted them is fixed at the source, databases left
half-rekeyed by earlier binaries are repaired on the next pass, and the
refusals that remain can no longer brick an open. - Legacy tracked
ignored_schema_migrationsis untracked at open (#6046;
fixes #4356). On legacy lineages the clone-local migration cursor predated
itsdolt_ignorepattern and sat committed at HEAD, so every migration pass
dirtied a tracked table bd could never clean — push worked and every
bd dolt pulldied withcannot merge with uncommitted changes,
permanently (reported independently on two fleets, 24 and 17 databases). An
open-time reconcile untracks it and unwedges the pull. bd deleteno longer wedges auto-export forever (#6059, completing
#5806; fixes #5896). Auto-export's orphan guard refused to overwrite an
issues.jsonlholding a deleted issue's record, refused again on every
subsequent command, and the documented recovery re-imported the JSONL —
resurrecting the issue the user deleted. Deletions are now proven via store
history (a newstorage.HistoryPresencecapability that the default
embedded store implements too) and the export proceeds; unprovable cases
still refuse.- Ignored-cursor sentinel replay is clamped to floor 11 (#6054; #5981
class, #5366 follow-up). A missing clone-local sentinel used to zero the
migration cursor and replay the wholeignoredchain from 0001 on every
upgrade from a released tree — v1.1.0/v1.1.2/v1.2.x all top that cursor at 11
and have noleasestable, so the sentinel was always missing. That replay
dragged inignored/0007's unguardedUPDATE wisps SET is_blocked = 0,
silently restampingwisps.updated_atacross the plane, unrecoverable
because the wisp plane has no committed history. Upgrades now apply exactly
the pending set,ignored/0012–0026. - Server-mode
DOLT_ADD/DOLT_COMMITrun after the SQL transaction
commits (#6040, carrying @nova-submodules' #5740). Staging inside the
still-open transaction materialized Dolt commits from the BEGIN-time
snapshot, silently reverting rows concurrent sessions had committed in the
window — observed in production as claims reverting minutes after being
made. The commit now stages the post-merge working set. bd bootstrapprobes git remotes for Dolt data instead of rejecting
them, and exits non-zero when it declines (#6037; fixes #5743, #5663).
Bootstrap rejected the very git-origin-derived remotebd initpersists,
printed✓ Database already existsfor the refusal, and exited 0 with
nothing created — a closed loop withbd init --reinit-localpointing back
at it.- Truthful errors and safe identity attribution for proxied/gateway
bd init(#6062). Nothing on the open path asserted the SQL session was on
the database bd asked for, so a credential-scoped front door could serve its
own database while bd attributed the reads to the requested one; everyUSE
failure was labeleddatabase not found, including access denials. Both are
fixed, along with a silent-data-hazard variant worse than the reported
error, and--init-if-missingis honored in proxied-server mode. --storage-classis honored on every create path (#6060). The flag was
accepted and ignored on the proxied route (minting a durable versioned row
for a request that asked for ephemeral), on--filemarkdown batches, and
on--graphplans; the direct door was fixed in-window (#5149, #5164). The
ephemeral/versioned conflict is now rejected on the proxied route with the
same message as the direct one.- Three JSON-contract defects fixed before 1.3.0 froze them (#6053):
revision tokens are opaque decimal strings again on the way out and must be
sent as strings inexpected_version— JSON numbers exceeded JavaScript's
2^53 precision;--set-metadata k=5stores the typed scalar5(restoring
v1.2.2's inference); andbd create --jsontimestamps carry nanosecond
precision again. - A Homebrew
--HEADversion stamp is recognized instead of being misread as
0.0.0(#6079, carrying @anisoptera's #5625; refs #5603, #5650). Version
comparison scans dot-separated parts with%dand leaves what it cannot read
at 0, so every non-semver stamp bd has written compared as "older than
0.56.0" and handed a live workspace to the pre-v56 recovery — which
deletes.doltwhen the.bd-dolt-okmarker is absent. Two stamps reach
that call:HEAD-<shortsha>frombrew install --HEAD, and the
v1.1.1-0.2026…Go pseudo-version that bricked five production cities in
#5650. The recovery is now gated onIsValidSemverbefore the comparison, so
it can only remove predecessors from the recovery set, never add one.
Alongside it:bd doctorreports a--HEADbuild as healthy instead of
naggingbrew upgrade beads(which would undo what the user asked for), a
changed HEAD stamp counts as an upgrade so the post-upgrade reconciliation
runs, andbd upgrade status/reviewyields no delta rather than dumping
the entire release history. bd flatten/bd compactrun a full GC after the rewrite (#6057;
fixes #5907). Dolt's generational GC never revisits the old generation, so
the post-rewrite pass freed ~nothing and orphaned history kept resolving,
contradicting flatten's own contract.bd gc --fullis new, and a
low-reclaim pass now hints at it.bdno longer serializes every invocation behind the schema-init advisory
lock (#6022). Measured on an 18-seat rig, the lock was held 96.7% of the
time and cost 0.4–2.4s of pure waiting on every claim, heartbeat, list,
comment and mail check. The steady-state probe now answers without the lock
and takesGET_LOCKonly on the path that can actually migrate; it issues no
writes and fails closed.bd purgeandbd pruneselect candidates by tier (#5995). A wisp
minted before theephemeralcolumn was set belonged to neither sweep — one
production database had 858 rows no sweep could ever reach. The tiers are
now complementary predicates, so the first purge after upgrade may clear
considerably more than usual.- Server mode honors
Config.LenientOpen(#5783 by @Toady00; fixes
#5781). The dirty-table refusal's documented recovery —bd dolt commit—
could not itself open a server-backed store, a deadlock previously broken
for embedded mode only. Found in the wild: 15 of 21 databases on one
deployed server carried a permanently dirtyconfigtable. - The aux-row rekey survives dolt#11131 encoding drift (#5064; fixes
#4380). A driftedevents/commentstable panicked Dolt inside the re-key
scan, aborting the migration and leaving the database unopenable. Drifted
tables are now skipped with a warning, recorded clone-locally in
aux_row_rekey_drifted, and re-keyed on a later pass; healing the drift
itself is Dolt'sschema-encoding-drift recover-rows. This already reached
1.1.x and v1.2.2 users — it is the [1.1.2] fix — and lands on the main line
here, so a store upgrading from v1.2.2 is not newly exposed. Diagnosis and
fix by @marcodelpin, carried and reworked by @maphew. - Incremental auto-export actually takes the incremental path (#5806), and
three format/scope regressions the dead code path was hiding — leaked
memories, included owner issues, a missing_typediscriminator — are pinned
by tests. Server-mode only; embedded mode still full-exports every cycle. - Disabling telemetry no longer strands the queued metrics backlog forever
(GH#5712) — 2M+ files / 15.8GB observed on one control VM; the prune child
now runs, network-free, until the backlog decays. - Quality-of-life truth-telling:
bd primesays when the memory plane
could not be read instead of impersonating an empty one (#5877);bd show
on a deleted or purged issue points atbd history <id>instead of printing
text identical to an ID that never existed (ga-m6inyb);bd vc commit/
bd dolt commitsweep the entire working set and reportNothing to commithonestly; every CLI label write normalizes its input so a label can
match its own filter — one real database had 150 such rows across 111 issues
(#5813, fixes #5812);bd showno longer corrupts quoted shell globs via
CommonMark emphasis pairing (#5799); andbd blockedno longer silently
ignores the label filters it already accepted (#5822).
Security
- Go toolchain 1.26.5 → 1.26.7 (#6047), closing seven stdlib advisories
reachable from the shippedbdbinary: quadraticnet/urlpath
resolution,html/templateJavaScript-regexp context tracking, unbounded
post-handshakecrypto/tlsmessages, a missingReadHeaderTimeouton
net/http's unencrypted HTTP/2 check, unbounded recursion inencoding/xml
andencoding/asn1, and thex/net/idnaPunycode bug innet/http's
vendored copy —bd serveis a real HTTP server and bd makes outbound TLS
calls. Thegodirective stays at 1.26.5, so importers of the module keep
their current floor. - Dependency bumps clearing all 25 open advisories (#6047), one commit per
cluster with a reachability verdict each:golang.org/x/crypto0.55.0,
golang.org/x/mod0.40.0,klauspost/compress1.18.7,moby/go-archive
0.3.3,kin-openapi0.144.0 withoapi-codegen2.7.1, and a refreshed
beads-mcp/uv.lock. None of the fixed code is reachable from the shipped
binary — the headline critical iskin-openapi'sopenapi3filter
middleware, which enters the graph only through thetooldirective for spec
codegen. No behavior change; no dolt bump was required.
Troubleshooting (upgrading from v1.2.2)
Most upgrades need no command at all — on an embedded or local store the first
invocation migrates in place. The papercuts below are the shapes worth
recognizing before you file a bug:
| Symptom | Cause | Fix |
|---|---|---|
Migration counter jumps backwards to 0012 after reaching 0066
| The clone-local series runs after the main one, with its own numbering | Let it finish — it is not a loop |
| A piped or CI upgrade prints nothing | Progress goes to stderr only when it is a terminal | Not a stall; wait for exit |
A shared dolt sql-server did not migrate at all
| It is never auto-migrated; consent is explicit (#5920, #6048) | Upgrade every client, then bd migrate schema once — or BD_ALLOW_REMOTE_MIGRATE=1 in scripted use
|
bd serve refuses to start against a proxied store
| A daemon has no operator to consent for it, and the gate now covers that path (#6055) | Reconcile the schema first, or set BD_ALLOW_REMOTE_MIGRATE=1 as standing consent for the service
|
Another machine's bd refuses the database after one client upgraded
| Forward schema-skew guard: a mixed-version fleet is a broken fleet | Upgrade every client together; check which -a bd; designated-migrator flow for multi-clone stores
|
bd dolt push / bd dolt pull refused after installing 1.3.0
| The pending-migration gate covers sync, not just bd migrate
| Finish syncing with the old binary first, or migrate and push from the designated migrator |
A long-running bd --readonly serve does not come back up
| The flag is now refused instead of binding a silently writable server | Drop --readonly from the serve invocation
|
⛔ workspace is frozen for migration, exit 14
| A MIGRATION-FREEZE sentinel in the workspace root, the cwd, or an ancestor of either
| Remove the file the message names (or unset BD_MIGRATION_FREEZE_FILE) once the migration is done
|
Open refused over "backend": "sqlite" in .beads/metadata.json
| A stale field from the 1.2.x era; the live data is Dolt | Apply the exact one-field edit the rejection message gives |
First bd purge after upgrade clears far more than usual
| Legacy typed wisps are now reachable by the tier predicate | Expected, one-time (#5995) |
| A cross-rig bead gate stays pending under a proxied-server rig | Known limitation: multi-rig prefix routing (routes.jsonl) is not supported with proxied-server rigs (#5861)
| bd gate check, or bd close --force
|
Validation
- The release was cut from
release/1.3.0, and every change on the branch
landed through a reviewed PR against it — 28 of them, driven by a full
pre-tag release audit. - The full check matrix is green at the branch tip. The release-prep PR
(#6038), whose merge commitb3ef65c8is the tip, was tested on a head that
had already merged #6088: 122 checks green, 1 skipped, 0 failing. That
matrix is the Embedded Dolt Cmd shards (20), Embedded Dolt Storage shards
(5), Proxied Dolt Cmd shards (15) and Server Dolt Full Suite shards (16),
plus Embedded Dolt Conformance (core and audit), Server Dolt Conformance, the
storage-backend conformance oracle, the contract corpus, the Differential
Regression against the v0.49.6 baseline, the macOS lane, the Windows lanes
(native/msys2/cygwin make shells, dbproxy server,doltversion,cmd/bd
liveness, worktree-remove boundary), andnix build .#default. - The last red lanes were closed before the prep PR, and only one was a
product defect. #6088 was that one — the #6048 consent gate had swept in
bd-owned auto-started servers and re-checked itself on every schema-init
retry, red across the Server Dolt matrix — now fixed and pinned by
TestSharedServerDatabasein both directions. The other three were harness
bugs: ajsonOutputglobal leak breaking the shared-migrate-refusal subtests
in full-package runs (#6073), a freeze-marker path comparison that was not
symlink-safe, which is what the macOS doctor freeze-gate failures were
(#6087), and the missing assertion for #6053's string revision token in both
showsuites (#6086). - Upgrade smoke ran the five legs that matter for this release — v1.1.0,
v1.1.2, v1.2.1, v1.2.2 and v1.2.2-rc.1 → candidate — alongside 14 historical
upgrade lanes from v0.9.1 through v1.2.2. - A new wisp-plane upgrade corpus (#6049) seeds and asserts the clone-local
plane the 1.3.0 migration chain rewrites — wisps, wisp deps and comments,
leases, events, and the ignored-track cursor — across v1.0.1/v1.1.x/v1.2.2 →
candidate, closing the coverage hole behind this release's sentinel-replay
and restamp fixes. - The v53 → v66 upgrade, the shared-server consent flow, the backup-first
recipes, and the multi-clone designated-migrator flow are documented in
Upgrading, with the
cursor-rollback procedure in the
recovery runbook. - RC tag gates, all green. The
v1.3.0-rc.1release pipeline completed
withverify-version-consistency, both goreleaser legs (linux + darwin),
both package gates (MCP, npm), and release attestation successful, and both
registry publish jobs skipped by prerelease gating. The tag-triggered
Migration Test Harness and Cross-Version Smoke runs both passed. The
publishedlinux_amd64archive checksum-verifies and reports
1.3.0-rc.1 (9c6a69ec1). A local validation battery against the tag passed
the full release stability gate — all 7 upgrade scenarios from each of
v1.2.2, v1.1.2, and v1.1.0, including the new wisp-plane leg — plus
fresh-workspace, migration-UX (28 steps, counter restart as documented),
forward schema-skew guard, migration-freeze, and journal-actor checks.
Installing
For the v1.3.0-rc.1 prerelease, take the binary from this release's
assets — the package managers below track the latest stable release and will
not pick up a prerelease. For the final v1.3.0, use the command that
matches your install method:
# macOS / Linux / FreeBSD
curl -fsSL https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh | bash
# Homebrew (macOS, Linux)
brew upgrade beads
# npm
npm update -g @beads/bd
# go install — server-mode only
CGO_ENABLED=0 go install github.com/steveyegge/beads/cmd/bd@latest
# go install — embedded-capable
CGO_ENABLED=1 GOFLAGS=-tags=gms_pure_go go install github.com/steveyegge/beads/cmd/bd@latest# Windows
irm https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1 | iexIf you still have the old tap formula installed as bd, switch to the Homebrew
core formula:
brew uninstall bd
brew untap gastownhall/beads 2>/dev/null || true
brew untap steveyegge/beads 2>/dev/null || true
brew install beadsWhatever you use, run which -a bd afterwards: a second binary earlier in
PATH is the fleet-skew failure described in the upgrading notes.
Contributors
Thanks to everyone who contributed to v1.3.0 (between v1.2.2 and
release/1.3.0 — which, because v1.2.2 re-shipped the v1.1.2 tree, spans the
whole 1.2 line's work):
@A3Ackerman, @AJBcoding, @anisoptera, @aphexcx, @arcaven, @aryrabelo,
@athosmartins, @banozz0, @bee-ghosttrack, @boardthatpowder, @brendan-appstart,
@chrisjunlee, @coffeegoddd, @cosentinode, @csauer02-personal-user, @csells,
@cuongbphv, @daniel-jasinski, @davevan2, @DyrtyJax, @ecuthiell, @enieuwy,
@eric-richardson1, @Ethee, @GraemeF, @HackAttack, @harry-miller-trimble,
@heymatthew, @iamthebot, @idirectships, @idvorkin-ai-tools, @imkp1,
@itsandyking, @jacobhausler, @jamelt, @jdelic, @jjgarzella, @johnzook,
@joshuaguyervs, @julianknutsen, @kevglynn, @Kevinwochan, @liviux,
@lumaks-redox, @maphew, @marcodelpin, @marlon-costa-dc, @maxinflection,
@mccraigmccraig, @mlushpenko, @mohamedramadan14, @Mosnar, @MovGP0, @mwotton,
@nova-submodules, @ousamabenyounes, @Photobombastic, @postoso, @prmichaelsen,
@pvinis, @quad341, @RaviTharuma, @remuscazacu, @rjc123, @Rome-1, @ryanwclark1,
@scotthamilton77, @shaunc, @shiminshen, @ShiroKSH, @shon-yuan, @sjarmak,
@srobroek, @steveyegge, @swedeinasia-flow, @thewoolleyman, @Toady00,
@uschtwill, @vishnujayvel, @Wldc4rd, @zach-source, @Zireael
Special thanks to the external contributors whose fixes were carried onto the
release branch:
- @marcodelpin (Marco Del Pin), whose diagnosis and fix for dolt#11131 encoding
drift lets the migration path survive tables it cannot read — carried and
reworked as #5064 by @maphew (matt wilkie) - @Toady00 (Brandon Dennis), whose #5783 makes server mode honor
Config.LenientOpenso the dirty-table refusal's own recovery works - @nova-submodules (Nova Latent), whose #5740 diagnosis and fix for
server-mode lost updates was carried as #6040 - @anisoptera (Isis Anisoptera), whose #5625 recognizer for Homebrew
--HEAD
version stamps was carried as #6079, keeping a HEAD build out of the
.dolt-deleting pre-v56 recovery
Recommended Reading
- Upgrading guide
- Recovery runbook: cursor rollback
- Dolt architecture: embedded and server modes
- Federation and multi-replica leases
- Events journal reference
- Full changelog, including the withheld [1.2.1] section
Full Changelog: v1.2.2...release/1.3.0