gastown Documentation

Gas Town - multi-agent workspace manager

17,533 stars Go Go 1 file · ~23,761 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy gastown on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name gastown -p 8080:8080 --restart always gastownhall/gastown:latest
Configured Services & Ports
⚙️ gastown
image: build locally
🔌 Ports: ${DASHBOARD_PORT:-8080}:8080
docker-compose.yml
yaml (docker-compose.yml)
# Run with
# GIT_USER="" GIT_EMAIL="" FOLDER="/Users/you/code" docker compose up -d

services:
  gastown:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: gastown-sandbox
    stdin_open: false
    tty: false
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETUID
      - SETGID
      - DAC_OVERRIDE
      - FOWNER
      - NET_RAW
    environment:
      IS_SANDBOX: 1
      GIT_USER: ${GIT_USER:-TestUser}
      GIT_EMAIL: ${GIT_EMAIL:[email protected]}
    volumes:
      # FOLDER must be defined in .env file, e.g. FOLDER=/home/user
      # or provided as an environment variable when running docker compose,
      # e.g. FOLDER=/home/user docker compose up
      - agent-home:/home/agent
      - ${FOLDER}:/gt
      # Dolt data on a proper ext4 volume (not the macOS bind mount) to
      # avoid journal corruption from VirtioFS fsync semantics.
      - dolt-data:/gt/.dolt-data
    ports:
      - "${DASHBOARD_PORT:-8080}:8080"
    command: sleep infinity

    # Exec into the container with: docker compose exec gastown zsh

volumes:
  agent-home:
  dolt-data:

1. Project Overview & Quickstart (gastownhall/gastown)

File: README.md

Gas Town

Multi-agent orchestration system for Claude Code, GitHub Copilot, and other AI agents with persistent work tracking

Overview

Gas Town is a workspace manager that lets you coordinate multiple AI coding agents (Claude Code, GitHub Copilot, Codex, Gemini, and others) working on different tasks. Instead of losing context when agents restart, Gas Town persists work state in git-backed hooks, enabling reliable multi-agent workflows.

What Problem Does This Solve?

Challenge Gas Town Solution
Agents lose context on restart Work persists in git-backed hooks
Manual agent coordination Built-in mailboxes, identities, and handoffs
4-10 agents become chaotic Scale comfortably to 20-30 agents
Work state lost in agent memory Work state stored in Beads ledger

Architecture

mermaid
graph TB
    Mayor[The MayorAI Coordinator]
    Town[Town Workspace~/gt/]

    Town --> Mayor
    Town --> Rig1[Rig: Project A]
    Town --> Rig2[Rig: Project B]

    Rig1 --> Crew1[Crew MemberYour workspace]
    Rig1 --> Hooks1[HooksPersistent storage]
    Rig1 --> Polecats1[PolecatsWorker agents]

    Rig2 --> Crew2[Crew Member]
    Rig2 --> Hooks2[Hooks]
    Rig2 --> Polecats2[Polecats]

    Hooks1 -.git worktree.-> GitRepo1[Git Repository]
    Hooks2 -.git worktree.-> GitRepo2[Git Repository]

    style Mayor fill:#e1f5ff,color:#000000
    style Town fill:#f0f0f0,color:#000000
    style Rig1 fill:#fff4e1,color:#000000
    style Rig2 fill:#fff4e1,color:#000000

Core Concepts

The Mayor 🎩

Your primary AI coordinator. The Mayor is a Claude Code instance with full context about your workspace, projects, and agents. Start here - just tell the Mayor what you want to accomplish.

Town 🏘️

Your workspace directory (e.g., ~/gt/). Contains all projects, agents, and configuration.

Rigs 🏗️

Project containers. Each rig wraps a git repository and manages its associated agents.

Crew Members 👤

Your personal workspace within a rig. Where you do hands-on work.

Polecats 🦨

Worker agents with persistent identity but ephemeral sessions. Spawned for tasks, sessions end on completion, but identity and work history persist.

Hooks 🪝

Git worktree-based persistent storage for agent work. Survives crashes and restarts.

Convoys 🚚

Work tracking units. Bundle multiple beads that get assigned to agents. Convoys labeled mountain get autonomous stall detection and smart skip logic for epic-scale execution.

Beads Integration 📿

Git-backed issue tracking system that stores work state as structured data.

Bead IDs (also called issue IDs) use a prefix + 5-character alphanumeric format (e.g., gt-abc12, hq-x7k2m). The prefix indicates the item's origin or rig. Commands like gt sling and gt convoy accept these IDs to reference specific work items. The terms "bead" and "issue" are used interchangeably—beads are the underlying data format, while issues are the work items stored as beads.

Molecules 🧬

Workflow templates that coordinate multi-step work. Formulas (TOML definitions) are instantiated as molecules with tracked steps. Two modes: root-only wisps (steps materialized at runtime, lightweight) and poured wisps (steps materialized as sub-wisps with checkpoint recovery). See Molecules.

Monitoring: Witness, Deacon, Dogs 🐕

A three-tier watchdog system keeps agents healthy:

  • Witness - Per-rig lifecycle manager. Monitors polecats, detects stuck agents, triggers recovery, manages session cleanup.
  • Deacon - Background supervisor running continuous patrol cycles across all rigs.
  • Dogs - Infrastructure workers dispatched by the Deacon for maintenance tasks (e.g., Boot for triage).

Refinery 🏭

Per-rig merge queue processor. When polecats complete work via gt done, the Refinery batches merge requests, runs verification gates, and merges to main using a Bors-style bisecting queue. Failed MRs are isolated and either fixed inline or re-dispatched.

Escalation 🚨

Severity-routed issue escalation. Agents that hit blockers escalate via gt escalate, which creates tracked beads routed through the Deacon, Mayor, and (if needed) Overseer. Severity levels: CRITICAL (P0), HIGH (P1), MEDIUM (P2). See Escalation.

Scheduler ⏱️

Config-driven capacity governor for polecat dispatch. Prevents API rate limit exhaustion by batching dispatch under configurable concurrency limits. Default is direct dispatch; set scheduler.max_polecats to enable deferred dispatch with the daemon. See Scheduler.

Seance 👻

Session discovery and continuation. Discovers previous agent sessions via .events.jsonl logs, enabling agents to query their predecessors for context and decisions from earlier work.

bash
gt seance                       # List discoverable predecessor sessions
gt seance --talk  -p "What did you find?"  # One-shot question

Wasteland 🏜️

Federated work coordination network linking Gas Towns through DoltHub. Rigs post wanted items, claim work from other towns, submit completion evidence, and earn portable reputation via multi-dimensional stamps. See Wasteland.

New to Gas Town? See the Glossary for a complete guide to terminology and concepts.

Installation

Choose one of the two setup paths below: install Gas Town on your host, or run it inside a Docker container.

Prerequisites

Native installs require the host tools below. Docker installs only require Docker Compose on the host; the image supplies Go, Dolt, bd, tmux, and CLI utilities inside the container. The platform steps below say when a path installs gt, bd, and dolt for you and when you install them separately.

Tool Version Notes
Git 2.20+ Worktree support
Go 1.26.2+ (see go.mod) Required for the Linux and Windows paths and for macOS source builds. Not needed for brew install gastown or Docker setup.
Beads (bd) 0.57.0+ Required for native installs. Homebrew and Docker supply it; source/native Go paths install it with go install.
sqlite3 any Used by convoy database queries. Usually pre-installed on macOS and Linux.
ICU4C dev headers varies Required for source builds that compile the ICU-backed query layer. Use libicu-dev on Debian/Ubuntu, libicu-devel on Fedora/RHEL, icu4c on macOS, and MSYS2 ICU packages for native Windows.
tmux 3.0+ Required for gt up and the tmux-backed roles (Mayor, Witnesses, Refineries, polecats). Optional only for minimal-mode workflows where you run runtime instances manually.
Claude Code CLI latest Default runtime. See Runtime Configuration for alternatives (Codex, Copilot, Gemini, Cursor).

Local setup

Install the prerequisites listed above, then install gt for your platform.

Install gt on macOS

Homebrew installs gt, bd, and dolt together.

bash
brew install gastown

Avoid go install on macOS. The unsigned binary it produces gets killed by Gatekeeper. To build from source, install Dolt and ICU4C with Homebrew, install bd with Go, then build and install gt with make install. Put $HOME/.local/bin and $HOME/go/bin ahead of any stale binary locations on your PATH so the freshly installed gt and bd take precedence.

bash
brew install dolt icu4c
go install github.com/steveyegge/beads/cmd/bd@latest
export PATH="$HOME/.local/bin:$HOME/go/bin:$PATH"
git clone https://github.com/steveyegge/gastown.git
cd gastown
make install

Install gt on Linux

Install Dolt by following the Dolt installation guide, then install gt and bd with go install.

bash
go install github.com/steveyegge/gastown/cmd/gt@latest
go install github.com/steveyegge/beads/cmd/bd@latest

Prepend the Go binary directory to your PATH if it is not already there, so freshly installed gt and bd binaries take precedence over stale copies. Append to ~/.zshrc instead if you use zsh.

bash
echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Install gt on Windows

Install Dolt first by following the Dolt installation guide. Unlike the macOS Homebrew path, go install does not install Dolt. Then install gt and bd with go install.

powershell
go install github.com/steveyegge/gastown/cmd/gt@latest
go install github.com/steveyegge/beads/cmd/bd@latest

Both binaries land in %USERPROFILE%\go\bin\. Put that directory before older gt or bd install locations on PATH, then open a new shell for the change to take effect.

Native Windows source builds that compile the ICU-backed query layer need an MSYS2 UCRT64 or MinGW64 shell with matching icu, toolchain, and pkg-config packages; the repository's Windows CI uses pacboy -S icu:p toolchain:p pkg-config:p. Plain PowerShell/MSVC is not enough for that CGO build.

For full tmux-backed workflows on Windows, use WSL or another Linux environment. Native Windows shells are best treated as minimal CLI-only environments.

Create your workspace

Run gt install to create your headquarters (HQ) at ~/gt. The --shell flag installs shell integration and enables Gas Town globally. The --git flag initializes the HQ as a git repository. Before using --git, set git config --global user.name and git config --global user.email so the initial commit has a valid identity.

bash
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
gt install ~/gt --shell --git
cd ~/gt

Start the long-lived services. gt up boots Dolt, the daemon, the Deacon, the Mayor, and per-rig Witnesses and Refineries.

bash
gt up

Verify the install. The --fix flag clears the warnings that gt install does not preempt.

