In the previous chapter, Polecats (Ephemeral Workers), we hired AI workers and gave them isolated sandboxes. But having a worker and a workspace isn't enough. If you tell a worker "Build the feature," they might skip writing tests, forget to update documentation, or break the build.
Workers need instructions. In Gas Town, these instructions are called Molecules.
Imagine you are a pilot. You don't just jump in a plane and fly. You follow a Pre-flight Checklist:
If you skip step 1, the plane falls out of the sky.
In software, if an AI agent (or a human) skips steps:
A Molecule is a structured workflowβa rigid checklist that guides an agent from start to finish.
If a Polecat is the Worker, the Molecule is the Job Ticket.
Understanding Molecules requires learning a few specific terms from Gas Town chemistry.
Sometimes you have a maintenance loop that runs every 5 minutes (like "Check server health"). You don't want to fill your permanent database with millions of these checks. For this, we use Wisps. They act like Molecules but vanish (evaporate) when done, leaving no trace unless they find an error.
Let's look at how to define and run a workflow.
Formulas are written in TOML files located in .beads/formulas/. Here is a simple "Feature Workflow" formula:
# .beads/formulas/feature-work.toml
name = "Standard Feature"
type = "workflow"
[[steps]]
id = "design"
title = "Read requirements and plan"
[[steps]]
id = "code"
title = "Implement code changes"
needs = ["design"] # Dependent on previous step!
[[steps]]
id = "test"
title = "Run test suite"
needs = ["code"]
You cannot run a TOML file directly. You must "Cook" it first to validate it, then "Pour" it to create tasks.
# 1. Validate and prepare the template
bd cook feature-work
# 2. Instantiate it (create the tasks in the database)
bd mol pour feature-work --var issue=GT-101
What just happened? Gas Town read your formula and created three linked tasks in your database. It automatically assigned dependencies: the "code" task is blocked until the "design" task is marked complete.
The agent (or you) can check where they are in the process:
bd mol current
Output:
Molecule: GT-101 (Standard Feature)
β GT-101.1: Read requirements and plan
β GT-101.2: Implement code changes [IN PROGRESS]
β GT-101.3: Run test suite [WAITING]
The agent knows it cannot run tests yet. It must finish coding first.
Molecules are not just lists; they are Directed Acyclic Graphs (DAGs). This means the system mathematically ensures steps happen in the right order.
When you run bd mol pour, Gas Town performs a "Format Bridge." It reads the template and generates discrete database entries (Beads) for every single step.
Let's look at how the system parses these workflows.
In internal/formula/parser.go, we read the TOML file and validate that there are no "cycles" (e.g., Step A needs Step B, and Step B needs Step Aβwhich is impossible).
// internal/formula/parser.go
func (f *Formula) validateWorkflow() error {
if len(f.Steps) == 0 {
return fmt.Errorf("workflow requires steps")
}
// Mathematical check to ensure no circular logic exists
if err := f.checkCycles(); err != nil {
return err
}
return nil
}
In internal/beads/molecule.go, the system iterates through the template steps and creates real issues in the database.
// internal/beads/molecule.go
// instantiateFromChildren creates tasks based on the template
func (b *Beads) instantiateFromChildren(mol *Issue, parent *Issue, templates []*Issue) ([]*Issue, error) {
var createdIssues []*Issue
for _, tmpl := range templates {
// Create a new task in the DB for this step
childOpts := CreateOptions{
Title: tmpl.Title,
Type: "task",
Parent: parent.ID, // Link to the main project
}
child, _ := b.Create(childOpts)
createdIssues = append(createdIssues, child)
}
return createdIssues, nil
}
After creating the tasks, we must link them so the agent knows the order. This logic ensures the "checklist" behavior.
// internal/beads/molecule.go
// Second pass: wire dependencies
for _, tmpl := range templates {
// If this step depends on another...
for _, depID := range tmpl.DependsOn {
// ... tell the database that Step B requires Step A
b.AddDependency(newChildID, newDepID)
}
}
We have a workspace (Rig), a worker (Polecat), and instructions (Molecule). But where do we actually store the record of this work? We need a ledger that can handle distributed data and merging.
Next Chapter: Beads & Dolt (The Ledger)
Generated by Code IQ