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!

Figure 1: Local proxy shutdown returns idle RAM and eliminates the stopped processes' CPU work, with an expected battery benefit; while active, the 20-workspace shared-server setup used about the same RAM as direct servers and the local setup used 39% more.
RAM, CPU, and power with proxied Dolt in Beads 1.3: 20 idle workspaces use 2,456 MB with direct servers, 603 MB with one shared server and proxies, or zero after local proxy shutdown. Direct servers use about 1.6 CPU-seconds each per idle hour; stopped local processes use zero. A full battery illustrates the expected benefit of less background work; power and battery savings were not measured. Across 20 active workspaces, shared-server proxies used 2.43 GB, about the same as the 2.48 GB direct baseline; local-server proxies used 3.45 GB, about 39% more.

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.

Figure 2: The original hand-drawn sketch for the Beads event factory visualizer, annotated in red.
The original hand-drawn sketch for the Beads event factory visualizer, annotated in red.

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.

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.

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.

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:

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 search now includes closed issues. Add --status open when a script needs only issues whose status is open; bd list still excludes closed issues by default.
  • Some bd list --ready filter 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 update now follows close policy. Moving an issue to a done status fails when it has open children or a live blocker, just like bd close; use bd update --force only when you mean to override that guard.
  • bd config list now only returns the actual configuration. Use bd kv list or bd memories instead of parsing those values from bd config list.
  • bd delete --force no longer implies cascading deletion on proxied servers. It leaves dependents in place; use --cascade --force when you intend to delete the dependent subtree too.
  • bd dep cycles --json has a new result shape. Consumers must handle objects containing members and partial, rather than arrays of issue arrays.
  • --profile is 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 push or bd sync must explicitly consent with --yes when that adoption is intended, or configure the remote beforehand.
  • Go integrations have interface changes. The published backend package no longer exposes orphan-handling symbols. Types implementing beads.Storage must also implement several new methods, including IssueClaimer, IssueReader, and ReadyClaimer; the change is broader than adding one method. Check the complete interface when updating an implementation.
  • BEADS_DIR must point at the .beads directory itself. A project root now fails with “no beads database found” instead of resolving upward.
  • bd dolt status --json has a new shape on proxied workspaces. It reports proxy and backend processes separately.
  • bd ready includes custom statuses in the active category. 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!