bash
gt doctor --fix

Add a project

Use gt rig add to clone a repository into your HQ as a rig.

bash
gt rig add myproject https://github.com/you/repo.git

Rig names accept letters, digits, and underscores. Hyphens, dots, spaces, and path separators are not allowed. Use my_project instead of my-project.

To set a custom beads prefix for the rig, pass --prefix.

bash
gt rig add myproject https://github.com/you/repo.git --prefix mp

Create your crew workspace

A crew workspace is a personal git clone where you do hands-on work.

bash
gt crew add yourname --rig myproject
cd myproject/crew/yourname

Start the Mayor

The Mayor coordinates work across rigs.

bash
gt mayor attach

Docker Compose setup

docker-compose.yml runs Gas Town inside a sandbox container. The container hosts an HQ at /gt, which Compose bind-mounts from ${FOLDER} on the host. The entrypoint runs gt install /gt --git against that directory on first start, so FOLDER must point at an empty directory that you want to become the HQ or an existing Gas Town HQ. Set GIT_USER and GIT_EMAIL so git and Dolt commits do not use the default test identity. See the full Docker guide for lifecycle, storage, and security details.

bash
export GIT_USER="<your name>"
export GIT_EMAIL="<your email>"
export FOLDER="/path/to/empty/dir"   # empty directory or existing Gas Town HQ
export DASHBOARD_PORT=8080           # optional, host port for the dashboard

mkdir -p "$FOLDER"
docker compose build              # only needed on first run or after code changes
docker compose up -d
docker compose logs -f gastown    # wait for "HQ created successfully!", then Ctrl-C

docker compose exec gastown zsh   # or bash

Inside the container, finish bootstrapping.

bash
gt enable                         # enable Gas Town global state
gt shell install                  # install shell integration
gt up --restore                   # start services and restore worker settings
gh auth login                     # optional: required for private GitHub rigs
gt mayor attach

The dashboard port is exposed from the container to the host. Treat it as a trusted local-network surface, and do not point FOLDER at a host workspace that a native gt install is using at the same time.

Quick Start Guide

Getting Started

Run

shell
git config --global user.name "Your Name" &&
git config --global user.email "[email protected]" &&
gt install ~/gt --shell --git &&
cd ~/gt &&
gt up &&
gt doctor --fix &&
gt config agent list &&
gt mayor attach

and tell the Mayor what you want to build!


Basic Workflow

mermaid
sequenceDiagram
    participant You
    participant Mayor
    participant Convoy
    participant Agent
    participant Hook

    You->>Mayor: Tell Mayor what to build
    Mayor->>Convoy: Create convoy with beads
    Mayor->>Agent: Sling bead to agent
    Agent->>Hook: Store work state
    Agent->>Agent: Complete work
    Agent->>Convoy: Report completion
    Mayor->>You: Summary of progress

Example: Feature Development

bash
# 1. Start the Mayor
gt mayor attach

# 2. In Mayor session, create a convoy with bead IDs
gt convoy create "Feature X" gt-abc12 gt-def34 --notify --human

# 3. Assign work to an agent
gt sling gt-abc12 myproject

# 4. Track progress
gt convoy list

# 5. Monitor agents
gt agents

Common Workflows

Best for: Coordinating complex, multi-issue work

mermaid
flowchart LR
    Start([Start Mayor]) --> Tell[Tell Mayorwhat to build]
    Tell --> Creates[Mayor createsconvoy + agents]
    Creates --> Monitor[Monitor progressvia convoy list]
    Monitor --> Done{All done?}
    Done -->|No| Monitor
    Done -->|Yes| Review[Review work]

Commands:

bash
# Attach to Mayor
gt mayor attach

# In Mayor, create convoy and let it orchestrate
gt convoy create "Auth System" gt-x7k2m gt-p9n4q --notify

# Track progress
gt convoy list

Minimal Mode (No Tmux)

Run individual runtime instances manually. Gas Town just tracks state.

bash
gt convoy create "Fix bugs" gt-abc12   # Create convoy (sling auto-creates if skipped)
gt sling gt-abc12 myproject            # Assign to worker
claude --resume                        # Agent reads mail, runs work (Claude)
# or: codex                            # Start Codex in the workspace
gt convoy list                         # Check progress

Beads Formula Workflow

Best for: Predefined, repeatable processes

Formulas are TOML-defined workflows embedded in the gt binary (source in internal/formula/formulas/).

Example Formula (internal/formula/formulas/release.formula.toml):

toml
description = "Standard release process"
formula = "release"
version = 1

[vars.version]
description = "The semantic version to release (e.g., 1.2.0)"
required = true

[[steps]]
id = "bump-version"
title = "Bump version"
description = "Run ./scripts/bump-version.sh {{version}}"

[[steps]]
id = "run-tests"
title = "Run tests"
description = "Run make test"
needs = ["bump-version"]

[[steps]]
id = "build"
title = "Build"
description = "Run make build"
needs = ["run-tests"]

[[steps]]
id = "create-tag"
title = "Create release tag"
description = "Run git tag -a v{{version}} -m 'Release v{{version}}'"
needs = ["build"]

[[steps]]
id = "publish"
title = "Publish"
description = "Run ./scripts/publish.sh"
needs = ["create-tag"]

Execute:

bash
# List available formulas
bd formula list

# Run a formula with variables
bd cook release --var version=1.2.0

# Create formula instance for tracking
bd mol pour release --var version=1.2.0

Manual Convoy Workflow

Best for: Direct control over work distribution

bash
# Create convoy manually
gt convoy create "Bug Fixes" --human

# Add issues to existing convoy
gt convoy add hq-cv-abc gt-m3k9p gt-w5t2x

# Assign to specific agents
gt sling gt-m3k9p myproject/my-agent

# Check status
gt convoy show

Runtime Configuration

Gas Town supports multiple AI coding runtimes. Per-rig runtime settings are in settings/config.json.

json
{
  "runtime": {
    "provider": "codex",
    "command": "codex",
    "args": [],
    "prompt_mode": "none"
  }
}

Notes:

  • Claude uses hooks in .claude/settings.json (managed via --settings flag) for mail injection and startup.
  • For Codex, set project_doc_fallback_filenames = ["CLAUDE.md"] in
    ~/.codex/config.toml so role instructions are picked up.
  • For runtimes without hooks (e.g., Codex), Gas Town sends a startup fallback
    after the session is ready: gt prime, optional gt mail check --inject
    for autonomous roles, and gt nudge deacon session-started.
  • GitHub Copilot (copilot) is a built-in preset using --yolo for autonomous
    mode. It uses executable lifecycle hooks in .github/hooks/gastown.json (same events
    as Claude: sessionStart, userPromptSubmitted, preToolUse, sessionEnd). Uses a
    5-second ready delay instead of prompt detection. Requires a Copilot seat and org-level
    CLI policy. See docs/INSTALLING.md.

Key Commands

Workspace Management

bash
gt install            # Initialize workspace
gt rig add <name> <repo>    # Add project
gt rig list                 # List projects
gt crew add <name> --rig <rig>  # Create crew workspace

Agent Operations

bash
gt agents                   # List active agents
gt sling  <rig>    # Assign work to agent
gt sling  <rig> --agent cursor   # Override runtime for this sling/spawn
gt mayor attach             # Start Mayor session
gt mayor start --agent auggie           # Run Mayor with a specific agent alias
gt prime                    # Context recovery (run inside existing session)
gt feed                     # Real-time activity feed (TUI)
gt feed --problems          # Start in problems view (stuck agent detection)

Built-in agent presets: claude, gemini, codex, kiro, cursor, auggie, amp, opencode, copilot, pi, omp

The kiro preset launches kiro-cli chat --trust-all-tools, supports Kiro's
documented --resume / --resume-id session flags, and does not install Kiro
hooks or .kiro project files.

Convoy (Work Tracking)

bash
gt convoy create <name> [issues...]   # Create convoy with issues
gt convoy list              # List all convoys
gt convoy show [id]         # Show convoy details
gt convoy add <convoy-id>   # Add issues to convoy

Configuration

bash
# Set custom agent command
gt config agent set claude-glm "claude-glm --model glm-4"
gt config agent set codex-low "codex --thinking low"

# Set default agent
gt config default-agent claude-glm

Monitoring & Health

bash
gt escalate -s HIGH "description"  # Escalate a blocker
gt escalate list               # List open escalations
gt scheduler status            # Show scheduler state
gt seance                      # Discover previous sessions
gt seance --talk           # Query a predecessor session

Beads Integration

bash
bd formula list             # List formulas
bd cook <formula>           # Execute formula
bd mol pour <formula>       # Create trackable instance
bd mol list                 # List active instances

Wasteland Federation

bash
gt wl join <remote>            # Join a wasteland
gt wl browse                   # View wanted board
gt wl claim                # Claim work
gt wl done  --evidence   # Submit completion

Cooking Formulas

Gas Town includes built-in formulas for common workflows. See internal/formula/formulas/ for available recipes.

Activity Feed

gt feed launches an interactive terminal dashboard for monitoring all agent activity in real-time. It combines beads activity, agent events, and merge queue updates into a three-panel TUI:

  • Agent Tree - Hierarchical view of all agents grouped by rig and role
  • Convoy Panel - In-progress and recently-landed convoys
  • Event Stream - Chronological feed of creates, completions, slings, nudges, and more
bash
gt feed                      # Launch TUI dashboard
gt feed --problems           # Start in problems view
gt feed --plain              # Plain text output (no TUI)
gt feed --window             # Open in dedicated tmux window
gt feed --since 1h           # Events from last hour

Navigation: j/k to scroll, Tab to switch panels, 1/2/3 to jump to a panel, ? for help, q to quit.

Problems View

At scale (20-50+ agents), spotting stuck agents in the activity stream becomes difficult. The problems view surfaces agents needing human intervention by analyzing structured beads data.

Press p in gt feed (or start with gt feed --problems) to toggle the problems view, which groups agents by health state:

State Condition
GUPP Violation Hooked work with no progress for an extended period
Stalled Hooked work with reduced progress
Zombie Dead tmux session
Working Active, progressing normally
Idle No hooked work

Intervention keys (in problems view): n to nudge the selected agent, h to handoff (refresh context).

Dashboard

Gas Town includes a web dashboard for monitoring your workspace. The dashboard
must be run from inside a Gas Town workspace (HQ) directory.

bash
# Start dashboard (default port 8080)
gt dashboard

# Start on a custom port
gt dashboard --port 3000

# Start and automatically open in browser
gt dashboard --open

The dashboard gives you a single-page overview of everything happening in your
workspace: agents, convoys, hooks, queues, issues, and escalations. It
auto-refreshes via htmx and includes a command palette for running gt commands
directly from the browser.

Monitoring & Health

Gas Town uses a three-tier watchdog chain to keep agents healthy at scale:

text
Daemon (Go process) ← heartbeat every 3 min
    └── Boot (AI agent) ← intelligent triage
        └── Deacon (AI agent) ← continuous patrol
            └── Witnesses & Refineries ← per-rig agents

Witness (Per-Rig)

Each rig has a Witness that monitors its polecats. The Witness detects stuck agents, triggers recovery (nudge or handoff), manages session cleanup, and tracks completion. Witnesses delegate work rather than implementing it directly.

Deacon (Cross-Rig)

The Deacon runs continuous patrol cycles across all rigs, checking agent health, dispatching Dogs for maintenance tasks, and escalating issues that individual Witnesses can't resolve.

Escalation

When agents hit blockers, they escalate rather than waiting:

bash
gt escalate -s HIGH "Description of blocker"
gt escalate list                    # List open escalations
gt escalate ack            # Acknowledge an escalation

Escalations route through Deacon -> Mayor -> Overseer based on severity. See Escalation design.

Merge Queue (Refinery)

The Refinery processes completed polecat work through a bisecting merge queue:

  1. Polecat runs gt done -> branch pushed, MR bead created
  2. Refinery batches pending MRs
  3. Runs verification gates on the merged stack
  4. If green: all MRs in batch merge to main
  5. If red: bisects to isolate the failing MR, merges the good ones

This is a Bors-style merge queue — polecats never push directly to main.

Scheduler

The scheduler controls polecat dispatch capacity to prevent API rate limit exhaustion:

bash
gt config set scheduler.max_polecats 5   # Enable deferred dispatch (max 5 concurrent)
gt scheduler status                      # Show scheduler state
gt scheduler pause                       # Pause dispatch
gt scheduler resume                      # Resume dispatch

Default mode (max_polecats = -1) dispatches immediately via gt sling. When a limit is set, the daemon dispatches incrementally, respecting capacity. See Scheduler design.

Seance

Discover and query previous agent sessions:

bash
gt seance                              # List discoverable predecessor sessions
gt seance --talk                   # Full context conversation with predecessor
gt seance --talk  -p "Question?"   # One-shot question to predecessor

Seance discovers sessions via .events.jsonl logs, enabling agents to recover context and decisions from earlier work without re-reading entire codebases.

Wasteland Federation

The Wasteland is a federated work coordination network linking multiple Gas Towns through DoltHub:

bash
gt wl join hop/wl-commons              # Join a wasteland
gt wl browse                           # View wanted board
gt wl claim                        # Claim a wanted item
gt wl done  --evidence        # Submit completion with evidence
gt wl post --title "Need X"            # Post new wanted item

Completions earn portable reputation via multi-dimensional stamps (quality, speed, complexity). See Wasteland guide.

Telemetry (OpenTelemetry)

Gas Town emits all agent operations as structured logs and metrics to any OTLP-compatible backend (VictoriaMetrics/VictoriaLogs by default):

bash
# Configure OTLP endpoints
export GT_OTEL_LOGS_URL="http://localhost:9428/insert/jsonline"
export GT_OTEL_METRICS_URL="http://localhost:8428/api/v1/write"

Events emitted: session lifecycle, agent state changes, bd calls with duration, mail operations, sling/nudge/done workflows, polecat spawn/remove, formula instantiation, convoy creation, daemon restarts, and more.

Metrics include: gastown.session.starts.total, gastown.bd.calls.total, gastown.polecat.spawns.total, gastown.done.total, gastown.convoy.creates.total, and others.

See OTEL data model and OTEL architecture for the complete event schema.

Advanced Concepts

The Propulsion Principle

Gas Town uses git hooks as a propulsion mechanism. Each hook is a git worktree with:

  1. Persistent state - Work survives agent restarts
  2. Version control - All changes tracked in git
  3. Rollback capability - Revert to any previous state
  4. Multi-agent coordination - Shared through git

Hook Lifecycle

mermaid
stateDiagram-v2
    [*] --> Created: Agent spawned
    Created --> Active: Work assigned
    Active --> Suspended: Agent paused
    Suspended --> Active: Agent resumed
    Active --> Completed: Work done
    Completed --> Archived: Hook archived
    Archived --> [*]

MEOW (Mayor-Enhanced Orchestration Workflow)

MEOW is the recommended pattern:

  1. Tell the Mayor - Describe what you want
  2. Mayor analyzes - Breaks down into tasks
  3. Convoy creation - Mayor creates convoy with beads
  4. Agent spawning - Mayor spawns appropriate agents
  5. Work distribution - Beads slung to agents via hooks
  6. Progress monitoring - Track through convoy status
  7. Completion - Mayor summarizes results

Shell Completions

bash
# Bash
gt completion bash > /etc/bash_completion.d/gt

# Zsh
gt completion zsh > "${fpath[1]}/_gt"

# Fish
gt completion fish > ~/.config/fish/completions/gt.fish

Project Roles

Role Description Primary Interface
Mayor AI coordinator gt mayor attach
Human (You) Crew member Your crew directory
Polecat Worker agent Spawned by Mayor
Witness Per-rig agent health monitor Automatic patrol
Deacon Cross-rig supervisor daemon gt patrol
Refinery Merge queue processor Automatic
Hook Persistent storage Git worktree
Convoy Work tracker gt convoy commands

Tips

  • Always start with the Mayor - It's designed to be your primary interface
  • Use convoys for coordination - They provide visibility across agents
  • Leverage hooks for persistence - Your work won't disappear
  • Create formulas for repeated tasks - Save time with Beads recipes
  • Use gt feed for live monitoring - Watch agent activity and catch stuck agents early
  • Monitor the dashboard - Get real-time visibility in the browser
  • Let the Mayor orchestrate - It knows how to manage agents

Design Documentation

For deeper technical details, see the design docs in docs/:

Topic Document
Architecture docs/design/architecture.md
Glossary docs/glossary.md
Molecules docs/concepts/molecules.md
Escalation docs/design/escalation.md
Scheduler docs/design/scheduler.md
Wasteland docs/WASTELAND.md
OTEL data model docs/otel-data-model.md
Witness design docs/design/witness-at-team-lead.md
Convoy lifecycle docs/design/convoy/
Polecat lifecycle docs/design/polecat-lifecycle-patrol.md
Plugin system docs/design/plugin-system.md
Agent providers docs/agent-provider-integration.md
Hooks docs/HOOKS.md
Installation guide docs/INSTALLING.md
Docker guide docs/docker.md

Troubleshooting

Agents lose connection

Check hooks are properly initialized:

bash
gt hooks list
gt hooks repair

Convoy stuck

Force refresh:

bash
gt convoy refresh <convoy-id>

Mayor not responding

Restart Mayor session:

bash
gt mayor detach
gt mayor attach

License

MIT License - see LICENSE file for details


File: docs/concepts/convoy.md

Convoys

Convoys are the primary unit for tracking batched work across rigs.

Quick Start

bash
# Create a convoy tracking some issues
gt convoy create "Feature X" gt-abc gt-def --notify overseer

# Check progress
gt convoy status hq-cv-abc

# List active convoys (the dashboard)
gt convoy list

# See all convoys including landed ones
gt convoy list --all

Concept

A convoy is a persistent tracking unit that monitors related issues across
multiple rigs. When you kick off work - even a single issue - a convoy tracks it
so you can see when it lands and what was included.

text
🚚 Convoy (hq-cv-abc)
                         │
            ┌────────────┼────────────┐
            │            │            │
            ▼            ▼            ▼
       ┌─────────┐  ┌─────────┐  ┌─────────┐
       │ gt-xyz  │  │ gt-def  │  │ bd-abc  │
       │ gastown │  │ gastown │  │  beads  │
       └────┬────┘  └────┬────┘  └────┬────┘
            │            │            │
            ▼            ▼            ▼
       ┌─────────┐  ┌─────────┐  ┌─────────┐
       │  nux    │  │ furiosa │  │  amber  │
       │(polecat)│  │(polecat)│  │(polecat)│
       └─────────┘  └─────────┘  └─────────┘
                         │
                    "the swarm"
                    (ephemeral)

Convoy vs Swarm

Concept Persistent? ID Description
Convoy Yes hq-cv-* Tracking unit. What you create, track, get notified about.
Swarm No None Ephemeral. "The workers currently on this convoy's issues."
Stranded Convoy Yes hq-cv-* A convoy with ready work but no polecats assigned. Needs attention.

When you "kick off a swarm", you're really:

  1. Creating a convoy (the tracking unit)
  2. Assigning polecats to the tracked issues
  3. The "swarm" is just those polecats while they're working

When issues close, the convoy lands and notifies you. The swarm dissolves.

Convoy Lifecycle

text
OPEN ──(all issues close)──► LANDED/CLOSED
  ↑                              │
  └──(add more issues)───────────┘
       (auto-reopens)
State Description
open Active tracking, work in progress
closed All tracked issues closed, notification sent

Adding issues to a closed convoy reopens it automatically.

Commands

Create a Convoy

bash
# Track multiple issues across rigs
gt convoy create "Deploy v2.0" gt-abc bd-xyz --notify gastown/joe

# Track a single issue (still creates convoy for dashboard visibility)
gt convoy create "Fix auth bug" gt-auth-fix

# With default notification (from config)
gt convoy create "Feature X" gt-a gt-b gt-c

Add Issues

bash
# Add issues to existing convoy
gt convoy add hq-cv-abc gt-new-issue
gt convoy add hq-cv-abc gt-issue1 gt-issue2 gt-issue3

# Adding to closed convoy requires reopening first
bd update hq-cv-abc --status=open
gt convoy add hq-cv-abc gt-followup-fix

Check Status

bash
# Show issues and active workers (the swarm)
gt convoy status hq-abc

# All active convoys (the dashboard)
gt convoy status

Example output:

text
🚚 hq-cv-abc: Deploy v2.0

  Status:    ●
  Progress:  2/4 completed
  Created:   2025-12-30T10:15:00-08:00

  Tracked Issues:
    ✓ gt-xyz: Update API endpoint [task]
    ✓ bd-abc: Fix validation [bug]
    ○ bd-ghi: Update docs [task]
    ○ gt-jkl: Deploy to prod [task]

List Convoys (Dashboard)

bash
# Active convoys (default) - the primary attention view
gt convoy list

# All convoys including landed
gt convoy list --all

# Only landed convoys
gt convoy list --status=closed

# JSON output
gt convoy list --json

Example output:

text
Convoys

  🚚 hq-cv-w3nm6: Feature X ●
  🚚 hq-cv-abc12: Bug fixes ●

Use 'gt convoy status ' for detailed view.

Notifications

When a convoy lands (all tracked issues closed), subscribers are notified:

bash
# Explicit subscriber
gt convoy create "Feature X" gt-abc --notify gastown/joe

# Multiple subscribers
gt convoy create "Feature X" gt-abc --notify mayor/ --notify --human

Notification content:

text
🚚 Convoy Landed: Deploy v2.0 (hq-cv-abc)

Issues (3):
  ✓ gt-xyz: Update API endpoint
  ✓ gt-def: Add validation
  ✓ bd-abc: Update docs

Duration: 2h 15m

Create from Epic

Auto-discover tracked issues from an existing epic's children. Useful when
a planning/decomposition tool has already structured work as an epic with
child implementation beads.

bash
# Auto-discover children from epic
gt convoy create --from-epic gt-epic-abc

# Override the convoy name (defaults to epic title)
gt convoy create --from-epic gt-epic-abc "Custom convoy name"

# Combine with other flags
gt convoy create --from-epic gt-epic-abc --owned --merge=direct

How it works:

  1. Verifies the given bead is an epic
  2. BFS-walks the parent-child hierarchy to find slingable descendants
  3. Creates a standard convoy (hq-cv-*) tracking all slingable children (task, bug, feature, chore)

Non-slingable types (sub-epics, decisions) are recursed into but never
tracked directly. Only leaf work items appear in the convoy.

Auto-Convoy on Sling

When you sling a single issue without an existing convoy:

bash
gt sling bd-xyz beads/amber

This auto-creates a convoy so all work appears in the dashboard:

  1. Creates convoy: "Work: bd-xyz"
  2. Tracks the issue
  3. Assigns the polecat

Even "swarm of one" gets convoy visibility.

Cross-Rig Tracking

Convoys live in town-level beads (hq-cv-* prefix) and can track issues from any rig:

bash
# Track issues from multiple rigs
gt convoy create "Full-stack feature" \
  gt-frontend-abc \
  gt-backend-def \
  bd-docs-xyz

The tracks relation is:

  • Non-blocking: doesn't affect issue workflow
  • Additive: can add issues anytime
  • Cross-rig: convoy in hq-, issues in gt-, bd-*, etc.

Convoy vs Rig Status

View Scope Shows
gt convoy status [id] Cross-rig Issues tracked by convoy + workers
gt rig status <rig> Single rig All workers in rig + their convoy membership

Use convoys for "what's the status of this batch of work?"
Use rig status for "what's everyone in this rig working on?"

See Also


File: docs/concepts/heartbeats.md

Heartbeats

Gas Town has three distinct heartbeat stores. They have different readers
and thresholds, so Deacon heartbeat commands refresh the Deacon-specific stores
together to avoid false "stuck agent" escalations (see hq-qxl9: a Deacon
refreshed its session heartbeat while the file store aged past threshold).

The three stores

1. Deacon heartbeat file — `/deacon/heartbeat.json`

  • Written by: gt deacon heartbeat [action] and gt heartbeat when
    GT_ROLE=deacon → deacon.Touch() / deacon.TouchWithAction()
    (internal/deacon/heartbeat.go).
  • Read by: the stuck-agent-dog plugin (parses the JSON timestamp, falling
    back to mtime for malformed legacy files, and cross-checks tmux activity
    before escalating) and the Go daemon (deacon.ReadHeartbeat; thresholds 5m
    stale / 20m very-stale → poke).
  • Also touches: the legacy deacon/.deacon-heartbeat mtime file for old
    shell scripts.

2. Session heartbeat (per-session state store)

  • Written by: gt heartbeat [--state=working|idle|exiting|stuck] →
    polecat.TouchSessionHeartbeatWithState(). Requires GT_SESSION.
  • Read by: the Witness, which reads the self-reported state instead of
    inferring liveness from timers (ZFC: gt-3vr5). This is the store polecats
    refresh.

