How Town-Level Beads Are Organized and Prefixed in Gas Town: A Complete Guide

Town-level beads in Gas Town are stored in a hidden .beads directory, identified by the prefix defined in routes.jsonl (typically "hq-"), and resolved to the town root when the route path is set to ".".

In the gastownhall/gastown repository, understanding how town-level beads are organized and prefixed is essential for working with the Mayor, Deacon, and role beads that define a town's configuration. The architecture uses a dedicated database location and a prefix-based routing system to distinguish town-wide beads from rig-specific ones. This design allows Gas Town to maintain a single source of truth for town-level state while supporting distributed rig configurations.

Understanding the Town-Level Bead Architecture

A town in Gas Town represents the top-level workspace, identified by the presence of mayor/town.json at its root. All beads belonging to the town itself—including Mayor, Deacon, and role beads—are stored in a single Beads database located in the town's hidden .beads directory.

This centralized storage model ensures that town-wide configuration remains atomic and portable. Unlike rig-specific beads that may reside in separate database files, town-level beads consolidate authority data in one location relative to the town root.

The routes.jsonl Prefix Mapping System

The mapping between a bead-ID prefix and the physical database location is defined in routes.jsonl, a JSON-lines file stored inside the .beads directory. For town-level beads, the entry follows this structure:

{ "prefix":"hq-", "path":"." }
  • prefix: The string that appears at the start of every town-level bead ID, including the trailing hyphen (e.g., "hq-").
  • path: When set to ".", it indicates that the database resides at the town root itself—the .beads directory at the town level.

This configuration allows Gas Town to resolve bead IDs like hq-1234 to the correct physical storage without hardcoding paths throughout the codebase.

Key Functions in internal/beads/routes.go

The internal/beads/routes.go file implements the core logic for prefix extraction and path resolution.

Resolving the Town Beads Directory

The GetTownBeadsPath function returns the absolute path to the town-level beads database:

// GetTownBeadsPath returns the path to the town's .beads directory
// Located at routes.go:65-70
func GetTownBeadsPath(townRoot string) string {
    return filepath.Join(townRoot, ".beads")
}

This simple utility ensures consistent path construction across the application.

Extracting Prefixes from Bead IDs

The ExtractPrefix function parses any bead ID to isolate its prefix component:

// ExtractPrefix extracts the prefix including the trailing hyphen
// Located at routes.go:52-63
func ExtractPrefix(beadID string) string {
    // Implementation extracts "hq-" from "hq-abc123"
}

For example, passing "hq-abc123" returns "hq-", enabling the routing system to categorize beads correctly.

Mapping Prefixes to Physical Paths

The GetRigPathForPrefix function performs the critical lookup that connects a prefix to its storage location:

// Located at routes.go:68-82
func GetRigPathForPrefix(townRoot, prefix string) (string, error) {
    // Looks up prefix in loaded routes
    // Returns townRoot when route.Path == "."
}

When this function encounters a route with Path set to ".", it returns the townRoot directly, effectively routing the bead ID to the town-level .beads database.

Fallback Logic for Unregistered Rigs

If a rig lacks an entry in routes.jsonl, the system falls back to static configuration. The GetPrefixForRig function (located at routes.go:72-80) queries the config package for a default prefix, typically "gt". This ensures that new or unconfigured rigs can still participate in the bead ecosystem without explicit registration.

Practical Code Examples

To resolve the directory containing town-level beads:

townRoot := "/home/user/gt"               // the Gas Town root
beadsDir := beads.GetTownBeadsPath(townRoot)
// beadsDir == "/home/user/gt/.beads"

To extract a prefix and locate the corresponding database:

id := "hq-abc123"
prefix := beads.ExtractPrefix(id) // => "hq-"
rigPath := beads.GetRigPathForPrefix(townRoot, prefix)
// rigPath == "/home/user/gt" (town root) because the route has path="."

To programmatically add a town-level route (typically handled automatically by Gas Town commands):

route := beads.Route{Prefix: "hq-", Path: "."}
_ = beads.AppendRoute(townRoot, route)

Summary

  • Storage: Town-level beads reside in the .beads directory immediately beneath the town root, as returned by GetTownBeadsPath.
  • Identification: The routes.jsonl file maps a dedicated prefix (commonly "hq-") to the town-level database via the prefix field.
  • Resolution: GetRigPathForPrefix interprets a path value of "." as the town root, routing bead IDs to the centralized town database.
  • Fallback: Unregistered rigs default to the "gt" prefix through the GetPrefixForRig configuration fallback.

Frequently Asked Questions

What is the default prefix for town-level beads in Gas Town?

While the specific prefix is configurable in routes.jsonl, town-level beads typically use the "hq-" prefix. This is defined in the town's routes.jsonl entry with "path": ".", distinguishing them from rig-specific beads that use different prefixes.

How does Gas Town locate the database for town-level beads?

The system uses GetTownBeadsPath in internal/beads/routes.go to construct the path by joining the town root with the .beads directory name. This function ensures that all town-level bead operations target the correct database location consistently.

What happens if a rig is not defined in routes.jsonl?

Gas Town implements fallback logic in GetPrefixForRig that queries the static configuration from the config package. If no route exists for a rig, the system defaults to the "gt" prefix, allowing the rig to function with default settings while maintaining compatibility with the broader bead ecosystem.

Where is the town root determined in the codebase?

The town root is identified by the presence of mayor/town.json, as implemented in internal/workspace/find.go. This file serves as the primary marker that distinguishes a valid Gas Town workspace from a standard directory, establishing the boundary for town-level bead storage.

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 →