my-city with my-project rigged, the pancakes
formula cooked, and mayor / reviewer / worker agents (see
Tutorial 05). Everything below runs against the bead
store with the bd tool.
Confirm the local pack, rig registration, and reviewer binding carried forward
from the earlier tutorials:
What is a bead
A bead is a unit of work with an ID, a title, a status, and a type. We use thebd tool to work with beads directly.
pancakes beads come from cooking the formula in
Tutorial 05: a root bead (mc-79s), one bead per
step, and the Finalize workflow control step the v2 compiler appends. Each is
an independent top-level bead with its own ID; ordering lives in dependency
edges (below). The leading glyph is status, followed by ID, priority (P2),
and title. Pass --flat for a single-level list, --all to include closed
beads. Your inventory will differ — Refactor auth module, Sprint 42, and
Update API docs are created later on this page. The shape is what matters.
Every bead has:
- ID — prefixed with two letters from the city or rig name (
mc-194for “my-city”,ma-12for a rig “my-app”) - Title — human-readable name
- Status —
open,in_progress,blocked,deferred, orclosed - Type — what kind of bead it is
Bead types
The type determines what a bead represents:
There’s no separate storage for tasks vs. messages vs. sessions — one store,
one query interface, one dependency model for everything. That’s what makes the
system composable.
A formula has no type of its own. Cooking or slinging one produces plain
task
beads: the root carries gc.kind=workflow metadata, and an ephemeral
root-only run carries gc.kind=wisp. The kind lives in metadata, not the type
column. (The v1 materialization wrapped a run in a dedicated molecule
container bead with parent-child step children; the current one uses plain
task beads plus gc.kind metadata.)
Creating beads
Most beads are created indirectly:gc session new my-project/reviewercreates a session beadgc mail send mayor "Subject" "Body"creates a message beadgc formula cook reviewcreates a workflow root plus a bead for every stepgc sling mayor review --formuladoes the same and routes the work tomayor
bd to create them manually:
Priority:, Status:) vary by bd version — some builds
print one, some both. The bead is created identically either way. The
dependency and convoy examples below use all three of these beads.
Bead lifecycle
Beads flowopen → in_progress → closed:
- open — not started; discoverable by agents via hooks.
- in_progress — claimed by an agent.
- closed — done.
- blocked — has an open
blocksdependency. Set automatically. - deferred — snoozed until a date.
blocked and
deferred are derived states the system manages for you.
--status (--state is a different command for state
dimensions). As with the opening listing, the output here is trimmed to the
beads this page created — yours will still include the open pancakes beads
and the mayor’s session bead.
Beads as execution state
The bead store is the execution state of the whole system — every running session, message in flight, and formula step is a bead with a status. To know what the city is doing right now, query the store:Labels
Labels are how beads get organized and routed:bd label add takes a single label per call — apply multiples one at a time.
Some labels have special meaning in Gas City:
gc:session— marks session beadsgc:message— marks mail beadsthread:<id>— groups mail messages into conversationsread— marks a message as read
Metadata
Beads carry arbitrary key-value metadata for structured state:session_name, alias), routing
(gc.routed_to), merge strategies, and formula references. Attach anything you
like without touching the title or description; --unset-metadata <key> removes
one.
Dependencies
Beads depend on other beads. You saw this in formulas —needs = ["design"] is
a blocking dependency, so the step can’t start until the design bead closes.
This is how Gas City orders work without a central scheduler: each bead knows
what it waits for, and agents see only ready work.
mc-xp7 won’t appear in any agent’s work query until mc-a4l is closed —
the same mechanism behind formula step ordering, where needs declarations
become blocks edges.
The dependency types:
Only
blocks affects work visibility — it expresses ordering (“do A before
B”). The rest express grouping (“these beads belong together”): v2 workflow
steps tracks their root, convoys tracks their members, and v1 molecules use
parent-child. A convoy’s members don’t depend on each other; they’re just the
same batch.
Convoys
Slinging an existing bead wraps it in a convoy automatically. Convoys answer batch questions — “are all five of these tasks done yet?” — and show up inbd list as type convoy and in gc convoy list with progress summaries.
You can also create one by hand to group arbitrary work as a sprint or deploy:
convoy bead; membership is tracks edges from it to each
member — the “tracking 3 issue(s)” above. Tracking is pure grouping: it changes
no parent and blocks nothing.
Auto-close
When a bead closes, any convoy tracking it whose members are now all closed closes itself — in the background via theon_close hook, no polling.
Convoys with the owned label skip auto-close, for workflows where you want
explicit control over completion:
Adding beads and checking convoys
Work grows after a convoy is created — a bug surfaces mid-sprint. Add beads to an existing convoy:Stranded work
To find open beads in convoys that have no assignee — work that’s stuck waiting for someone to pick it up:Convoy metadata
Convoys carry metadata that controls how grouped work behaves:convoy.owner— which agent manages this convoyconvoy.notify— who to notify when the convoy completesconvoy.merge— merge strategy for PRs (direct,mr,local)target— target branch inherited by child beads
How agents find work
Routed agents discover work through the claim protocol in their session startup prompt, which runsgc hook --claim. (The legacy Stop-hook form gc hook --inject is silent compatibility behavior and no longer injects work.) The
flow:
- Work is created (
bd create,gc sling, formula cook, …) - Work is routed to an agent (assignee or
gc.routed_tometadata) - Session startup runs the agent’s work query through
gc hook --claim - The hook atomically claims one ready bead and preassigns continuation siblings
- The agent runs the claimed work — find work on your hook, you run it
mc-xp7 is blocked by mc-a4l, so this query won’t return it — blocked work
is invisible to work queries. Once mc-a4l closes, rerun the same query. The
readiness barrier is gone, though mc-xp7 would also need
gc.routed_to=my-project/worker to land in this queue, which nothing here
sets. Routing decides which queue a bead appears in; readiness decides
whether it appears at all.
This is the “pull” model: agents check for work instead of having it pushed.
The bead store
Beads are persisted in a store. Gas City supports several backends:- bd (default) — Dolt-backed database via the
bdCLI. Full-featured, good for production. - file — JSON file on disk. Simple, good for tutorials and small setups.
- exec — Delegates to a custom script. For integration with external systems.
city.toml:
You rarely touch beads directly —
gc session, gc mail, gc sling, and gc formula handle creation and management. You reach for bd when you want to
query outstanding work across the city, create ad-hoc tasks, inspect a
formula’s dependency graph, or debug why an agent isn’t picking up work.
(Listings trimmed to this page’s beads; open pancakes beads will show up in
yours too.)
Sprint 42 entry under BLOCKS is the convoy’s incoming tracks edge —
grouping, not a blocker.
Beads are the ground truth of the city’s running state. Sessions, mail, and
convoys are beads; a formula materializes its work as beads when run.
What’s next
- Orders — formulas and scripts on autopilot, triggered by time, schedule, conditions, or events