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:agent label) – 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-request label) – 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 for mayor/town.json.
  • ResolveRoutingTarget – Handles cross-rig bead routing when beads reference external repositories.
  • Storage abstraction – Supports both CLI invocation (bd binary) and in-process beadsdk.Storage access.

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 .beads directory, 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 by getResolvedBeadsDir in internal/beads/beads.go.
  • The Go API provides the Beads wrapper struct and Issue type 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →