What Is a Bead in Gas Town and How Is It Stored?
A Bead in Gas Town is the fundamental unit of work in the Beads issue-tracking system, stored as plain-text JSONL records inside the repository's .beads directory rather than an external database.
In the gastownhall/gastown repository, the Bead abstraction serves as the native currency for tracking tasks, agent states, and ephemeral merge requests. All bead data lives directly within the repository filesystem, enabling complete offline portability and version-controlled issue management.
Types of Beads in Gas Town
A Bead represents a flexible concept that adapts to different workflows within the Gas Town ecosystem. The system distinguishes between several bead types using label conventions:
- Task / Bug / Feature beads – Standard development issues tracked through the development lifecycle.
- Agent beads (
gt:agentlabel) – Persistent state containers for Gas Town agents such as polecats or deacons, stored in the same database but representing autonomous entities rather than human tasks. - Merge-request beads (
gt:merge-requestlabel) – Lightweight, transient "wisps" that represent merge requests without persisting as permanent issues. - Specialized beads – Additional categories including rig beads, role beads, and standing-order beads, each identified by dedicated labels for infrastructure and automation purposes.
Storage Architecture and Repository Layout
Gas Town stores all beads inside the repository, eliminating dependencies on external issue-tracking services. The storage system utilizes a plain-text JSON Lines (JSONL) format for durability and git compatibility.
Locating the Beads Database
The system discovers the town root by traversing upward from the current working directory until it locates a mayor/town.json file. Once identified, the beads database resides at <town-root>/.beads.
The effective storage path is computed by getResolvedBeadsDir in internal/beads/beads.go (lines 49-56), which checks for a BEADS_DIR environment variable override before defaulting to the standard .beads directory.
File Organization
The .beads directory maintains separate files for different bead lifecycles:
.beads/issues.jsonl– Contains persistent beads including tasks, bugs, features, and agent states. Each line represents a complete JSON record..beads/wisps.jsonl– Stores ephemeral beads such as merge-request wisps that do not require long-term persistence.
The Beads CLI (bd) and the Go wrapper in internal/beads read and write these files either through subprocess calls or directly via the beadsdk.Storage interface.
Go Implementation Details
The core bead logic resides in the internal/beads package, specifically within internal/beads/beads.go.
The Issue Struct
The type Issue struct (lines 75-96) defines the schema for a bead in memory:
type Issue struct {
ID string
Title string
Labels []string
Status string
Assignee string
HookBead bool // Marks agent-related beads
AgentState string // Serialized state for agent beads
// ... additional metadata fields
}
The Beads Wrapper
The Beads struct (lines 30-44) provides the high-level API for interacting with the database:
FindTownRoot– Locates the repository root by searching formayor/town.json.ResolveRoutingTarget– Handles cross-rig bead routing when beads reference external repositories.- Storage abstraction – Supports both CLI invocation (
bdbinary) and in-processbeadsdk.Storageaccess.
Working with Beads: Code Examples
Creating a Task Bead
Use the Beads wrapper to create standard issues:
b := beads.New(".") // Initialize wrapper for current working directory
err := b.Create(beads.CreateOptions{
Title: "Add user authentication",
Labels: []string{"gt:task"},
Priority: 1,
Description: "Implement login flow using OIDC",
})
Listing Open Tasks
Filter beads by status and label:
openTasks, _ := b.List(beads.ListOptions{
Status: "open",
Label: "gt:task",
})
for _, t := range openTasks {
fmt.Printf("%s – %s\n", t.ID, t.Title)
}
Accessing Agent Bead State
Agent beads bypass standard routing prefixes and expose dedicated state fields:
// Retrieve agent state regardless of ID prefix
agentBead := b.ForAgentBead().Show("gt-abc123")
fmt.Printf("Agent state: %s\n", agentBead.AgentState)
Querying Merge Request Wisps
Ephemeral merge-request beads combine data from both persistent and ephemeral stores:
mrs, _ := b.ListMergeRequests(beads.ListOptions{Status: "open"})
for _, mr := range mrs {
fmt.Printf("MR %s: %s (assignee %s)\n", mr.ID, mr.Title, mr.Assignee)
}
Summary
- A Bead in Gas Town is the fundamental unit of work tracked by the Beads system, capable of representing tasks, agent states, or ephemeral merge requests.
- All beads store data inside the repository under the
.beadsdirectory, not in external databases. - Persistent beads reside in
.beads/issues.jsonl, while ephemeral wisps live in.beads/wisps.jsonl. - The town root is discovered by locating
mayor/town.json, with storage paths resolved bygetResolvedBeadsDirininternal/beads/beads.go. - The Go API provides the
Beadswrapper struct andIssuetype for programmatic CRUD operations, supporting both CLI and direct storage interfaces.
Frequently Asked Questions
What is the difference between issues.jsonl and wisps.jsonl?
The issues.jsonl file stores permanent beads including tasks, bugs, and agent states that require long-term tracking and version history. The wisps.jsonl file contains ephemeral beads such as merge-request wisps that represent transient workflow states and do not need to persist indefinitely in the repository history.
How does Gas Town locate the .beads directory?
Gas Town discovers the beads directory by walking up the filesystem from the current working directory until it finds a mayor/town.json file, which marks the town root. The .beads folder must reside at this root level. The FindTownRoot method in the Beads wrapper implements this traversal logic.
What is an agent bead in Gas Town?
An agent bead is a specialized bead type marked with the gt:agent label that stores the persistent state of a Gas Town autonomous agent, such as a polecat or deacon. Unlike task beads, agent beads contain a dedicated AgentState field and are accessed through the ForAgentBead() method to bypass standard routing prefixes.
Can beads be stored outside the repository?
While the default behavior stores beads within .beads at the town root, the system supports the BEADS_DIR environment variable to override the storage location. The getResolvedBeadsDir function (lines 49-56 in internal/beads/beads.go) checks for this override before returning the default path, though external storage breaks the version-control integration that makes Gas Town portable.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →