Welcome to Beads… 1.3? What happened to 1.2? A Bee! Curious? Read the incident report.
For those new to Beads, it is a
vendor-neutral, durable task tracker for coding agents. Each bead records a
state such as open, in_progress, or closed and can depend on other beads.
This gives agents persistent, structured work across sessions: useful for crash
safety, multi-agent orchestration, and keeping a record of what remains to be
done.
This article also covers Gas City 1.5.0, which has been updated to take advantage of all of the Beads features in this new release.
For those new to Gas City, it’s an open platform for building your own software factories, built on Beads. Gas City orchestrates agents, allowing the dispatching of repeatably high quality work to be as simple as prompting. Instructions called formulas turn work into beads and guide agents through workflows such as review pipelines and visual QA inspections.
Ease of Migration
Beads 1.2.x focused on preventing schema forks when multiple clones share a single Dolt remote. This made it safer and easier to migrate your Beads database to the latest version of Beads, always a problem in the past.
Building on that same theme, Beads 1.3 can apply pending schema changes when it opens a supported embedded database. For a local workspace without a Dolt remote, migration can happen on the first ordinary command after upgrading. This happens almost completely automatically (although the upgrade guide provides the nitty gritty if you’re interested).
In our lab tests, we have been able to migrate more than 300 different Beads schemas from previous versions to the latest schema, safely and automatically.
I personally tested the upgrade from 1.2.2 to 1.3.0 using the released binaries and a synthetic database containing 27,472 records and 39 dependencies. All exported issue content and dependencies survived the upgrade, and I could create and read a new bead afterward.
Proxied Dolt
Being easier to upgrade isn’t a reason to upgrade by itself, so what else
does 1.3 offer? The first improvement is in bd’s database backend, Dolt. The
new experimental proxied Dolt mode lets idle workspaces give your laptop a break.
If you switch between projects, their database servers shouldn’t have to keep
running while you work on something else.
Proxied Dolt is opt-in. It adds a proxy between bd and Dolt, keeps the database
available between commands, and shuts down the processes it manages after an
idle timeout. The next command starts them again when needed; your database
stays on disk.
How much difference does that make?
In our twenty-workspace test, direct servers held onto about 2.5 GB of RAM while idle. With a proxy in front of one shared server, that dropped by ~75%. With a local proxy for each workspace, idle process memory dropped to zero. The processes had stopped, so there was nothing left to keep in memory!
Those two proxy setups work a little differently. With a shared external server, the idle proxies stop but the server stays running. That comparison also replaces twenty servers with one, so the saving comes from the whole setup. In local mode, each workspace’s proxy and Dolt process both stop.
Stopped processes don’t use CPU, either. The release benchmark measured that idle CPU use falling to zero after local shutdown. Less background work means less laptop battery usage when idle databases stop.
The performance notes in the 1.3.0 release corroborate the idle savings and local active-memory tradeoff in our benchmarks. This test compared server configurations, not embedded Dolt, using a 30-second idle timeout. It ran on one machine under heavy unrelated load, with a Dolt CLI one patch behind the pinned version; the exact savings will depend on your setup.
To take advantage of proxy mode, run the following command when creating a new Beads database:
bd init --proxied-server --proxied-server-idle-timeout 5m
The “5m” at the end indicates how long the proxy can remain idle before it
shuts down (5m == 5 minutes). Running a bd command that uses the database
can reset the idle timer.
Watch It Run with Events
More performance options are great, but what I bet some of you will like more is events. Specific bead mutations are now appended to an ordered event journal. If you want to build a dashboard or react when a bead changes, you now have a stream to follow. Each entry identifies the operation, its sequence number, the affected bead, and the state available to consumers (event-journal landing).
The journal is off by default. You opt-in per workspace:
$ bd config set events-journal true
Set events-journal = true (in config.yaml)
Here is a short run through creating two beads, adding a dependency, and getting the work done:
$ bd events tail --since 0 --limit 8 \
| jq -c '{seq,op,issue_id,status:(.issue.status // null),blocked:(.issue.is_blocked // false)}'
{"seq":1,"op":"create","issue_id":"demo-blocker","status":"open","blocked":false}
{"seq":2,"op":"create","issue_id":"demo-article","status":"open","blocked":false}
{"seq":3,"op":"dep_add","issue_id":"demo-article","status":"open","blocked":true}
{"seq":4,"op":"comment","issue_id":"demo-article","status":"open","blocked":true}
{"seq":5,"op":"update","issue_id":"demo-article","status":"open","blocked":false}
{"seq":6,"op":"close","issue_id":"demo-blocker","status":"closed","blocked":false}
{"seq":7,"op":"update","issue_id":"demo-article","status":"in_progress","blocked":false}
{"seq":8,"op":"close","issue_id":"demo-article","status":"closed","blocked":false}
The journal covers create, update, close, delete, dep_add,
dep_remove, and comment. A consumer can remember the last seq it processed
and use --since to request later entries. That gives external tools an ordered
change stream without requiring them to query Dolt tables or follow changes to
Beads’ storage implementation. The journal is local to a clone and branch; it
isn’t pushed or federated, and each replica has its own sequence space. By
default, Beads retains at least seven days and 100,000 rows, so a consumer also
needs to handle a checkpoint that has fallen behind the retained window.
That mechanism makes visualizers easier to build, and it is the feature I am most excited about. To exercise each operation, I sketched out a Beads factory, plugged the idea into Codex, and built this interactive demo.
My demo styled like a factory serves as a proof of concept. The community has already taken the journal much further, so here are a few visualizers that use it.
First up, we have Mardi Gras by Matt Wright. This parade-themed TUI offers a fun and colorful take on a more productivity-focused Beads visualizer, showing the state of your beads with parade metaphors (rolling for in progress, lined up for ready, stalled for blocked). That makes the current state of your beads simple to digest. You can change bead statuses or create new beads from it, and because it follows the journal, it updates in real time as work completes.
Slide 1 of 4: Figure 3: In a fictional workshop project, the registration API contract holds up four downstream tasks in Mardi Gras's Stalled section.
Next up, we have bddb by
Mikhail Beliakov, a kanban board interface for Beads.
Using the Beads 1.3 journal and bd serve, the board gets live updates as agents
work without needing to manually refresh the page. Journaling must be enabled
in each workspace the agents write from; otherwise, their changes appear on
the next polling cycle. The dashboard also lets you change the status and
priority of beads directly from the board.
Slide 1 of 4: Figure 4: Before the CLI command runs, the sample design task is open and the form task has a Blocked badge.
Honorable mention: Reef. Stephanie Jarmak, a Gas City maintainer and the main contributor to its new dashboard, built the experimental Reef visualization. Reef turns live sessions into fish and beads into morsels. It predates 1.3 and reads the Gas City supervisor APIs rather than the event journal, so it is not a demo of the new API. However, it shows how much personality a Beads visualizer can have.
Slide 1 of 3: Figure 5: The Reef dashboard visualizing Gas City sessions as fish and Beads as morsels.
These three community visualizers are just a small sample of the hundreds we found while preparing this article, including 75 that are actively maintained. We reached out to a bunch of the ones that are actively maintained and many of them have already moved to the event-based support in Beads 1.3. If you’d like a recommendation, check out the list of community beads viewers we maintain. And if yours isn’t on that list, we’re happy to add it with a docs PR!
We have been blown away by the breadth and depth of the community’s work. From the whole Gas City team: Thank you to those who help make Beads a better tool.
Also New in 1.3
Work leases keep dead agents from stranding tasks. A claim now gets a
five-minute lease. Active workers refresh it with bd heartbeat, and
bd reclaim returns expired work to the ready queue after a grace period
(#4537).
By default, that grace period is another ten minutes after the lease expires.
bd sync combines remote syncing steps into one command. It pulls, checks for
conflicts, recomputes blocked state, and pushes, with distinct exit codes for
conflicts and retryable races.
bd serve exposes Beads over HTTP. Supported server-backed workspaces can
serve the same work surface to long-running automation clients instead of
forking a bd process for every request
(first v0 API landing).
Authentication is off by default on loopback; a non-loopback bind requires a
token file unless you use the explicit insecure override.
Provenance records connect work to outside artifacts. bd provenance
links a bead to the commit, PR, branch, work ID, or transcript behind it
(#4461). That gives you a trail
from the task to what actually happened. Records are typed and deduplicated;
an agent, GitHub Action, or hook still has to append them.
Large reads can be much smaller. bd list --brief and
bd ready --json --brief omit free-form text fields, so agents don’t have to
read every description just to find their next task. Deferred work also returns
to the ready queue on the next ready read after its date passes.
Shared-server clients stop piling on duplicate automatic backups by default. Previously, multiple Beads clients could each decide to back up the same Dolt database, pinning its CPU. Beads 1.3 turns that automatic default off for server-backed workspaces (the fix). Explicit backup settings still win, so make sure your backup plan is intentional. Gas City has disabled these automatic backups in its managed Beads commands since Gas City 1.3; this is a Beads improvement for other shared-server clients.
These features are covered in the published 1.3.0 release notes.
Gas City 1.5
If you use Beads through Gas City, Gas City 1.5.0 uses Beads 1.3.1 and enables proxied-server mode for fresh city and rig scopes. Beads owns the Dolt processes in those scopes.
Existing cities keep their current topology until explicitly migrated; upgrading the binaries alone does not convert those stores. Moving an existing city to proxied mode is optional, one-way, and covered in the Gas City docs: hand the city’s Dolt process to Beads.
Gas City 1.5.0 accesses proxied stores through the bd CLI; native database
access is not enabled in that mode.
Also New in Gas City 1.5
A preview SQLite ledger for infrastructure beads. A city can move its execution graph, sessions, messaging, orders and nudge queue off the work ledger onto a dedicated SQLite store. On a production-scale city, that measured 130–250× faster infrastructure reads. It’s opt-in and experimental, so try it on a throwaway city first.
Maintenance works on every topology. The reaper, JSONL export and backup
orders now reach the city and every rig through gc bd, so proxied,
Gas City-managed and mixed cities all get reaped, archived and backed up. When
an order can’t do part of its work, a new order.skipped event says so.
gc doctor leaves a stopped city stopped, and checks your backups. Running
it no longer starts a stopped store, and a new check warns when a proxied scope
has no recent backup.
Sessions and pools are harder to break. Claim and close share one identity,
and the orphan sweep, the corpse cleaner and gc session kill no longer take
out live or resumable sessions.
The Dolt compactor protects shared history. It never flattens a database that has a remote, so history your clones depend on stays intact.
The Gas City pack binds as gc. New cities import it as [imports.gc],
and gc doctor --fix offers to rename an existing [imports.gascity].
The rest is in the Gas City 1.5.0 release notes.
Updating
Back up with the old binary
before installing the new one. A command such as
bd export can itself open and migrate a database under the new binary, making
the resulting export too late to serve as a pre-upgrade backup. If you are
still on the retracted 1.2.1 release, follow its
recovery guidance
before treating it as a normal upgrade source.
If you use Gas City, upgrade Gas City and let it bring Beads along. If you use Beads on its own, upgrade Beads.
Upgrading Through Gas City
The gascity Homebrew formula depends on beads, so brew upgrade gascity
upgrades Beads to 1.3.1 too. Coming from Gas City 1.4.2, the Beads schema is
already current. Coming from Gas City 1.4.1 or earlier, your city’s Beads
databases also need a one-time schema migration. The Gas City docs walk through
upgrading an existing city:
backing it up, upgrading, migrating the city and each rig, and checking the
result.
Upgrading Beads Directly
If you use Beads on its own, brew upgrade beads installs 1.3.1. If you also
run Gas City, upgrade Gas City instead: it pins the Beads version it was
tested with. How you migrate depends on where your database lives, and the
Beads upgrade guide covers each case:
- A local embedded database: the first command after upgrading applies the migration.
- A shared Dolt server: upgrade every client first,
then consent once with
bd migrate schema. - Clones sharing a Dolt remote: sync every clone with the old binary, migrate exactly one, and have the others adopt it.
- Anything from before 1.0: current Beads refuses older storage layouts rather than opening them, and the guide gives the explicit migration for each.
Whichever case applies, run the one-command blocked-flag repair on each database once it has migrated, so no ready work stays hidden.
Breaking Changes
These are selected changes that can affect scripts and integrations upgrading from 1.2.2 or the 1.1 line. The final release notes contain the full highlights list, including work withheld from 1.2.2:
bd searchnow includes closed issues. Add--status openwhen a script needs only issues whose status isopen;bd liststill excludes closed issues by default.- Some
bd list --readyfilter combinations now fail. Filters that the ready path cannot honor return an error instead of being silently ignored. - Dependency type values are limited to 32 characters. The database has always stored 32; validation now rejects longer values before they reach it.
- Closing through
bd updatenow follows close policy. Moving an issue to a done status fails when it has open children or a live blocker, just likebd close; usebd update --forceonly when you mean to override that guard. bd config listnow only returns the actual configuration. Usebd kv listorbd memoriesinstead of parsing those values frombd config list.bd delete --forceno longer implies cascading deletion on proxied servers. It leaves dependents in place; use--cascade --forcewhen you intend to delete the dependent subtree too.bd dep cycles --jsonhas a new result shape. Consumers must handle objects containingmembersandpartial, rather than arrays of issue arrays.--profileis now--cpu-profile. The old flag has no compatibility alias.- Adopting a Dolt remote from Git origin now requires consent. Scripts that
relied on silent adoption by
bd dolt pushorbd syncmust explicitly consent with--yeswhen that adoption is intended, or configure the remote beforehand. - Go integrations have interface changes. The published
backendpackage no longer exposes orphan-handling symbols. Types implementingbeads.Storagemust also implement several new methods, includingIssueClaimer,IssueReader, andReadyClaimer; the change is broader than adding one method. Check the complete interface when updating an implementation. BEADS_DIRmust point at the.beadsdirectory itself. A project root now fails with “no beads database found” instead of resolving upward.bd dolt status --jsonhas a new shape on proxied workspaces. It reports proxy and backend processes separately.bd readyincludes custom statuses in theactivecategory. Ready counts can rise after upgrading.
Where Are We?
The event journal gives tools an ordered record of bead changes without tying them to Dolt’s table layout. My factory demo and the community tools above show how much personality and practical help those windows into the work can offer.
Our tests covered upgrades from more than 300 historical Beads schemas. In our shared-server test, idle RAM use dropped by about 75%. Idle shutdown may also help laptop battery life.
Whatever part of 1.3 brings you over, back up first. And if you run Beads through Gas City, bring 1.5.0 and Beads 1.3.1 along.
Have thoughts about this post? Join the Gas Town Hall Discord!