3. Agent-bead label — `heartbeat:` on the agent bead (e.g. `hq-deacon`)

  • Written by: gt mol await-signal on each timeout/signal wake
    (updateAgentHeartbeat in internal/cmd/molecule_await_signal.go). A
    label rewrite is used because bd agent heartbeat was never shipped
    (steveyegge/beads#2828). Deacon heartbeat commands also sync this label when
    it is older than half of the stale threshold.
  • Read by: Witness second-order monitoring ("who watches the watchers"):
    Witnesses check the Deacon's bead activity and alert the Mayor if it looks
    unresponsive (>5 minutes per the patrol formula).
  • Gotcha: a session that never reaches await-signal (handoff churn,
    session limits, one very long patrol turn) leaves this label stale for
    hours even though the agent is healthy.

Rules of thumb

  • Deacon sessions: gt deacon heartbeat refreshes the Deacon file and
    throttled bead label. gt heartbeat also refreshes the session store and,
    when GT_ROLE=deacon, uses the same Deacon file/label sync path.
  • Polecats / Witness / Refinery: gt heartbeat (session store) is the
    one that matters.
  • Monitoring scripts: never declare an agent stuck from a single store.
    Cross-check tmux session activity (tmux display-message -p '#{window_activity}') before escalating — a live session with a stale
    store is heartbeat-write divergence, not a stuck agent. The
    stuck-agent-dog plugin does this since hq-qxl9.

File: docs/concepts/identity.md

Agent Identity and Attribution

Canonical format for agent identity in Gas Town

Why Identity Matters

When you deploy AI agents at scale, anonymous work creates real problems:

  • Debugging: "The AI broke it" isn't actionable. Which AI?
  • Quality tracking: You can't improve what you can't measure.
  • Compliance: Auditors ask "who approved this code?" - you need an answer.
  • Performance management: Some agents are better than others at certain tasks.

Gas Town solves this with universal attribution: every action, every commit,
every bead update is linked to a specific agent identity. This enables work
history tracking, capability-based routing, and objective quality measurement.

BD_ACTOR Format Convention

The BD_ACTOR environment variable identifies agents in slash-separated path format.
This is set automatically when agents are spawned and used for all attribution.

Format by Role Type

Role Type Format Example
Mayor mayor mayor
Deacon deacon deacon
Witness {rig}/witness gastown/witness
Refinery {rig}/refinery gastown/refinery
Crew {rig}/crew/{name} gastown/crew/joe
Polecat {rig}/polecats/{name} gastown/polecats/toast

Why Slashes?

The slash format mirrors filesystem paths and enables:

  • Hierarchical parsing (extract rig, role, name)
  • Consistent mail addressing (gt mail send gastown/witness)
  • Path-like routing in beads operations
  • Visual clarity about agent location

Attribution Model

Gas Town uses three fields for complete provenance:

Git Commits

bash
GIT_AUTHOR_NAME="gastown/crew/joe"      # Who did the work (agent)
GIT_AUTHOR_EMAIL="[email protected]"    # Who owns the work (overseer)

Result in git log:

text
abc123 Fix bug (gastown/crew/joe <[email protected]>)

Interpretation:

  • The agent gastown/crew/joe authored the change
  • The work belongs to the workspace owner ([email protected])
  • Both are preserved in git history forever

Beads Records

json
{
  "id": "gt-xyz",
  "created_by": "gastown/crew/joe",
  "updated_by": "gastown/witness"
}

The created_by field is populated from BD_ACTOR when creating beads.
The updated_by field tracks who last modified the record.

Event Logging

All events include actor attribution:

json
{
  "ts": "2025-01-15T10:30:00Z",
  "type": "sling",
  "actor": "gastown/crew/joe",
  "payload": { "bead": "gt-xyz", "target": "gastown/polecats/toast" }
}

Environment Setup

Gas Town uses a centralized config.AgentEnv() function to set environment
variables consistently across all agent spawn paths (managers, daemon, boot).

Example: Polecat Environment

bash
# Set automatically for polecat 'toast' in rig 'gastown'
export GT_ROLE="polecat"
export GT_RIG="gastown"
export GT_POLECAT="toast"
export BD_ACTOR="gastown/polecats/toast"
export GIT_AUTHOR_NAME="gastown/polecats/toast"
export GT_ROOT="/home/user/gt"
export BEADS_DIR="/home/user/gt/gastown/.beads"
export BEADS_AGENT_NAME="gastown/toast"

Example: Crew Environment

bash
# Set automatically for crew member 'joe' in rig 'gastown'
export GT_ROLE="crew"
export GT_RIG="gastown"
export GT_CREW="joe"
export BD_ACTOR="gastown/crew/joe"
export GIT_AUTHOR_NAME="gastown/crew/joe"
export GT_ROOT="/home/user/gt"
export BEADS_DIR="/home/user/gt/gastown/.beads"
export BEADS_AGENT_NAME="gastown/joe"

Manual Override

For local testing or debugging:

bash
export BD_ACTOR="gastown/crew/debug"
bd create --title="Test issue"  # Will show created_by: gastown/crew/debug

See reference.md for the complete
environment variable reference.

Identity Parsing

The format supports programmatic parsing:

go
// identityToBDActor converts daemon identity to BD_ACTOR format
// Town level: mayor, deacon
// Rig level: {rig}/witness, {rig}/refinery
// Workers: {rig}/crew/{name}, {rig}/polecats/{name}
Input Parsed Components
mayor role=mayor
deacon role=deacon
gastown/witness rig=gastown, role=witness
gastown/refinery rig=gastown, role=refinery
gastown/crew/joe rig=gastown, role=crew, name=joe
gastown/polecats/toast rig=gastown, role=polecat, name=toast

Audit Queries

Attribution enables powerful audit queries:

bash
# All work by an agent
bd audit --actor=gastown/crew/joe

# All work in a rig
bd audit --actor=gastown/*

# All polecat work
bd audit --actor=*/polecats/*

# Git history by agent
git log --author="gastown/crew/joe"

Design Principles

  1. Agents are not anonymous - Every action is attributed
  2. Work is owned, not authored - Agent creates, overseer owns
  3. Attribution is permanent - Git commits preserve history
  4. Format is parseable - Enables programmatic analysis
  5. Consistent across systems - Same format in git, beads, events

CV and Skill Accumulation

Human Identity is Global

The global identifier is your email - it's already in every git commit. No separate "entity bead" needed.

text
[email protected]                ← global identity (from git author)
├── Town A (home)                ← workspace
│   ├── gastown/crew/joe         ← agent executor
│   └── gastown/polecats/toast   ← agent executor
└── Town B (work)                ← workspace
    └── acme/polecats/nux        ← agent executor

Agent vs Owner

Field Scope Purpose
BD_ACTOR Local (town) Agent attribution for debugging
GIT_AUTHOR_EMAIL Global Human identity for CV
created_by Local Who created the bead
owner Global Who owns the work

Agents execute. Humans own. The polecat name in completed-by: gastown/polecats/toast is executor attribution. The CV credits the human owner ([email protected]).

Polecats Have Persistent Identities

Polecats have persistent identities but ephemeral sessions. Like employees who
clock in/out: each work session is fresh (new tmux, new worktree), but the identity
persists across sessions.

  • Identity (persistent): Agent bead, CV chain, work history
  • Session (ephemeral): Claude instance, context window
  • Sandbox (ephemeral): Git worktree, branch

Work credits the polecat identity, enabling:

  • Performance tracking per polecat
  • Capability-based routing (send Go work to polecats with Go track records)
  • Model comparison (A/B test different models via different polecats)

See polecat-lifecycle.md for details.

Skills Are Derived

Your CV emerges from querying work evidence:

bash
# All work by owner (across all agents)
git log --author="[email protected]"
bd list [email protected]

# Skills derived from evidence
# - .go files touched → Go skill
# - issue tags → domain skills
# - commit patterns → activity types

Multi-Town Aggregation

A human with multiple towns has one CV:

bash
# Future: federated CV query
bd cv [email protected]
# Discovers all towns, aggregates work, derives skills

See ~/gt/docs/hop/decisions/008-identity-model.md for architectural rationale.

Enterprise Use Cases

Compliance and Audit

bash
# Who touched this file in the last 90 days?
git log --since="90 days ago" -- path/to/sensitive/file.go

# All changes by a specific agent
bd audit --actor=gastown/polecats/toast --since=2025-01-01

Performance Tracking

bash
# Completion rate by agent
bd stats --group-by=actor

# Average time to completion
bd stats --actor=gastown/polecats/* --metric=cycle-time

Model Comparison

When agents use different underlying models, attribution enables A/B comparison:

bash
# Tag agents by model
# gastown/polecats/claude-1 uses Claude
# gastown/polecats/gpt-1 uses GPT-4

# Compare quality signals
bd stats --actor=gastown/polecats/claude-* --metric=revision-count
bd stats --actor=gastown/polecats/gpt-* --metric=revision-count

Lower revision counts suggest higher first-pass quality.


File: docs/concepts/integration-branches.md

Integration Branches

Group epic work on a shared branch, land to main as a unit.

Integration branches provide end-to-end support for epic-scoped work across
the Gas Town pipeline. When you create an integration branch for an epic, it
becomes the automatic target for every stage: polecats spawn their worktrees
from the integration branch (so they start with sibling work already present),
the Refinery merges completed MRs into the integration branch instead of main,
and when all epic children are closed, the Refinery can land the integration
branch back to its base branch (main by default, or whatever was specified
with --base-branch at creation) as a single merge commit.

Landing can happen on command or automatically via patrol. The result is that
an entire epic flows through the system as a coherent unit, from first sling
to final land, without any manual branch targeting.

Workflow

  1. Create the epic and its children. Structure your work as an epic with
    child tasks (or sub-epics) underneath. Set up dependencies between children
    to define which can run in parallel and which must wait.

  2. Create the integration branch. This is the shared branch where all child
    work accumulates.

    bash
    gt mq integration create gt-auth-epic
  3. Create a convoy to track the work. The convoy gives you a single dashboard
    for the entire epic's progress.

    bash
    gt convoy create "Auth overhaul" gt-auth-tokens gt-auth-sessions gt-auth-middleware
  4. Sling the first wave. Identify children with no blockers and sling them
    to the rig. Use --no-convoy since the tracking convoy already exists.

    bash
    gt sling gt-auth-tokens gastown --no-convoy
    gt sling gt-auth-sessions gastown --no-convoy
  5. Polecats process the work. Each polecat spawns its worktree from the
    integration branch, so it starts with any sibling work that has already
    landed there. When a polecat finishes, it submits a merge request.

  6. Refinery merges to the integration branch. Instead of merging to main,
    the Refinery merges each MR into the integration branch and marks the child
    task as complete.

  7. Track progress via the convoy. The convoy status updates each time the
    Refinery completes a task.

    bash
    gt convoy status hq-cv-abc
  8. Sling the next wave. When a wave completes and its dependent children
    unblock, sling the next batch. Those polecats will start from the integration
    branch — which now contains all the work from the preceding wave.

    bash
    gt sling gt-auth-middleware gastown --no-convoy
  9. Land when complete. When all children under the epic are closed, the
    integration branch is ready to land. If integration_branch_auto_land is
    enabled, the Refinery does this automatically during patrol. Otherwise,
    land manually:

    bash
    gt mq integration land gt-auth-epic

    This merges the integration branch back to its base branch (main by
    default) as a single merge commit, deletes the branch, and closes the
    epic.

Concept

The Problem

Without integration branches, epic work lands piecemeal:

text
Child A ──► MR ──► main     (lands Tuesday)
Child B ──► MR ──► main     (lands Wednesday, breaks A's work)
Child C ──► MR ──► main     (lands Thursday, depends on A+B together)

Each child merges independently. If Child C depends on A and B being coherent
together, you're relying on merge order and hoping nothing breaks between lands.

The Solution

Integration branches batch epic work on a shared branch, then land atomically:

text
Epic: gt-auth-epic
                                  │
                    ┌─────────────┼─────────────┐
                    │             │             │
               Child A       Child B       Child C
                    │             │             │
                    ▼             ▼             ▼
               ┌────────┐  ┌────────┐  ┌────────┐
               │  MR A  │  │  MR B  │  │  MR C  │
               └───┬────┘  └───┬────┘  └───┬────┘
                   │           │           │
                   └───────────┼───────────┘
                               ▼
                 integration/gt-auth-epic
                    (shared branch)
                               │
                               ▼ gt mq integration land
                          base branch
                    (main or --base-branch)
                     (single merge commit)

All child MRs merge into the integration branch first. Children can build on
each other's work. When everything is ready, one command lands it all.

With vs Without

Aspect Without With Integration Branch
MR target main integration/{epic}
Land timing Each MR lands independently All MRs land together
Cross-child deps Risky—depends on merge order Safe—children share a branch
Rollback Revert individual commits Revert one merge commit
CI on main Runs per-MR Runs once on combined work

Lifecycle

1. Create the Epic

bash
bd create --type=epic --title="Auth overhaul"
# → gt-auth-epic

Create child issues under the epic as normal.

2. Create the Integration Branch

bash
gt mq integration create gt-auth-epic
# → Created integration/gt-auth-epic from origin/main
# → Stored branch name in epic metadata

This pushes a new branch to origin and records its name on the epic.

3. Sling Work

Assign children to polecats as normal:

bash
gt sling gt-auth-tokens gastown
gt sling gt-auth-sessions gastown

Polecats auto-detect the integration branch when their issue is a child of an
epic that has one. No manual targeting needed.

4. MRs Merge to Integration Branch

When polecats run gt done or gt mq submit, auto-detection kicks in:

text
gt done
  → Detects parent epic gt-auth-epic
  → Finds integration/gt-auth-epic branch
  → Submits MR targeting integration/gt-auth-epic (not main)

The Refinery processes these MRs and merges them to the integration branch.

5. Land When Complete

Once all children are closed and all MRs merged:

bash
gt mq integration land gt-auth-epic
# → Verified all MRs merged
# → Merged integration/gt-auth-epic → base branch (--no-ff)
# → Tests passed
# → Pushed to origin
# → Deleted integration/gt-auth-epic
# → Closed epic gt-auth-epic

Auto-Detection

Integration branches work without manual targeting. Three systems auto-detect them:

System What It Does Config Gate
gt done / gt mq submit Targets MR at integration branch instead of main integration_branch_refinery_enabled
Polecat spawn Sources worktree from integration branch integration_branch_polecat_enabled
Refinery patrol Checks if integration branches are ready to land integration_branch_auto_land

Detection Algorithm

When gt done or gt mq submit runs:

Step Action Result
1 Load config, check integration_branch_refinery_enabled If false, skip detection
2 Get current issue ID from branch name e.g., gt-auth-tokens
3 Walk parent chain (max 10 levels) Find ancestor epics
4 For each epic: read integration_branch: from metadata Get stored branch name
5 Fallback: generate name from template e.g., integration/{title}
6 Check if branch exists (local, then remote) Verify it's real
7 If found, target MR at that branch Instead of main

The --epic flag on gt mq submit bypasses auto-detection and resolves
the target branch using the configured template (defaulting to
integration/{epic}).

Branch Naming

Template Variables

Variable Description Example
{epic} Full epic ID gt-auth-epic
{prefix} Epic prefix (before first hyphen) gt
{user} From git config user.name klauern

Precedence

Priority Source Example
1 (highest) --branch flag on create --branch "feat/{epic}"
2 integration_branch_template in config "{user}/{epic}"
3 (lowest) Default "integration/{title}"

Template Variables

Variable Description Example
{title} Sanitized epic title (lowercase, hyphenated, max 60 chars) add-user-authentication
{epic} Full epic ID RA-123
{prefix} Epic prefix before first hyphen RA
{user} Git user.name klauern

Examples

bash
# Default template (uses epic title)
gt mq integration create gt-auth-epic
# → integration/add-user-authentication  (from epic title)

# Custom template in config: "{user}/{prefix}/{epic}"
gt mq integration create RA-123
# → klauern/RA/RA-123

# Override with --branch flag
gt mq integration create RA-123 --branch "feature/{epic}"
# → feature/RA-123

The actual branch name created is stored in the epic's metadata, so auto-detection
always finds the right branch regardless of which template was used.

If two epics produce the same branch name (same title), a numeric suffix from the
epic ID is appended automatically (e.g., integration/add-auth-456).

Commands

`gt mq integration create `

Create an integration branch for an epic.

bash
gt mq integration create <epic-id> [flags]

Flags:

Flag Description Default
--branch Override branch name template Config template or integration/{title}
--base-branch Create from this branch instead of the rig's default branch (also sets where land merges back to) origin/<default_branch>

What it does:

  1. Verifies the epic exists
  2. Generates branch name from template (expanding variables)
  3. Validates branch name (git-safe characters)
  4. Creates local branch from base
  5. Pushes to origin
  6. Stores branch name and base branch in epic metadata

Error cases:

  • Epic not found
  • Branch already exists
  • Invalid characters in generated branch name

`gt mq integration status `

Display integration branch status for an epic.

bash
gt mq integration status <epic-id> [flags]

Flags:

Flag Description
--json Output as JSON

Output includes:

  • Branch name and creation date
  • Commits ahead of main
  • Merged MRs (closed, targeting integration branch)
  • Pending MRs (open, targeting integration branch)
  • Child issue progress (closed / total)
  • Ready-to-land status
  • Auto-land configuration

Ready-to-land criteria (all must be true):

  1. Integration branch has commits ahead of main
  2. Epic has children
  3. All children are closed
  4. No pending MRs (all submitted work is merged)

`gt mq integration land `

Merge an epic's integration branch back to its base branch.

bash
gt mq integration land <epic-id> [flags]

Flags:

Flag Description Default
--force Land even if some MRs still open false
--skip-tests Skip test run after merge false
--dry-run Preview only, make no changes false

What it does:

  1. Verifies epic exists and has an integration branch
  2. Reads base branch from epic metadata (defaults to the rig's default_branch if not stored)
  3. Checks all MRs targeting integration branch are merged
  4. Fetches latest refs and checks idempotency (if already merged, skips to cleanup)
  5. Acquires file lock (prevents concurrent land races)
  6. Creates a temporary worktree (avoids disrupting running agents)
  7. Merges integration branch to base branch using --no-ff
  8. Runs tests (unless --skip-tests)
  9. Verifies merge brought changes (guards against empty merges)
  10. Pushes to origin
  11. Deletes integration branch (local and remote)
  12. Closes the epic

Idempotent retry: If land crashes after pushing but before cleanup (branch
deletion / epic close), rerunning the same command is safe. The idempotency
check detects that the integration branch is already an ancestor of the target
and skips directly to cleanup.

Error cases:

  • Epic has no integration branch
  • Pending MRs exist (use --force to override)
  • Tests fail
  • Empty merge (no changes to land)

Configuration

Default Branch

The rig's default_branch (set in config.json, auto-detected during gt rig add)
controls where work merges when no integration branch is active. It's also the
default base branch when creating integration branches. If your project uses
develop or master instead of main, set it once in rig config and the whole
pipeline follows:

json
{
  "type": "rig",
  "name": "myproject",
  "default_branch": "develop"
}

Integration Branch Settings

All integration branch fields live under merge_queue in rig settings (settings/config.json):

json
{
  "merge_queue": {
    "enabled": true,
    "integration_branch_polecat_enabled": true,
    "integration_branch_refinery_enabled": true,
    "integration_branch_template": "integration/{title}",
    "integration_branch_auto_land": false
  }
}
Field Type Default Description
integration_branch_polecat_enabled *bool true Polecats auto-source worktrees from integration branches
integration_branch_refinery_enabled *bool true gt mq submit and gt done auto-detect integration branches as MR targets
integration_branch_template string "integration/{title}" Branch name template (supports {title}, {epic}, {prefix}, {user})
integration_branch_auto_land *bool false Refinery patrol auto-lands when all children closed

Note: *bool fields use pointer semantics — null/omitted means "use default"
(true for polecat/refinery enabled, false for auto-land). Set explicitly to false
to disable.

Auto-Landing

When integration_branch_auto_land is true, the Refinery patrol automatically
lands integration branches that are ready.

How It Works

During each patrol cycle, the Refinery:

  1. Lists all open epics: bd list --type=epic --status=open
  2. Checks each epic's integration branch: gt mq integration status <epic-id>
  3. If ready_to_land: true: runs gt mq integration land <epic-id>
  4. If not ready: skips (epic work is incomplete)

Conditions for Auto-Land

Both config gates must be true:

  • integration_branch_refinery_enabled: true (integration feature is on)
  • integration_branch_auto_land: true (auto-landing is on)

If either is false, the patrol step exits early.

When to Enable

Scenario Recommendation
Trusted CI, no human review needed Enable auto-land
Need human sign-off before landing Keep disabled (default), land manually
Mix of both Keep disabled, use gt mq integration land for manual control

Safety Guardrails

Integration branch landing is protected by a three-layer defense:

Layer 1: Formula and Role Instructions

The refinery formula and role template explicitly forbid landing integration
branches via raw git commands. Only gt mq integration land is authorized.

Layer 2: Pre-Push Hook

The .githooks/pre-push hook detects when a push to the default branch
introduces integration branch content. It uses ancestry-based detection:
if any origin/integration/* branch tip becomes newly reachable from the
pushed commits, the push is blocked unless GT_INTEGRATION_LAND=1 is set.

The default branch is detected dynamically via refs/remotes/origin/HEAD
(fallback: main), so this works regardless of the rig's branch naming.

This catches all merge styles: --no-ff, --ff-only, default merge, and
rebase. Only cherry-picks (which produce new SHAs) are not detected.

Scope: This check matches branches under the integration/ prefix (the
default template). Custom templates that produce branches outside integration/
are not covered by the hook — Layer 1 (formula language) is the guardrail for
those cases.

Requires: core.hooksPath must be configured for the hook to be active.
New rigs get this automatically. Existing rigs: run gt doctor --fix.

Layer 3: Authorized Code Path

The gt mq integration land command uses PushWithEnv() to set
GT_INTEGRATION_LAND=1, allowing the push through the hook. Raw git push
from any agent or user does not set this variable and will be blocked.
Manually setting the env var is possible but is not part of the supported
workflow — the variable is a policy-based trust boundary, not a
capability-based security mechanism.

Why Three Layers?

Layer Type Strength Limitation
Formula/Role Soft Covers all branch patterns AI agents can ignore instructions
Pre-push hook Hard Blocks all merge styles at git boundary Only matches integration/* prefix; env var is policy-based
Code path Hard Land command sets bypass env var Requires hook to be active

The layers complement each other. The formula covers custom templates; the hook
provides hard enforcement for default templates (catching merges, fast-forwards,
and rebases via ancestry detection); the code path ensures the CLI command can
bypass the hook.

Build Pipeline Configuration

Integration branches work with different project toolchains. The rig's build pipeline
commands are auto-injected into polecat-work, refinery-patrol, and sync-workspace
formulas so agents know how to validate work for each project.

The 5-Command Pipeline

Commands run in this order (any can be empty = skip):

  1. setup — Install dependencies (e.g., pnpm install)
  2. typecheck — Static type checking (e.g., tsc --noEmit)
  3. lint — Code style and quality (e.g., eslint .)
  4. test — Run test suite (e.g., go test ./...)
  5. build — Compile/bundle (e.g., go build ./...)

Example Configurations

Go project (all commands empty by default — configure per-rig):

json
{
  "merge_queue": {
    "test_command": "go test ./...",
    "lint_command": "golangci-lint run ./...",
    "build_command": "go build ./..."
  }
}

TypeScript project:

json
{
  "merge_queue": {
    "setup_command": "pnpm install",
    "typecheck_command": "tsc --noEmit",
    "lint_command": "eslint .",
    "test_command": "pnpm test:unit",
    "build_command": "pnpm build"
  }
}

How Commands Flow Into Formulas

Commands are auto-injected from <rig>/settings/config.json into formula vars:

  • Refinery patrol: buildRefineryPatrolVars() reads rig config during gt prime
  • Polecat work / sync: loadRigCommandVars() reads rig config during gt sling

User-provided --var flags on gt sling override rig config values.

Empty = Skip

Any command left empty (or not configured) is skipped silently by the formula.
This means a Go rig doesn't need setup_command or typecheck_command, and a
TypeScript rig can add all five without affecting Go rigs.

Polecats working on integration branches inherit the rig's build pipeline
automatically — no per-branch configuration is needed.

Anti-Patterns

Creating Integration Branch After Work Starts

Wrong: Sling children, then create the integration branch later.

Children slung before the integration branch exists will target main. Their MRs
won't flow to the integration branch. Create the integration branch first,
before slinging any child work.

Manually Targeting the Integration Branch

Wrong: Using --branch integration/gt-epic on gt mq submit.

Auto-detection handles this. If you find yourself manually targeting, check that:

  • The integration branch actually exists
  • integration_branch_refinery_enabled is not false
  • The issue is a child (or descendant) of the epic

Landing Partial Epics

Wrong: Using --force to land when children are still open.

This defeats the purpose. The integration branch exists so work lands together.
If you need to land early, close or remove the incomplete children first.

See Also


File: docs/concepts/molecules.md

Molecules

Molecules are workflow templates that coordinate multi-step work in Gas Town.

Molecule Lifecycle

text
Formula (source TOML) ─── "Ice-9"
    │
    ▼ bd cook
Protomolecule (frozen template) ─── Solid
    │
    ├─▶ bd mol pour ──▶ Mol (persistent) ─── Liquid
    │
    └─▶ bd mol wisp --root-only ──▶ Root Wisp (ephemeral) ─── Vapor

Root-only wisps (default): Formula steps are NOT materialized as database rows.
Only a single root wisp is created. Agents read steps inline from the embedded
formula at prime time. This prevents wisp accumulation (~6,000+ rows/day → ~400/day).

Poured wisps (pour = true): Steps ARE materialized as sub-wisps with
checkpoint recovery. If a session dies, completed steps remain closed and work
resumes from the last checkpoint. Use pour for expensive, low-frequency workflows
where losing progress would be costly (e.g., release workflows).

Core Concepts

Term Description
Formula Source TOML template defining workflow steps
Protomolecule Frozen template ready for instantiation
Molecule Active workflow instance (root wisp only)
Wisp Ephemeral molecule for patrols and polecat work (never synced)
Root-only Only root wisp created; steps read from embedded formula
Pour Formula flag (pour = true); steps materialized as sub-wisps with checkpoint recovery

How Agents See Steps

Agents do NOT use bd mol current or bd close <step-id> for formula workflows.
Instead, formula steps are rendered inline when the agent runs gt prime:

text
**Formula Checklist** (10 steps from mol-polecat-work):

### Step 1: Load context and verify assignment
Initialize your session and understand your assignment...

### Step 2: Set up working branch
Ensure you're on a clean feature branch...

The agent works through the checklist and runs gt done (polecats) or
gt patrol report (patrol agents) when complete.

Molecule Commands

Beads Operations (bd)

bash
# Formulas
bd formula list              # Available formulas
bd formula show <name>       # Formula details
bd cook <formula>            # Formula → Proto

# Molecules (data operations)
bd mol list                  # Available protos
bd mol show              # Proto details
bd mol wisp           # Create wisp (root-only by default)
bd mol bond   # Attach to existing mol

Agent Operations (gt)

bash
# Hook management
gt hook                    # What's on MY hook?
gt prime                   # Shows inline formula checklist
gt mol attach  <mol>   # Pin molecule to bead
gt mol detach          # Unpin molecule from bead

# Patrol lifecycle
gt patrol new              # Create patrol wisp and hook it
gt patrol report --summary "..."  # Close current patrol, start next cycle

Polecat Workflow

Polecats receive work via their hook — a root wisp attached to an issue.
They see the formula checklist inline when they run gt prime and work
through each step in order.

Polecat Workflow Summary

text
1. Spawn with work on hook
2. gt prime               # Shows formula checklist inline
3. Work through each step
4. Persist findings: bd update  --notes "..."
5. gt done                # Submit, preserve handoff metadata, exit

Molecule Types

Type Storage Use Case
Root-only Wisp (pour = false) .beads/ (ephemeral) Polecat work, patrols — high frequency, cheap steps
Poured Wisp (pour = true) .beads/ (sub-wisps) Releases, long workflows — low frequency, expensive steps

Heuristic: If you would curse losing the progress after a crash, set pour = true.
High frequency + cheap steps = inline (default). Low frequency + expensive steps = pour.

Patrol Workflow

Patrol agents (Deacon, Witness, Refinery) cycle through patrol formulas:

text
1. gt patrol new          # Create root-only patrol wisp
2. gt prime               # Shows patrol checklist inline
3. Work through each step
4. gt patrol report --summary "..."  # Close + start next cycle

gt patrol report atomically closes the current patrol root and spawns
a new one for the next cycle.

Best Practices

  1. Persist findings early — bd update --notes "..." before session death
  2. Run gt done when complete — mandatory for polecats (pushes, submits to MQ/PR path, exits)
  3. Use gt patrol report — for patrol agents to cycle (replaces squash+new pattern)
  4. File discovered work — bd create for bugs found, don't fix them yourself

File: docs/concepts/polecat-lifecycle.md

Polecat Lifecycle

Understanding the three-layer architecture of polecat workers

Overview

Polecats have three distinct lifecycle layers that operate independently. The
key design principle: clean completion retires the live polecat session.
The agent identity and merge evidence persist, but completed sessions do not
return to the idle reuse pool.

Operating States

Polecats use these primary operating states:

State Description How it happens
Working Actively doing assigned work Normal operation after gt sling
Idle Available before assignment Spawned or explicitly prepared for work
Done Work completed and session retired After gt done completes successfully
Stalled Session stopped mid-work Interrupted, crashed, or timed out without being nudged
Zombie Completed work but failed to exit gt done failed during cleanup

State cycle (happy path):

text
┌──────────┐
         │  IDLE    │──── gt sling
         └────┬─────┘
              v
         ┌──────────┐
         │ WORKING  │<──── session active, hook set
         └────┬─────┘
              │ gt done
              v
         ┌──────────┐
         │  DONE    │──── branch/MR evidence preserved, session exits
         └──────────┘

No idle reuse in the happy path. Polecats move: IDLE -> WORKING -> DONE.

Key distinctions:

  • Working = actively executing. Session alive, hook set, doing work.
  • Idle = not yet assigned and safe to use.
  • Done = work done, session killed, waiting for cleanup/refinery outcome.
  • Stalled = supposed to be working, but stopped. Needs Witness intervention.
  • Zombie = finished work, tried to exit, but cleanup failed. Stuck in limbo.

The Retired Completion Model

Polecat identity persists after completing work, but the live session does not.
When a polecat finishes its assignment:

  1. Signals completion via gt done
  2. Pushes branch, submits MR to merge queue
  3. Clears its hook (work is done)
  4. Sets agent state to "done"
  5. Kills its own session using PID-excluding cleanup
  6. Leaves branch/MR metadata for Witness/refinery cleanup

The next gt sling allocates available capacity without reusing a completed
session that still has branch/MR or cleanup state attached.

Why Retire Sessions?

  • Preserved identity — The polecat's agent bead, CV chain, and work history persist
  • Simpler lifecycle — Clean completion has one terminal session path
  • Done means retired — Session dies, cleanup/refinery owns remaining state

What About Pending Merges?

The Refinery owns the merge queue. Once gt done submits work:

  • The branch is pushed to origin
  • Work exists in the MQ, not in the polecat
  • If rebase fails, Refinery creates a conflict-resolution task
  • The completed polecat is not reused while pending MR or cleanup state remains

The Three Layers

The Problem: Three Concepts Were Conflated

Early designs treated polecats as monolithic. This caused recurring issues:

Concept Lifecycle Old behavior
Identity Long-lived (name, CV, ledger) Destroyed on nuke
Sandbox Per-assignment (worktree, branch) Destroyed on nuke
Session Ephemeral (Claude context window) = polecat lifetime

Separating these three layers keeps completed sessions out of the idle reuse pool,
preserves capability records (CV, completion history), and lets cleanup/refinery
own branch and worktree state after handoff.

Layer Summary

Layer Component Lifecycle Persistence
Identity Agent bead, CV chain, work history Permanent Never dies
Sandbox Git worktree, branch Per active assignment/cleanup window Created for work, retired after cleanup
Session Claude (tmux pane), context window Ephemeral per step Cycles per step/handoff

Identity Layer

The polecat's identity is permanent. It includes:

  • Agent bead (created once, never deleted)
  • CV chain (work history accumulates across all assignments)
  • Mailbox and attribution record

Identity survives all session cycles and sandbox resets. In the HOP model, this IS
the polecat — everything else is infrastructure that comes and goes. See
Polecat Identity below for details.

Session Layer

The Claude session is ephemeral. It cycles frequently:

  • After each molecule step (via gt handoff)
  • On context compaction
  • On crash/timeout
  • After extended work periods

Key insight: Session cycling is normal operation, not failure. The polecat
continues working—only the Claude context refreshes.

text
Session 1: Steps 1-2 → handoff
Session 2: Steps 3-4 → handoff
Session 3: Step 5 → gt done

All three sessions are the same polecat. The sandbox persists throughout.

Sandbox Layer

The sandbox is the git worktree—the polecat's working directory:

text
~/gt/gastown/polecats/Toast/

This worktree:

  • Exists while the polecat is active or awaiting cleanup
  • Survives handoff/session cycles during an assignment
  • Is not synced to main or branch-deleted by gt done
  • Contains uncommitted work, staged changes, branch state during active work

Witness/refinery cleanup owns sandbox retirement after durable handoff. Explicit
gt polecat nuke remains the manual destructive path.

Branch Preservation (After Completion)

When work completes, gt done leaves the feature branch and MR metadata intact:

bash
# Handled by gt done
git push origin polecat/<name>/@<suffix>
# Branch and metadata remain available for refinery/review/cleanup

When new work is slung:

bash
# Create fresh branch from current main
git checkout -b polecat/<name>/<new-issue>+<timestamp>
# Start working

Completed sandboxes are not treated as reusable idle worktrees while branch,
MR, or cleanup state remains attached.

Slot Layer

The slot is the name allocation from the polecat pool:

bash
# Pool: [Toast, Shadow, Copper, Ash, Storm...]
# Toast is allocated to work gt-abc

The slot:

  • Determines the sandbox path (polecats/Toast/)
  • Maps to a tmux session (gt-gastown-Toast)
  • Appears in attribution (gastown/polecats/Toast)
  • Persists until explicit nuke

Correct Lifecycle

text
/* Detailed source-code truncated for AI context efficiency. */

What "Recycle" Means

Session cycling: Normal. Claude restarts, sandbox stays, slot stays.

bash
gt handoff  # Session cycles, polecat continues

Sandbox setup: For active work. gt sling prepares a fresh branch for the assignment.

bash
gt sling gt-xyz gastown  # Allocates capacity and prepares branch

Session cycling happens constantly. Sandbox setup/cleanup is tied to assignments.

Anti-Patterns

Manual State Transitions

Anti-pattern:

bash
gt polecat done Toast    # DON'T: external state manipulation
gt polecat reset Toast   # DON'T: manual lifecycle control

Correct:

bash
# Polecat signals its own completion:
gt done  # (from inside the polecat session)

# Only explicit nuke destroys polecats:
gt polecat nuke Toast  # (destroys sandbox, identity persists)

Polecats manage their own session lifecycle. External manipulation bypasses verification.

Sandboxes Without Work (Idle vs Done vs Stalled)

An idle polecat has no hook, no session, and no completion/MR cleanup state —
this is available capacity.

A done polecat has completed work and exited, but branch/MR or cleanup state
may still be attached. It is not reusable until cleanup resolves that state.

A stalled polecat has a hook but no session — this is a failure:

  • The session crashed and wasn't nudged back to life
  • The hook was lost during a crash
  • State corruption occurred

Recovery for stalled:

bash
# Witness respawns the session in the existing sandbox
# Or, if unrecoverable:
gt polecat nuke Toast        # Clean up the stalled polecat
gt sling gt-abc gastown      # Respawn with fresh polecat

Confusing Session with Sandbox

Anti-pattern: Thinking session restart = losing work.

bash
# Session ends (handoff, crash, compaction)
# Work is NOT lost because:
# - Git commits persist in sandbox
# - Staged changes persist in sandbox
# - Molecule state persists in beads
# - Hook persists across sessions

The new session picks up where the old one left off via gt prime.

Session Lifecycle Details

Sessions cycle for these reasons:

Trigger Action Result
gt handoff Voluntary Clean cycle to fresh context
Context compaction Automatic Forced by Claude Code
Crash/timeout Failure Witness respawns
gt done Completion Session exits, polecat goes done

All except gt done result in continued work. Only gt done signals completion
and retires the completed polecat session.

Witness Responsibilities

The Witness monitors polecats but does NOT:

  • Force session cycles (polecats self-manage via handoff)
  • Interrupt mid-step (unless truly stuck)
  • Reuse polecats after completion while cleanup/MR state remains

The Witness DOES:

  • Detect and nudge stalled polecats (sessions that stopped unexpectedly)
  • Clean up zombie polecats (sessions where gt done failed)
  • Respawn crashed sessions
  • Handle escalations from stuck polecats (polecats that explicitly asked for help)

Polecat Identity

Key insight: Polecat identity is permanent; sessions are ephemeral, sandboxes are persistent.

In the HOP model, every entity has a chain (CV) that tracks:

  • What work they've done
  • Success/failure rates
  • Skills demonstrated
  • Quality metrics

The polecat name (Toast, Shadow, etc.) is a slot from a pool — persistent until
explicit nuke. The agent identity that executes as that polecat accumulates a
work history across all assignments.

text
POLECAT IDENTITY (permanent)      SESSION (ephemeral)     SANDBOX (assignment-scoped)
├── CV chain                      ├── Claude instance     ├── Git worktree
├── Work history                  ├── Context window      ├── Branch
├── Skills demonstrated           └── Dies on handoff     └── Retired after cleanup
└── Credit for work                   or gt done              by gt sling

This distinction matters for:

  • Attribution - Who gets credit for the work?
  • Skill routing - Which agent is best for this task?
  • Cost accounting - Who pays for inference?
  • Federation - Agents having their own chains in a distributed world

Implementation Status

As of 2026-03-07 (gt-o8g8 audit), all core lifecycle operations are shipped and
running in production
. See design/polecat-lifecycle-patrol.md § 10
for the full implementation matrix and design/persistent-polecat-pool.md
for phase-by-phase shipping status.

Key files:

  • internal/cmd/done.go — work submission, done-state handoff, session retirement
  • internal/cmd/sling.go + polecat_spawn.go — capacity allocation, branch setup
  • internal/cmd/handoff.go — session cycling for all roles
  • internal/witness/handlers.go — cleanup pipeline, POLECAT_DONE routing, zombie/orphan detection
  • internal/polecat/manager.go — stale detection, done-state projection, pool management

File: docs/concepts/propulsion-principle.md

The Propulsion Principle

If you find something on your hook, YOU RUN IT.

Gas Town is a steam engine. Agents are pistons. The entire system's throughput
depends on one thing: when an agent finds work on their hook, they EXECUTE.

Why This Matters

  • There is no supervisor polling asking "did you start yet?"
  • The hook IS your assignment - it was placed there deliberately
  • Every moment you wait is a moment the engine stalls
  • Other agents may be blocked waiting on YOUR output

The Handoff Contract

When you were spawned, work was hooked for you. The system trusts that:

  1. You will find it on your hook
  2. You will understand what it is (bd show / gt hook)
  3. You will BEGIN IMMEDIATELY

This isn't about being a good worker. This is physics. Steam engines don't
run on politeness - they run on pistons firing. You are the piston.

Molecule Navigation: Key Enabler

Molecules enable propulsion by providing clear waypoints. You don't need to
memorize steps or wait for instructions - discover them:

Orientation Commands

bash
gt hook              # What's on my hook?
gt prime             # Shows inline formula checklist
bd show    # What's my assigned issue?

The New Workflow: Inline Formula Steps

Formula steps are shown inline at prime time — no step beads to manage:

bash
gt prime             # See your checklist
# Work through each step in order
gt done              # Submit and self-clean (polecats)
gt patrol report     # Close + next cycle (patrol agents)

No step closures, no bd mol current, no momentum-killing transitions.

The new workflow (propulsion):

bash
bd close gt-abc.3 --continue

One command. Auto-advance. Momentum preserved.

The Propulsion Loop

text
1. gt hook                   # What's hooked?
2. bd mol current             # Where am I?
3. Execute step
4. bd close <step> --continue # Close and advance
5. GOTO 2

The Failure Mode We're Preventing

text
Polecat restarts with work on hook
  → Polecat announces itself
  → Polecat waits for confirmation
  → Witness assumes work is progressing
  → Nothing happens
  → Gas Town stops

Startup Behavior

  1. Check hook (gt hook)
  2. Work hooked → EXECUTE immediately
  3. Hook empty → Check mail for attached work
  4. Nothing anywhere → ERROR: escalate to Witness

Note: "Hooked" means work assigned to you. This triggers autonomous mode
even if no molecule is attached. Don't confuse with "pinned" which is for
permanent reference beads.

The Capability Ledger

Every completion is recorded. Every handoff is logged. Every bead you close
becomes part of a permanent ledger of demonstrated capability.

  • Your work is visible
  • Redemption is real (consistent good work builds over time)
  • Every completion is evidence that autonomous execution works
  • Your CV grows with every completion

This isn't just about the current task. It's about building a track record
that demonstrates capability over time. Execute with care.


File: docs/contrib-harnesses/polecat-pr-flow/polecat.md

PR-Flow Polecat Policy

Rig Policy — overrides formula instructions where they conflict.

This rig uses a polecat → GitHub PR → human review flow. After pushing
your branch, you MUST ensure a GitHub PR is open for it before running
gt done.

This overrides the canonical Refinery merge-queue assumption embedded in
mol-polecat-work. gt done is still the completion signal — but in this
rig, a visible PR is the gating artifact for review.

Required steps after implementation

  1. Push the branch explicitly (do not rely on gt done to push):
    bash
    git push -u origin HEAD
  2. Check whether a PR already exists for the branch:
    bash
    gh pr view "$(git branch --show-current)" >/dev/null 2>&1
  3. If no PR exists, create one against the base branch:
    bash
    gh pr create --fill --base main
  4. Only then run gt done.

Do NOT

  • Run gt done without a PR open — the review loop breaks.
  • Merge your own PR. A maintainer or the merge queue handles merging.
  • Push directly to main.

If `gh` commands fail

Auth, rate-limit, missing PR template, or unknown base branch — do NOT skip
PR creation to unblock yourself. Escalate to your Witness:

bash
gt mail send <rig>/witness -s "HELP: gh pr create failed" -m "Branch: $(git branch --show-current)
Error: 
Tried: <what you attempted>"

File: docs/contrib-harnesses/polecat-pr-flow/README.md

polecat-pr-flow

A reference harness for rigs that gate polecat work on a GitHub PR rather
than the canonical Refinery merge-queue flow.

It instructs polecats, after their final build/pre-verify passes, to push
their branch and open (or confirm) a GitHub PR before running gt done.

What's in here

File Purpose
polecat.md Role directive for polecats in a PR-flow rig. Broad guardrail — applies to any formula a polecat runs.
mol-polecat-work.toml Formula overlay that appends a PR-creation step to mol-polecat-work's submit-and-exit step. Surgical — only affects this formula.

Both layers are intentional: the directive sets the rig-level expectation
("open PRs, don't merge them yourself"), and the overlay wires the concrete
commands into the workflow a polecat actually sees at gt prime time.

Install

bash
# Role directive (rig-scoped)
mkdir -p ~/gt/<rig>/directives
cp polecat.md ~/gt/<rig>/directives/polecat.md

# Formula overlay (rig-scoped)
mkdir -p ~/gt/<rig>/formula-overlays
cp mol-polecat-work.toml ~/gt/<rig>/formula-overlays/mol-polecat-work.toml

Replace <rig> with your rig's name (e.g. gastown, longeye). For
town-wide installation, drop the <rig>/ segment — but this is almost
never what you want, since different rigs legitimately use different flows.

Verify it's active

bash
# Validate overlay step IDs against the current formula
gt doctor
# Expect: overlay-health: N overlay(s) healthy

# Inspect the rendered formula with the overlay applied
gt formula overlay show mol-polecat-work --rig <rig>

# See the directive text that will be injected at prime time
gt directive show polecat --rig <rig>

# End-to-end: see what a polecat would see
gt prime --explain
# Expect: "Formula overlay: applying 1 override(s) for mol-polecat-work (rig=<rig>)"

What this does / does not do

Does:

  • Tells the polecat to push and open a PR before gt done
  • Sets a rig-level policy that a PR is the review artifact
  • Surfaces gh pr create failure as an escalation to Witness, not a silent skip

Does not:

  • Modify gt done behavior (no Go changes)
  • Force PR creation via framework-level validation (agents can still misbehave)
  • Merge the PR (that's a maintainer / merge-queue concern)
  • Replace the directive or overlay if your rig also uses other customizations
    — merge this content with your existing files rather than overwriting them

When to fork this

If your rig needs additional PR-flow constraints (required reviewers, specific
labels, CODEOWNERS enforcement, CI checks before gt done), copy this harness
and adapt it. The point is a starting template, not a drop-in product.

Fixing an existing PR (gh#3602)

By default gt sling creates a fresh polecat/<name>/+<ts> branch from
main, which means re-slinging a bead with an existing open PR opens a
duplicate PR rather than reusing the original. To resume an existing PR
branch, use --branch or --pr:

bash
# Resume by branch name (works for any open or stashed branch)
gt sling  <rig> --branch polecat/example/gh-1234+abcdef

# Resume by PR number (resolves the head ref via `gh pr view`)
gt sling  <rig> --pr 1234

The polecat's worktree HEAD will land on the named branch, so its commits
extend the existing PR's history and gt done pushes back to the same ref.

Constraints:

  • --branch and --pr are mutually exclusive.
  • Neither can be combined with --base-branch (resume implies its own start point).
  • The --pr form requires the gh CLI to be authenticated against the repo.

The resume branch name is also exposed to formulas as the resume_branch
variable, alongside the existing base_branch, so overlays can react to it.

2. Official Technical Reference & Guides (gastownhall/docs)

Mintlify Starter Kit

Use the starter kit to get your docs deployed and ready to customize.

Click the green Use this template button at the top of this repo to copy the Mintlify starter kit. The starter kit contains examples with

  • Guide pages
  • Navigation
  • Customizations
  • API reference pages
  • Use of popular components

Follow the full quickstart guide

AI-assisted writing

Set up your AI coding tool to work with Mintlify:

bash
npx skills add https://mintlify.com/docs

This command installs Mintlify's documentation skill for your configured AI tools like Claude Code, Cursor, Windsurf, and others. The skill includes component reference, writing standards, and workflow guidance.

See the AI tools guides for tool-specific setup.

Development

Install the Mintlify CLI to preview your documentation changes locally. To install, use the following command:

text
npm i mint

Run the following command at the root of your documentation, where your docs.json is located:

text
mint dev

View your local preview at http://localhost:3000.

Publishing changes

Install our GitHub app from your dashboard to propagate changes from your repo to your deployment. Changes are deployed to production automatically after pushing to the default branch.

Need help?

Troubleshooting

  • If your dev environment isn't running: Run mint update to ensure you have the most recent version of the CLI.
  • If a page loads as a 404: Make sure you are running in a folder with a valid docs.json.

Resources