Step recovery: timeout and release

Implement recovery mechanism for stuck molecule steps.

## Problem
When a worker dies mid-step, the step stays in_progress forever.
Need timeout/release mechanism for nondeterministic idempotence.

## Solution
1. Track step start time (claimed_at timestamp)
2. Timeout: After 30 min in_progress, step returns to pending
3. Manual release: bd release <step-id>

## Implementation Options

### Option A: Beads-level timeout
- Add claimed_at field to issues
- bd ready excludes items in_progress < 30 min
- bd ready includes items in_progress > 30 min (auto-recovery)

### Option B: Daemon-level timeout
- Daemon watches in_progress items
- Moves back to pending after timeout

### Option C: Manual only (MVP)
- bd release <id> manually moves in_progress → pending
- Document recovery procedure
- Witness can automate for polecats

## Recommendation
Start with Option C (manual) for Christmas. Add Option A later.

## Acceptance
- [ ] bd release command works
- [ ] Stuck steps can be recovered
- [ ] Documented recovery procedure


Swarm cleanup: delete merged polecat branches and reset state

After a swarm completes and branches are merged, leftover state remains:

## Current Problem

1. **Remote branches not deleted** - polecat/* branches stay on origin after merge
2. **Polecat clones not reset** - still on old branch with completed work
3. **No cleanup command** - manual cleanup required

## Observed After Swarm

Remote branches still present:
- origin/polecat/Morsov
- origin/polecat/Nux
- origin/polecat/Rictus
- origin/polecat/Slit
- origin/polecat/Toast

## Proposed Solution

Add cleanup commands:

1. gt swarm cleanup <swarm-id> - Clean up after swarm completion
   - Delete remote polecat branches that were merged
   - Reset polecat clones to main
   - Clear issue assignments

2. gt polecat reset <rig>/<polecat> - Reset single polecat
   - git checkout main && git pull
   - Delete local polecat branch
   - Clear current issue assignment

3. Auto-cleanup option on gt session stop --cleanup

## Manual Cleanup For Now

git push origin --delete polecat/Nux polecat/Toast ...
cd polecats/Nux && git checkout main && git pull


mol-deacon-patrol

Deacon patrol molecule template. Label: template


Beads epic templates for batch work patterns

Optional: Define templates for common batch work patterns.

## Concept

A template encodes a workflow pattern that can be instantiated as beads:

```yaml
# templates/batch-basic.yaml
name: basic-batch
description: Simple batch work pattern
phases:
  - name: startup
    issues:
      - title: "Verify workers ready"
  - name: working
    # Actual work issues added separately
  - name: cleanup
    issues:
      - title: "Merge all branches"
      - title: "Clean up workers"
      - title: "Report to Mayor"
```

## Usage

```bash
gt spawn --template basic-batch --epic gt-u1j --workers 3
```

Creates beads epic with template phases + actual work from gt-u1j children.

## Decision Point

Templates are OPTIONAL. The core design (beads as state, multi-wave orchestration) works without templates. Templates are sugar for common patterns.

Consider deferring to P3 or dropping entirely if beads epics with dependencies suffice.

## Note

No "swarm IDs" involved - templates just pre-populate epic/issue structure.


Plugin surface for daemon lifecycle hooks

Allow rigs to customize daemon behavior via hooks/plugins.

## Hook Points

- on_heartbeat: Called during daemon heartbeat cycle
- on_worker_idle: Called when worker goes idle
- on_worker_stuck: Called when stuck detection triggers
- on_lifecycle_request: Called before processing lifecycle

## Configuration

```
<rig>/config/daemon-hooks.json
{
  "on_heartbeat": "./hooks/check-ci-status.sh",
  "on_worker_idle": "./hooks/maybe-assign-work.sh",
  "idle_threshold": "5m",
  "custom_signals": [
    {"name": "ci_status", "command": "./hooks/get-ci.sh"}
  ]
}
```

## Signal Contribution

Hooks can return signals that feed into decision engine:
- SKIP_POKE: Don't poke this agent
- FORCE_POKE: Override backoff, poke now
- CUSTOM_DATA: Extra context for logging

## Use Cases

- Check CI status before interrupting test runs
- Auto-assign work when worker becomes idle
- Custom stuck detection for specific workflows


Design: Swarm shutdown and worker cleanup

Design for graceful swarm shutdown, worker cleanup, and session cycling.

## Key Decisions

1. Pre-kill verification uses model intelligence (not framework rules)
2. Witness can request restart when context filling (mail self, exit)
3. Mayor NOT involved in per-worker cleanup (Witness responsibility)
4. Clear responsibility boundaries between Mayor/Witness/Polecat

## Subtasks (implementation)

- gt-sd6: Polecat decommission checklist prompting
- gt-f8v: Witness pre-kill verification protocol
- gt-eu9: Witness session cycling and handoff
- gt-gl2: Mayor vs Witness cleanup responsibilities

**Design complete.** Each subtask has full specification in its description.


Resource Beads: Leases, locks, and quotas

Resource beads represent reserved resources. Types: vm, lock, slot, quota. Fields: holder, expires, renewable. Daemon monitors for expiry and manages contention.


Refinery background daemon mode

The refinery 'gt refinery start' command only works in foreground mode (--foreground). Need to implement background daemon mode for production use.

Options:
1. Use a separate tmux session for the refinery
2. Implement proper daemonization
3. Use Claude Code session for the refinery agent

For MVP, option 1 (tmux session) is probably simplest.


Molecule Phase Terminology Documentation

Document the three-phase molecule lifecycle with consistent terminology:

## The Phases (States of Matter)

| Phase | State | Nature |
|-------|-------|--------|
| **Proto** | Solid/Crystal | Frozen template, static definition in catalog |
| **Mol** | Liquid | Reified instance, malleable, tracked in git (durable) |
| **Wisp** | Gas | Evaporates after squash, ephemeral orchestration |

## Documentation Gaps Identified

### High Priority
1. Update vision.md Steam Engine metaphor to use proto/mol/wisp terminology
2. Add lifecycle diagram: Proto → bond → Mol or Wisp → squash → Digest
3. Document Go types for phases (ProtoMolecule, etc.)
4. Document .beads-ephemeral/ structure and purpose

### Medium Priority
5. Update CLAUDE.md files (polecat, witness, refinery) with molecule workflow
6. Document bd mol bond/squash/burn CLI API with examples
7. Add polecat guide: Executing molecules and generating summaries

### Low Priority
8. Add terminology glossary to architecture.md
9. Create troubleshooting playbook for stuck molecules
10. Add reference diagrams for state transitions

## Current State
- architecture.md has good molecule basics but uses inconsistent terminology
- vision.md has Steam Engine metaphor (proto=fuel, wisp=steam, digest=distillate)
- molecules.md has detailed reference but needs phase clarity
- builtin_molecules.go has 8 molecules but no phase documentation in code


Test4

test4 body


Polecat management: add, remove, list, state

Polecat lifecycle: add, remove, list, state tracking.

## Data Model

```go
type Polecat struct {
    Name      string          `json:"name"`
    Rig       string          `json:"rig"`
    State     PolecatState    `json:"state"`
    ClonePath string          `json:"clone_path"`
    Branch    string          `json:"branch"`
    Issue     string          `json:"issue,omitempty"`
    CreatedAt time.Time       `json:"created_at"`
    UpdatedAt time.Time       `json:"updated_at"`
}

type PolecatState string
const (
    StateIdle       PolecatState = "idle"
    StateActive     PolecatState = "active"
    StateWorking    PolecatState = "working"
    StateDone       PolecatState = "done"
    StateStuck      PolecatState = "stuck"
)
```

## Interface

```go
type PolecatManager struct {
    rig *Rig
    git *Git
}

func NewPolecatManager(rig *Rig, git *Git) *PolecatManager

// Lifecycle
func (pm *PolecatManager) Add(name string) (*Polecat, error)
func (pm *PolecatManager) Remove(name string) error
func (pm *PolecatManager) List() ([]*Polecat, error)
func (pm *PolecatManager) Get(name string) (*Polecat, error)

// State
func (pm *PolecatManager) SetState(name string, state PolecatState) error
func (pm *PolecatManager) AssignIssue(name, issue string) error
func (pm *PolecatManager) ClearIssue(name string) error

// Convenience
func (pm *PolecatManager) Wake(name string) error   // idle → active
func (pm *PolecatManager) Sleep(name string) error  // active → idle
```

## Add Flow

1. Create directory: `<rig>/polecats/<name>/`
2. Clone rig repo into it (or copy from rig root)
3. Create new branch: `polecat/<name>`
4. Initialize polecat state file
5. Create mail inbox

## Remove Flow

1. Verify session not running
2. Check for uncommitted changes (warn/error)
3. Remove directory
4. Clean up state

## State Persistence

Store in `<rig>/polecats/<name>/state.json`


implement

Implement the solution for gt-test123. Follow codebase conventions.
File discovered work as new issues with bd create.

Make regular commits with clear messages.
Keep changes focused on the assigned issue.

Depends: load-context


Use Beads issue status as spawn source of truth

Currently witness tracks spawned issues in .gastown/witness.json to prevent re-spawning:

{"spawned_issues": ["gt-abc1", "gt-def2", ...]}

This is redundant with Beads issue status (in_progress). The witness could query:
  bd list --status=in_progress

The local list serves as a performance cache to avoid querying beads every cycle. Consider:
1. Use Beads as source of truth
2. Keep local cache with TTL
3. Sync cache on witness start

This simplifies state management and ensures consistency.


Update documentation for new config architecture

Update docs to reflect new structure:
- docs/architecture.md: Directory structure section
- CLAUDE.md files: Config references
- Add docs/configuration.md with full reference


Plugin: Plan-to-Epic converter

## Purpose

Help users create beads epics from various planning inputs.

## Inputs
- Markdown task lists
- GitHub issues
- Linear/Jira exports
- Free-form descriptions
- Existing beads epics

## Output
- Beads epic with properly structured children
- Dependencies set for wave ordering
- Priorities assigned
- Ready for `gt spawn --epic <id>`

## Implementation Options

### Option A: CLI Tool
```bash
gt plan import --from github --repo owner/repo --label batch-candidate
gt plan import --from markdown tasks.md
gt plan structure <epic-id>  # analyze and add dependencies
```

### Option B: Plugin Agent
A plugin at `<rig>/plugins/plan-oracle/` that:
- Receives planning requests via mail
- Analyzes scope and requirements
- Creates structured beads epic
- Sets dependencies based on analysis

### Option C: Interactive Mode
```bash
gt plan create
# Walks through questions, creates epic interactively
```

## Axiom

As stated: 'The Planning phase should end in the creation of a workable Beads plan.'

This plugin bridges the gap between human planning and machine-executable work.

## Priority

P2 - Nice to have for MVP. Manual epic creation works for now.

## Note

No "swarm IDs" - output is just a beads epic with children. Workers process it independently.


Merge execution: merge, test, push

Implement the actual merge execution.

Steps:
1. git checkout <mr.target>
2. git merge <mr.branch> --no-ff -m 'Merge <branch>: <title>'
3. If config.run_tests:
   - Run test_command (from config)
   - If failed: git reset --hard HEAD~1, return Failure(tests_failed)
4. git push origin <mr.target>
5. Return Success(merge_commit=HEAD)

Configuration:
- run_tests: bool (default true)
- test_command: string (default 'go test ./...')

Handle push failures with retry logic.

Reference: docs/merge-queue-design.md#process-merge-steps


Bug: LIFECYCLE messages use literal <rig> placeholder

Found stale LIFECYCLE messages addressed to @<rig>/witness instead of actual rig names like @gastown/witness. Template substitution not happening.

Examples found:
- gm-bay: LIFECYCLE: polecat requesting shutdown (to @<rig>/witness)
- gm-7du, gm-94e, gm-u5x, gm-89b: same issue

Fix: Ensure rig name is substituted in lifecycle mail templates.


gt mail: Cross-level routing is broken

**Problem:**
When Mayor (at ~/gt) sends mail to a rig worker (gastown/crew/max), the message lands in town-level beads (~/.beads/) but the recipient checks rig-level beads (crew/max/.beads/).

**Reproduction:**
```bash
cd ~/gt
gt mail send gastown/crew/max -s 'Test' -m 'body'
# Message goes to ~/gt/.beads/ with prefix hq-*

cd ~/gt/gastown/crew/max
gt mail inbox
# Does NOT see the message - it's looking in crew/max/.beads/
```

**Root cause:**
`findBeadsWorkDir()` walks up from CWD to find .beads. `Router.Send()` runs `bd create` in that directory. This means messages always go to the sender's beads, not the recipient's.

**Fix options:**
1. Route based on recipient address - if sending to rig/*, use that rig's .beads
2. Use a single shared beads database for all mail (simpler but less isolated)
3. Teach agents to check both levels (workaround, not fix)

**Related:**
- gt-ngu1: Pinned beads sorting (done but pointless if mail doesn't route)
- This blocks all cross-level mail functionality


Work on gt-e11: gt mail send priority flag is incompatibl...

Work on gt-e11: gt mail send priority flag is incompatible with bd mail send. Run 'bd show gt-e11' for details.


Add gt hook command (wrapper for bd hook)

Add a thin wrapper command `gt hook` that calls `bd hook` to inspect what's pinned to an agent's hook.

## Usage

```bash
gt hook                    # Show what's on current agent's hook
gt hook --agent deacon     # Show Deacon's hook
gt hook --agent gastown/furiosa  # Show polecat's hook
```

## Implementation

Thin wrapper in gt that:
1. Determines current agent identity
2. Calls `bd hook [--agent <name>]`
3. Formats output for gt context

## Why gt wrapper?

- Consistent with gt ecosystem (gt mail, gt status, etc.)
- Can add gt-specific context (session status, etc.)
- Easier discovery for gt users

## Related

- bd hook command (implemented by Dave)
- Chemistry UX design: gastown/mayor/rig/docs/chemistry-design-changes.md


gt orphans: Find lost polecat work

Add a command to find orphaned commits that were never merged to main.

## Problem
Polecat work can get lost when:
- Session killed before merge
- Refinery fails to process
- Network issues during push

## Solution
Add `gt orphans` command that:
1. Uses `git fsck --unreachable` to find dangling commits
2. Filters to recent commits (default: 7 days, configurable)
3. Excludes stash/index entries (WIP on, index on)
4. Shows commit details and suggests recovery

## Usage
```
gt orphans              # Last 7 days
gt orphans --days=14    # Last 2 weeks
gt orphans --recover    # Interactive cherry-pick
```

## Found orphans (Dec 16-20, 2025)
- 3b146c11: Fix mail read auto-ack and add Mayor startup directive
- b6fdc561: Add persistent theme config and fix crew session theming
- 97aba756: Unify gt prime to call bd prime and mail check
- ce769ca5: Add mol-bootstrap molecule for Gas Town installation
- b2219de7: Add bootstrap documentation for new Gas Town installations
- bc82348: feat: Add gt done command (already recovered)


implement

Implement the solution for {{issue}}. Follow codebase conventions.
File discovered work as new issues with bd create.

Make regular commits with clear messages.
Keep changes focused on the assigned issue.

Depends: load-context


Fix TestHasPolecat test failure in internal/session

TestHasPolecat in internal/session/manager_test.go fails because it expects
specific polecats (Toast, Cheedo) to exist in the test environment.

Error:
```
manager_test.go:46: expected hasPolecat(Toast) = true
manager_test.go:49: expected hasPolecat(Cheedo) = true
```

Fix: Either create test fixtures or mock the filesystem check.


implement

Implement the solution for gt-qwyu. Follow codebase conventions.
File discovered work as new issues with bd create.

Make regular commits with clear messages.
Keep changes focused on the assigned issue.

Depends: load-context


detectSender() doesn't recognize crew workers

## Problem

detectSender() in internal/cmd/mail.go only checks for /polecats/ directories. Crew workers in /crew/<name>/ fall through to the default 'mayor/', so:
- gt mail inbox shows mayor's inbox instead of the crew worker's
- gt mail send sets the wrong From address

## Fix

Add crew worker detection before the /polecats/ check:

if strings.Contains(cwd, "/crew/") {
    parts := strings.Split(cwd, "/crew/")
    ...
    return fmt.Sprintf("%s/crew/%s", rigName, crewMember)
}

## Affected
- Any crew worker running gt mail inbox without explicit address
- Crew worker handoffs (wrong sender)


gt polecat add: should handle existing branch gracefully

## Problem

`gt polecat add gastown Nux` fails if the branch `polecat/Nux` already exists.

## Current Behavior

```
fatal: a branch named 'polecat/Nux' already exists
```

## Expected Behavior

Should either:
1. Reuse the existing branch
2. Or prompt to delete/recreate
3. Or auto-suffix: polecat/Nux-2

## Context

Branch may exist from previous polecat that was removed but branch wasn't cleaned up.


Add bulk session stop command (gt session stop --all)

When decommissioning a rig, need to stop multiple sessions one at a time. A --all or --rig flag would allow: gt session stop --rig gastown


Refinery agent: merge queue processing loop

The Refinery agent processes the merge queue, merging polecat work to main.

## Interface

```go
type Refinery struct {
    rig    *Rig
    queue  *MergeQueue
    git    *Git
    mail   *Mailbox
    config RefineryConfig
}

type RefineryConfig struct {
    AutoMerge     bool          // Auto-merge passing MRs
    RunTests      bool          // Run tests before merge
    TestCommand   string        // Command to run tests
    RequireReview bool          // Require review before merge (future)
}

func NewRefinery(rig *Rig, ...) *Refinery

// Lifecycle
func (r *Refinery) Start() error
func (r *Refinery) Stop() error
func (r *Refinery) IsRunning() bool

// Processing
func (r *Refinery) ProcessQueue() error
func (r *Refinery) ProcessMR(mr *MergeRequest) error
```

## Processing Loop

1. Check queue for pending MRs
2. For each pending MR:
   a. Fetch polecat branch
   b. Attempt merge to refinery/rig (local main)
   c. Run tests if configured
   d. If pass: push to origin, mark merged
   e. If fail: mark rejected, notify polecat
3. Sleep, repeat

## Merge Strategy

- Fast-forward when possible
- Merge commit when not
- On conflict: reject MR, polecat must rebase

## Test Integration

If tests configured:
```bash
cd refinery/rig
git merge polecat/branch
<test_command>  # e.g., go test ./...
```
Result determines merge/reject.

## Notifications

On merge success:
- Mail to polecat: "Your work merged"
- Update bead if issue tracked

On merge failure:
- Mail to polecat: "Merge failed: <reason>"
- Include conflict details if applicable

## Dependencies

Needs: Rig management, Git wrapper, Mail system, Merge queue


session stop: --force flag is defined but not used


Inconsistent error wrapping patterns

Error handling is inconsistent across the codebase:

1. Some functions use fmt.Errorf with %w for wrapping, others don't
2. return nil, nil patterns (40+ occurrences) sometimes represent 'not found' and sometimes 'error but continue' - should use sentinel errors
3. Some places return nil for errors when they should propagate them

Examples of nil,nil that might need review:
- internal/git/git.go:272, 308
- internal/crew/manager.go:227
- internal/witness/manager.go:517, 523, 530, 775
- internal/beads/beads.go:225, 492


Remove unused style helper functions

internal/style/style.go defines RenderSuccess, RenderWarning, RenderError, and RenderInfo helper functions that are never used. Code uses style.Success.Render() directly instead. Either use the helpers consistently or remove them.


Swarms of One: Lightweight single-worker task dispatch

Design and implement a lightweight pattern for firing off single workers to handle tasks without full swarm overhead.

## Context

Currently we have:
- town spawn: Creates a polecat in a rig with issue assignment
- Swarms (sw-*): Full lifecycle tracking with manifest, state, events, reports
- Ephemeral rigs (rig-*): Temporary worker groups for swarms

What's missing: A simple way to say 'fire off a worker to do X' without swarm ceremony.

## Design Questions

1. Should this be a new command like 'gt fire' or an option on existing commands?
2. Should single tasks still get swarm IDs (sw-N) for consistency/queryability?
3. Should it default to creating new workers or support --reuse for idle polecats?
4. How does this relate to crew workers (gt-cik)?

## Possible Interface

gt fire --rig gastown --issue gt-xyz [--prompt '...']
gt fire gastown/QuickTask --issue gt-xyz

## Related

- gt-cik: Overseer Crew (user-managed persistent workspaces)
- gt-kmn: Swarm System epic


Federation: Wasteland architecture for cross-town coordination

## Overview

Federation enables Gas Town to scale across machines via **Outposts** - remote compute environments that can run workers.

**Design doc**: docs/federation-design.md

## Outpost Types

| Type | Description | Cost Model |
|------|-------------|------------|
| Local | Current model (tmux panes) | Free |
| SSH/VM | Full Gas Town clone on VM | Always-on |
| CloudRun | Container workers on GCP | Pay-per-use |

## Key Concepts

### Outpost Abstraction
```go
type Outpost interface {
    Name() string
    Type() OutpostType  // local, ssh, cloudrun
    MaxWorkers() int
    Spawn(issue string, config WorkerConfig) (Worker, error)
    Workers() []Worker
    Ping() error
}
```

### Cloud Run Workers
- Persistent HTTP/2 connections solve zero-to-one cold start
- Pay only when working (~$0.017 per 5-min session)
- Scale 0→N automatically
- Git clone via persistent volumes

### SSH/VM Outposts
- Full Gas Town clone on remote machine
- SSH for commands, git for sync
- Good for long-running autonomous work

## Design Principles

1. **Outpost abstraction** - support multiple backends
2. **Local-first** - remote is for overflow/burst
3. **Git as source of truth** - code and beads sync everywhere
4. **HTTP for Cloud Run** - dont force mail onto containers
5. **Graceful degradation** - works with any subset of outposts

## Related

- gt-f9x.7-10: Connection interface (lower-level abstraction)
- docs/federation-design.md: Full architectural analysis


Work assignment mail not received by polecat

When gt spawn sends a work assignment:

1. gt spawn says '✓ Work assignment sent'
2. Polecat runs 'gt mail inbox'
3. Shows '0 messages, 0 unread'

The work assignment mail never arrived at the polecat's inbox.

## Observed in session
- Spawned polecat dementus on gt-th7
- Polecat checked inbox: empty
- Polecat couldn't find issue (separate sync bug)

## Possible causes
- Mail routing issue for polecat addresses
- gt spawn not actually sending mail
- Mail sent to wrong address format

This was likely caused by stale beads in old polecats. With gt-9nf (fresh polecats), polecats now use shared rig beads via redirect file, eliminating sync issues. Mail routing uses town beads correctly.


gt swarm: Not discovering tasks from epic dependents

gt swarm create/start shows '0 tasks loaded' even when epic has dependents.

Repro:
1. Create epic gt-hw6
2. Create tasks and add deps: bd dep add gt-xxx gt-hw6
3. gt swarm create gastown --epic gt-hw6 --worker Toast
4. Swarm shows 'Tasks: 0'

Expected: Swarm should discover tasks that depend on the epic.
Actual: Shows '(no tasks loaded)'


Connection interface: Protocol for local/remote ops

Abstract interface for local vs remote (SSH) operations.

## Concept

Enable Gas Town to manage rigs on remote machines via SSH. The Connection interface abstracts whether operations happen locally or remotely.

## Interface

```go
type Connection interface {
    // Identification
    Name() string
    IsLocal() bool

    // File operations
    ReadFile(path string) ([]byte, error)
    WriteFile(path string, data []byte, perm os.FileMode) error
    MkdirAll(path string, perm os.FileMode) error
    Remove(path string) error
    Stat(path string) (os.FileInfo, error)
    Glob(pattern string) ([]string, error)

    // Command execution
    Exec(cmd string, args ...string) ([]byte, error)
    ExecDir(dir, cmd string, args ...string) ([]byte, error)

    // Tmux (for session management)
    TmuxNewSession(name, dir string) error
    TmuxKillSession(name string) error
    TmuxSendKeys(session, keys string) error
    TmuxCapturePane(session string, lines int) (string, error)
}
```

## Implementations

- LocalConnection (gt-f9x.8): Direct file/exec operations
- SSHConnection (future): Operations via SSH

## Usage

```go
func NewRigManager(conn Connection, ...) *RigManager

// Operations work the same regardless of connection type
rm.DiscoverRigs()  // uses conn.Glob, conn.ReadFile
```

## Design Notes

- Connection obtained from MachineRegistry (gt-f9x.9)
- Default is always local
- SSH connection requires machine config (host, key, user)


HOP: Entity chain tracking for agents

Track work history per-entity (CV chains). See ~/ai/stevey-gastown/hop/decisions/002-entity-chains.md for design. Post-v0.1 work.


bd create --dedup: semantic deduplication before issue creation

Before creating issue, check for semantic duplicates using AI similarity.

**From VC**: internal/deduplication/ - AI-powered batch comparison. ~300 lines.
VC had issue pollution problem: 438 issues with ~350+ spam because no early dedup.

**Gas Town implementation**: CLI flag on bd create:
```bash
bd create --dedup --title="Fix auth bug" --description="..."
```

Checks recent issues (7-day window) with AI similarity. If confidence >0.85, warns or blocks.

**Value**: Prevents pollution from parallel workers discovering same issues.

**VC lesson**: 115 issues filed in single day (Nov 2) because supervisor over-discovered without dedup. Rate limiting + dedup are essential.


gt witness: Witness management commands

Add 'gt witness' command group for witness lifecycle management.

Subcommands:
- gt witness start [rig] - Start witness for a rig
- gt witness stop [rig] - Stop witness
- gt witness status [rig] - Show witness status
- gt witness attach [rig] - Attach to witness session

Witness monitors polecats and handles:
- Idle detection and cleanup
- Session health checks
- Nudging stuck agents


Outpost configuration: YAML config and OutpostManager

## Overview

Configuration file for outposts and manager to load/track them.

## Config File

`~/ai/config/outposts.yaml`:

```yaml
outposts:
  - name: local
    type: local
    max_workers: 4

  - name: gce-burst
    type: ssh
    host: 10.0.0.5
    user: steve
    ssh_key: ~/.ssh/gce_worker
    town_path: /home/steve/ai
    max_workers: 8

  - name: cloudrun-burst
    type: cloudrun
    project: my-gcp-project
    region: us-central1
    service: gastown-worker
    max_workers: 20
    cost_cap_hourly: 5.00

policy:
  default_preference: [local, gce-burst, cloudrun-burst]
  overrides:
    - condition: "priority >= P3"
      prefer: cloudrun-burst
```

## OutpostManager

```go
type OutpostManager struct {
    outposts map[string]Outpost
    policy   AssignmentPolicy
}

func NewOutpostManager(configPath string) (*OutpostManager, error)
func (m *OutpostManager) Get(name string) (Outpost, bool)
func (m *OutpostManager) List() []Outpost
func (m *OutpostManager) SelectOutpost(issue Issue) Outpost
```

## Files

- `internal/outpost/manager.go`
- `internal/outpost/config.go` (extend)
- `internal/outpost/policy.go`

Depends on: gt-9a2.1 (interfaces)


Update config location: .gastown/ → config/

Move rig configuration from hidden .gastown/ to visible config/:
- config/rig.json: Rig configuration
- config/engineer.json: Engineer settings (test command, etc.)
- config/witness.json: Witness settings (heartbeat interval, etc.)

Hidden directories are poorly discovered by AI agents.


Test: New Router

Testing bd create for mail


session-gc

Clean dead sessions. Run gt gc --sessions.


Update polecat CLAUDE.md with molecule workflow

Add molecule execution guidance to polecat context:

## What to Add

### Molecule Awareness
- Polecats execute Wisps (ephemeral molecule instances)
- The work assignment mail includes molecule context
- Current step is tracked in the wisp

### Workflow Protocol
1. Read assignment (includes molecule ID and current step)
2. Execute current step
3. Update step status via bd mol step
4. Generate summary when all steps complete
5. Run bd mol squash to compress wisp into digest

### Key Commands
- bd mol show <wisp-id> - view current molecule state
- bd mol step <wisp-id> --status=complete - mark step done
- bd mol squash <wisp-id> --summary='...' - complete molecule

### Summary Generation
When completing work, generate a summary that:
- Lists what was accomplished
- Notes any deviations from the plan
- Captures key decisions made
- This becomes the permanent digest


Test message

Testing GGT mail system


implement

Implement the solution for gt-test. Follow codebase conventions.
File discovered work as new issues with bd create.

Make regular commits with clear messages.
Keep changes focused on the assigned issue.

Depends: load-context


Refinery background daemon mode

Refinery currently only works in foreground mode. Background daemon is stubbed.

## Current State
manager.go line 128-129:
```go
// Background mode: spawn a new process
// For MVP, we just mark as running - actual daemon implementation in gt-ov2
return nil
```

## Requirements

### 1. Background Process Spawning
```go
func (m *Manager) Start(foreground bool) error {
    if !foreground {
        // Spawn gt refinery start --foreground as subprocess
        cmd := exec.Command(os.Args[0], "refinery", "start", m.rig.Name, "--foreground")
        cmd.Start()  // Don't wait
        // Record PID
    }
}
```

### 2. PID File Management
- Write PID to .gastown/refinery.pid
- Check PID validity on status
- Clean up stale PID files

### 3. Log Output
- Redirect stdout/stderr to .gastown/refinery.log
- Log rotation (optional for MVP)

### 4. Graceful Shutdown
- Handle SIGTERM/SIGINT
- Complete current merge before exit
- Update state to stopped

### 5. Health Check
- Process existence check via kill -0
- Optional: heartbeat file with timestamp

## Files to Modify
- internal/refinery/manager.go: Start(), Status(), process spawning

## Acceptance Criteria
- [ ] gt refinery start <rig> spawns background process
- [ ] gt refinery status shows running with PID
- [ ] gt refinery stop sends SIGTERM and waits
- [ ] Logs written to .gastown/refinery.log
- [ ] Survives terminal close


Molecules: Composable Workflow Beads

## Summary

Molecules are crystallized workflow patterns stored as Beads issues.
When instantiated, the molecule creates child beads forming a DAG.

## Key Insight: Molecules ARE Beads

Per HOP Decision 001: Beads IS the ledger. Molecules don't get a separate YAML format - they're issues with `type: molecule` containing prose-based step definitions.

Agents don't need rigid schemas. They parse natural language natively. A molecule is just instructions with enough structure for tooling.

## Example: Engineer in a Box

```markdown
id: mol-xyz
type: molecule
title: Engineer in a Box

This workflow takes a task from design to merge.

## Step: design
Think carefully about architecture. Consider existing patterns,
trade-offs, testability.

## Step: implement
Write clean code. Follow codebase conventions.
Needs: design

## Step: review
Review for bugs, edge cases, style issues.
Needs: implement

## Step: test
Write and run tests. Cover happy path and edge cases.
Needs: implement

## Step: submit
Submit for merge via refinery.
Needs: review, test
```

## Instantiation

```bash
# Attach molecule when spawning
gt spawn --issue gt-abc --molecule mol-xyz

# Creates child beads atomically:
gt-abc.design     ← ready first
gt-abc.implement  ← blocked by design
gt-abc.review     ← blocked by implement
gt-abc.test       ← blocked by implement
gt-abc.submit     ← blocked by review, test
```

Each step issue gets an `instantiated-from` edge to the molecule (with step metadata).

## Why This Matters

1. **Unified data plane**: Everything in Beads, no parallel YAML channel
2. **AI-native**: Prose instructions, not rigid schemas
3. **Error isolation**: Each step is a checkpoint - failure doesn't lose progress
4. **Scales with AI**: As agents get smarter, they handle more complex molecules

## Implementation Primitives

- `ParseMoleculeSteps()`: Extract steps from prose (convention-based)
- `InstantiateMolecule()`: Atomic transaction creating all steps + edges
- `instantiated-from` edge type: Track provenance
- Parameterization: `{{variable}}` substitution from context map


Phase 1.2: Configure bd for ephemeral molecule bonding

Ensure bd mol bond --ephemeral works with Gas Town setup.

## Questions for Dave

1. Does bd automatically find .beads-ephemeral/ or need explicit path?
2. How does bd mol bond --ephemeral know which repo to use?
3. Is there a redirect mechanism for ephemeral like main beads?

## Integration

From polecat/crew working directory:
```bash
bd mol bond mol-polecat-work --ephemeral --assignee $(gt whoami)
```

Should create molecule in rig's .beads-ephemeral/, not main beads.


Integration branch management for swarms

Manage integration branches for swarm merging strategy.

## Branch Naming

- Integration branch: `integration/<swarm-id>` (e.g., integration/sw-1)
- Worker branches: `<swarm-id>/<polecat>` (e.g., sw-1/Toast)

## Operations

```go
// Create integration branch at swarm start
func (m *SwarmManager) CreateIntegrationBranch(swarmID string) error
// - Creates from BaseCommit
// - Pushes to origin

// Merge worker branch to integration
func (r *Refinery) MergeToIntegration(swarmID, workerBranch string) error
// - Fetches worker branch
// - Merges to integration/<swarm-id>
// - Handles conflicts (semantic merge)

// Land integration to main
func (r *Refinery) LandToMain(swarmID string) error
// - Merges integration/<swarm-id> to main
// - Pushes to origin
// - Triggers cleanup

// Cleanup branches after landing
func (m *SwarmManager) CleanupBranches(swarmID string) error
// - Deletes integration/<swarm-id> (local + remote)
// - Deletes all <swarm-id>/<polecat> branches
```

## All Workers Same Base

When swarm starts:
1. Record current main HEAD as BaseCommit
2. All polecats branch from BaseCommit
3. Integration branch also starts at BaseCommit

This ensures clean merges within the swarm.

## Reference

PGT: ephemeral.py (create_integration_branch, merge_integration_to_main)


gt uninstall: Clean removal of Gas Town harness

Add 'gt uninstall' command to cleanly remove a Gas Town installation.

Should:
- Remove harness directory structure
- Optionally preserve rigs/data with --keep-data flag
- Warn about running sessions
- Clean up any global config references


Deacon rounds molecule: the kernel execution loop

Define and implement mol-deacon-rounds - the molecule the Deacon executes each wake.

## Molecule Definition

```markdown
# mol-deacon-rounds

The Deacon kernel - executed on every wake cycle.

## Step: session-check
Check context budget. If low, cycle to fresh session.
Needs: (none - always runs first)

## Step: health-scan
Check health of all monitored agents:
- Mayor (gt-mayor session)
- Witnesses (gt-*-witness sessions)
- Refineries (gt-*-refinery sessions)
- Crew (gt-*-* sessions, lifecycle only)

Remediate unhealthy agents:
- Restart dead sessions
- Nudge stuck agents
- Escalate if remediation fails

Needs: session-check

## Step: lifecycle
Process pending lifecycle requests from mail:
- LIFECYCLE: <identity> requesting cycle
- LIFECYCLE: <identity> requesting restart
- LIFECYCLE: <identity> requesting shutdown

Needs: health-scan

## Step: plugins
Run due plugins:
1. Check scheduled plugins (cron-like)
2. Check event-triggered plugins (from mail events)
3. Check human-requested plugins (from mail)
4. Execute each, record outcomes

Needs: lifecycle

## Step: events
Process timer and event callbacks:
- TIMER: <identity> wake at <time>
- EVENT: <type> <payload>

Notify relevant agents or trigger actions.

Needs: plugins

## Step: complete
Finalize the cycle:
1. Update heartbeat.json
2. Clear/update keepalive.json
3. Log summary
4. Return to prompt (wait for next wake)

Needs: events
```

## Execution

The Deacon reads this molecule from its pinned bead and executes steps in order.
Each step:
1. Announces "Starting <step>"
2. Performs the step logic
3. Records outcome
4. Proceeds to next step

## Step Plugins

Each step can have inline plugins (additional attention):
```yaml
step: health-scan
  plugins:
    - advanced-diagnostics  # Run if basic scan finds issues
```

## Relation to bd mol

Uses the same molecule format as bd mol for polecats.
Deacon molecule is special: it's the kernel, not work.


Refinery semantic merge processing loop

Implement the Refinery semantic merge loop for processing polecat work.

## Overview

The Refinery is a fully empowered Claude Code agent that:
1. Fetches polecat branches
2. Merges to integration branch
3. Resolves conflicts semantically (re-implements if needed)
4. Runs tests
5. Escalates only when truly stuck

## Processing Loop

1. Check queue for completed tasks (polecat done, not yet merged)
2. For each task:
   - Fetch polecat branch
   - Attempt merge to integration/<swarm-id>
   - On conflict: semantic resolution (understand intent, re-implement)
   - Run tests if configured
   - On success: mark merged, file bead, notify witness
   - On failure: notify polecat (test fail) or escalate (stuck)
3. When all tasks merged: land integration to main

## Semantic Merge

When git merge fails, Refinery:
1. Reads polecat changes and beads issue
2. Understands intent
3. Re-implements on current integration branch
4. Only escalates if truly blocked

## Daemon Poking

Refinery is poked by:
- Daemon heartbeat (periodic)
- Witness notification (polecat done)
- Mayor request (check queue)

## Dependencies

Needs: gt-u1j.6 (mail), gt-u1j.3 (git), gt-u1j.14 (merge queue)

## Reference

See PGT ephemeral.py for branch operations.


Bug: parseLifecycleRequest always matches 'cycle' due to LIFECYCLE prefix

In lifecycle.go, parseLifecycleRequest checks strings.Contains(title, "cycle") first, but the prefix "LIFECYCLE:" contains the word "cycle". This means ALL lifecycle messages match the cycle action, making restart and shutdown unreachable. Fix: check for restart/shutdown before cycle, or use word boundaries.


Design GGT prompt architecture

Audit PGT prompts and design canonical prompt system for GGT. Create docs/prompts.md with inventory, gap analysis, and Witness prompt design.


Mail coordination should use town-level database

gt mail send/inbox should use ~/gt/.beads (town root) not rig-local beads. Cross-rig mail coordination (Witness <-> Mayor, polecat <-> Witness) needs to be in a shared location.


CloudRun protocol types: WorkRequest, WorkEvent, WorkResult

## Overview

HTTP protocol types for Cloud Run work dispatch. **Types only** - server and client are separate tasks.

## Request Type

```go
type WorkRequest struct {
    IssueID string          `json:"issue_id"`
    Rig     RigConfig       `json:"rig"`
    Beads   BeadsConfig     `json:"beads"`
    Branch  string          `json:"worker_branch"`
    Context map[string]any  `json:"context,omitempty"`
}

type RigConfig struct {
    URL    string `json:"url"`
    Branch string `json:"branch"`
}

type BeadsConfig struct {
    URL    string `json:"url"`
    Branch string `json:"branch"`
}
```

## Response Types (streaming NDJSON)

```go
type WorkEvent struct {
    Type     string `json:"type"`  // status, log, progress, result, error
    Status   string `json:"status,omitempty"`
    Line     string `json:"line,omitempty"`
    Percent  int    `json:"percent,omitempty"`
    Branch   string `json:"branch,omitempty"`
    PRURL    string `json:"pr_url,omitempty"`
    Code     string `json:"code,omitempty"`
    Message  string `json:"message,omitempty"`
}

type WorkResult struct {
    Status  string `json:"status"`  // done, failed
    Branch  string `json:"branch"`
    PRURL   string `json:"pr_url,omitempty"`
    Error   string `json:"error,omitempty"`
}
```

## Files

- `internal/cloudrun/protocol.go` - All types above

## Notes

This is just types. Server (gt-9a2.7b) and client (gt-9a2.7c) are separate tasks.
Small, focused task - can complete quickly.


File locking for concurrent access

Add file locking for concurrent access safety.

## At-Risk Files
- .gastown/swarms.json (or per-swarm state.json)
- .gastown/refinery.json
- polecats/<name>/state.json
- inbox.jsonl files

## Go File Locking
Use syscall.Flock for advisory locking:
```go
type FileLock struct {
    file *os.File
}

func AcquireLock(path string, timeout time.Duration) (*FileLock, error) {
    f, err := os.OpenFile(path+".lock", os.O_CREATE|os.O_RDWR, 0644)
    if err != nil {
        return nil, err
    }
    // Use syscall.Flock with timeout
}

func (l *FileLock) Release() error
```

## Integration Pattern
```go
func (m *Manager) saveState(ref *Refinery) error {
    lock, err := AcquireLock(m.stateFile(), 5*time.Second)
    if err != nil {
        return fmt.Errorf("could not acquire lock: %w", err)
    }
    defer lock.Release()

    // Read-modify-write cycle
}
```

## New Package
internal/filelock/
├── lock.go     # FileLock, AcquireLock
└── lock_test.go

## Apply To
- internal/refinery/manager.go: loadState/saveState
- internal/cmd/swarm.go: SwarmStore
- internal/mail/mailbox.go: Append, rewrite
- internal/polecat/manager.go: state operations

## Timeout Handling
Default 5 second timeout. Return error if lock not acquired.

## Acceptance Criteria
- [ ] Lock files created (.lock extension)
- [ ] Timeout on lock contention
- [ ] All state files protected
- [ ] Locks released on error paths


rebase-main

Rebase against main to incorporate any changes.
Resolve conflicts if needed.

git fetch origin main
git rebase origin/main

If there are conflicts, resolve them carefully and continue the rebase.

Depends: self-review, verify-tests


Merge: gt-rana.1

branch: polecat/rictus
target: main
source_issue: gt-rana.1
rig: gastown


gt done: Missing command referenced in polecat docs


Witness updates: Remove issue filing proxy

Update Witness prompting to remove issue filing proxy, since polecats now have direct beads access.

## Remove from Witness Prompting

The following is NO LONGER Witness responsibility:
- Processing polecat 'file issue' mail requests
- Creating issues on behalf of polecats
- Forwarding issue creation requests

## Add: Legacy Request Handling

If Witness receives an old-style 'please file issue' request:

1. Respond with update:
   town inject <polecat> "UPDATE: You have direct beads access now. Use bd create to file issues yourself."

2. Do not file the issue - let the polecat learn the new workflow.

## Keep in Witness Prompting

- Monitoring polecat progress
- Nudge protocol
- Pre-kill verification
- Session lifecycle management


Merge: gt-pyqv

branch: polecat/dementus
target: main
source_issue: gt-pyqv
rig: gastown


MCP beads tools fail from polecat directories

The beads MCP plugin (plugin:beads:beads) fails to find issues when invoked from polecat directories.

## Observed
- Polecat in /gt/gastown/polecats/dementus
- MCP tool: plugin:beads:beads - show (issue_id: 'gt-th7')
- Error: 'bd command failed: Error: no issue found matching gt-th7'

## Expected
MCP tools should work the same as running bd directly.

## Note
This may be related to gt-tmm (beads sync issue) rather than an MCP-specific bug. The MCP tool uses bd under the hood, and bd can't find the issue because the polecat's beads database is stale.


Consolidate configuration architecture: three-tier model

Rationalize Gas Town's scattered configuration into a clean three-tier model:

## Current Problems
- Config split across mayor/, .gastown/, and rig/config.json
- Runtime state mixed with configuration
- Hidden directories (.gastown/) are missed by agents
- Category confusion: identity vs config vs runtime state

## Proposed Architecture

### Tier 1: Town Config (mayor/)
```
mayor/
├── town.json      # Town identity (unchanged)
├── rigs.json      # Rig registry (unchanged)
└── config.json    # NEW: Town-level configuration
    # theme defaults, daemon settings, etc.
```

### Tier 2: Town Runtime (.runtime/)
```
~/gt/.runtime/                    # NEW: Gitignored
├── daemon.json                   # {pid, started_at, heartbeat}
├── deacon.json                   # {cycle, last_action}
└── agent-requests.json           # Lifecycle requests
```

### Tier 3: Rig Config (settings/)
```
<rig>/
├── config.json                   # Rig identity only (type, git_url, beads.prefix)
├── settings/                     # NEW: Visible, git-tracked
│   ├── config.json               # theme, merge_queue, max_workers
│   ├── namepool.json             # pool settings (style, max)
│   └── roles/                    # Per-role overrides (optional)
└── .runtime/                     # NEW: Gitignored
    ├── witness.json              # {state, started_at, stats}
    ├── refinery.json             # {state, started_at, stats}
    └── namepool-state.json       # {in_use, overflow_next}
```

## Key Principles
1. **Visible > Hidden** for config agents need to find
2. **Git-tracked** for identity and config; **gitignored** for runtime
3. **Separation of concerns**: identity, config, runtime are distinct
4. **Locality**: town config at town root, rig config at rig root

## Migration
- Move .gastown/ contents to appropriate new locations
- Update all code that reads/writes these files
- Update .gitignore patterns
- Update documentation (architecture.md, CLAUDE.md)


Implement gt sling command

The unified work dispatch command.

```bash
gt sling <thing> <target> [options]
```

Implements spawn + assign + pin in one operation. See sling-design.md.

Acceptance:
- [ ] Parse thing (proto name, issue ID, epic ID)
- [ ] Parse target (agent address)
- [ ] Spawn molecule if proto
- [ ] Assign to target agent
- [ ] Pin to agent's hook (pinned bead)
- [ ] Support --wisp flag for ephemeral
- [ ] Support --molecule flag for issue+workflow
- [ ] Error if hook already occupied (unless --force)


Deacon session cycling: first step of rounds

First step of every Deacon wake cycle: check if a fresh session is needed.

## Why First

Token costs are quadratic with session length. A Deacon running for hours
accumulates massive context. Better to cycle early and often.

## Implementation

At wake, before doing anything else:

1. Check context budget estimate (conversation turns, tool calls, etc.)
2. If budget is low (e.g., >50% consumed), request cycle:
   - Write handoff mail to self with current state
   - Request lifecycle: cycle via daemon
   - Daemon kills session, starts fresh
   - New session reads handoff mail, continues

## Decision Criteria

- Conversation turns > N (configurable, default 50?)
- Explicit "context feels heavy" signal from Claude
- Time since last cycle > M hours (configurable, default 4?)
- Forced cycle on certain events (e.g., major config change)

## State to Preserve in Handoff

- Current health status
- Pending lifecycle requests (in flight)
- Plugin state (last run times, outcomes)
- Any active timers

## Relation to Daemon

The Deacon requests its own cycle via the same lifecycle mechanism:
```
gt mail send deacon/ -s "LIFECYCLE: deacon/ requesting cycle" -m "..."
```

Daemon sees this, kills gt-deacon session, respawn loop restarts it.


MR state transitions: validate open→in_progress→closed

Enforce valid state transitions for merge-requests:

Valid transitions:
- open → in_progress (Engineer claims MR)
- in_progress → closed (merge success or rejection)
- in_progress → open (failure, reassign to worker)
- open → closed (manual rejection)

Invalid:
- closed → anything (immutable once closed)

Implement validation in MR update operations.

Reference: docs/merge-queue-design.md#state-machine


Remove stale migration docs from gastown-py

The gastown-py repo has migration-related documentation that is now misinformation since we have made design decisions. Remove or clearly mark as obsolete: any docs about migration paths, old architecture assumptions, or superseded designs.


Overhaul gt mol to match bd mol chemistry interface

## The Sling: Unified Work Dispatch

This issue tracks the overhaul of `gt molecule` to align with chemistry metaphor and introduce the **Universal Gas Town Propulsion Principle**.

### The Propulsion Principle

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

This is the one rule that drives all Gas Town agents.

### The Sling Operation

`gt sling <thing> <target> [options]` - unified command for spawn + assign + pin.

See: `gastown/mayor/rig/docs/sling-design.md`

### Implementation Tasks

| Issue | Title | Priority |
|-------|-------|----------|
| gt-4ev4 | Implement gt sling command | P1 |
| gt-uym5 | Implement gt mol status command | P1 |
| gt-i4kq | Update templates for Propulsion Principle | P1 |
| gt-7hor | Document the Propulsion Principle | P2 |

### Command Changes

| Old | New |
|-----|-----|
| `gt molecule instantiate` | `gt sling` |
| `gt molecule attach` | `gt sling --force` |
| `gt molecule detach` | `gt mol burn` |
| `gt molecule progress` | `gt mol status` |
| `gt molecule list` | `gt mol catalog` |
| `gt spawn --molecule` | `gt sling` |

### Acceptance Criteria

- [ ] `gt sling` works for protos, issues, and epics
- [ ] `gt mol status` shows hook state
- [ ] Templates updated for propulsion principle
- [ ] Old commands deprecated with warnings
- [ ] Documentation complete


Witness role template + CLAUDE.md

Create the Witness agent's role context:

1. internal/templates/roles/witness.md.tmpl
   - Witness responsibilities (polecat lifecycle)
   - Core loop description
   - Commands available (gt polecats, bd ready, etc)
   - Escalation protocol

2. Generate CLAUDE.md for witness/ directories
   - Context about the rig
   - Mail address: <rig>/witness
   - Startup protocol (gt prime, check inbox)

The Witness is the per-rig 'pit boss' - NOT a global coordinator. It manages polecats for ONE rig only.


Interactive prompts for destructive operations

Add interactive confirmations for destructive operations.

## Operations Needing Confirmation
- `gt swarm cancel` - Cancels active swarm
- `gt swarm land --force` - Force landing
- `gt polecat decommission` - Removes polecat
- `gt rig remove` - Removes rig
- `gt stop --all` - Stops all sessions
- `gt mail purge` - Permanently deletes mail

## Implementation Options

### Option 1: promptui library
```go
import "github.com/manifoldco/promptui"

prompt := promptui.Prompt{
    Label:     "Delete polecat Toast",
    IsConfirm: true,
}
result, err := prompt.Run()
```

### Option 2: Simple stdin
```go
func confirm(prompt string) bool {
    fmt.Printf("%s [y/N]: ", prompt)
    var response string
    fmt.Scanln(&response)
    return strings.ToLower(response) == "y"
}
```

## Bypass Flags
All confirmations skippable with --force or --yes:
```go
if !force && !confirm("Really cancel swarm?") {
    return nil
}
```

## Acceptance Criteria
- [ ] Destructive ops prompt by default
- [ ] --force or --yes bypasses
- [ ] Clear prompt text explaining action
- [ ] Non-interactive mode (piped input) auto-fails


Document how to configure a Gas Town Harness

Create docs explaining what a harness is (private repo containing GT installation with rigs gitignored), why you'd want one, and how to set it up with beads redirects


gt crew add: Create crew workspace

Implement 'gt crew add <name> [--rig <rig>]' command:
- Clone repo into <rig>/crew/<name>/
- Create feature branch (optional, or stay on main)
- Register for mail delivery
- Initialize CLAUDE.md with crew worker prompting
- Do NOT register with witness (user-managed)


Witness Patrol Molecule

Create mol-witness-patrol molecule for witness heartbeat loop.

Similar to DeaconPatrolMolecule but for per-rig witness duties.

## Steps
1. inbox-check - Process witness mail
2. survey-workers - List polecats, check status
3. inspect-workers - Capture pane output, assess state
4. plugin-run - Execute plugins from <rig>/plugins/witness/
5. decide-actions - Determine nudges, escalations
6. execute-actions - Send nudges, process shutdowns
7. context-check - Check own context, handoff if needed
8. loop-or-exit - Continue or cycle

The plugin-run step enables user customization of the patrol loop.


Test: release command verification


Merge: gt-92l

branch: polecat/Ace
target: main
source_issue: gt-92l
rig: gastown


Merge: gt-h5n.5

branch: polecat/Scabrous
target: main
source_issue: gt-h5n.5
rig: gastown


Merge: gt-h5n.5


GGT Command Parity: Complete gt command coverage

Complete gt command set to match/exceed PGT town commands.

Covers: uninstall, rig info, refinery attach, witness, session mgmt, mail UX, daemon.


Digest: mol-deacon-patrol

Test patrol cycle - verifying wisp flow


gt polecat: add 'done' or 'finish' command to transition from working to idle

When a polecat finishes work but session wasn't properly cleaned up, there's no way to reset it from 'working' state back to 'idle'.

Tried:
```
gt polecat sleep gastown/Angharad
Error: sleeping polecat: polecat is not active (state: working)
```

The sleep command only works on 'active' polecats, not 'working' ones.

Had to manually edit state.json to reset:
```
jq '.state = "idle" | .issue = ""' state.json
```

Need a command like:
```
gt polecat done gastown/Angharad   # working -> idle
gt polecat finish gastown/Angharad # working -> idle
gt polecat reset gastown/Angharad  # any state -> idle (force)
```


test message


mol-crew-session: Startup/shutdown protocols for crew workers

Crew workers (like joe, max) don't have patrol molecules keeping them fresh. When gt gets rebuilt, they have stale binaries that cause hangs and bugs.

## Problem

- Crew binaries get stale when gt is rebuilt elsewhere
- No automatic pull/rebase/rebuild on session start
- No standardized shutdown protocol (sync, push, handoff)

## Solution: mol-crew-session

A molecule template for crew sessions:

### Startup Phase
1. `git pull --rebase` - get latest code
2. `bd sync` - sync beads
3. `go build -o gt ./cmd/gt` - rebuild gt (if in gastown)
4. `gt prime` - load context

### Work Phase
- Open-ended human interaction
- No molecule steps - just work until done

### Shutdown Phase
1. `git status` - check for uncommitted changes
2. `bd sync` - sync beads
3. `git push` - push code
4. Handoff if incomplete work

## Implementation

1. Define mol-crew-session in builtin_molecules.go
2. Update crew CLAUDE.md to reference the protocol
3. Optionally: gt prime auto-runs startup steps

## Dependencies

- Should implement after deacon/witness/polecat patrols are stable
- Consider: gt-3x0z.10 (Witness patrol molecules)

## Related

- gt-3x0z.9: Deacon wisp patrol (done)
- fix-gt script: Current workaround for binary freshness


Merge: gt-0ei3

branch: polecat/capable
target: main
source_issue: gt-0ei3
rig: gastown


TIDY UP: Your previous work (patrol runner) was already m...

TIDY UP: Your previous work (patrol runner) was already merged to main. Check your git status is clean, sync beads, and if nothing to do, just run 'gt done'.


gt mq retry: retry a failed MR

Implement 'gt mq retry <id>' to retry a failed merge request.

Actions:
1. Verify MR exists and is in failed state (open with failure labels)
2. Remove failure labels (needs-rebase, needs-fix)
3. Reset to ready state
4. Optionally re-run immediately (--now flag)

Options:
- --now: immediately process (instead of waiting for Engineer loop)

Reference: docs/merge-queue-design.md#cli-commands


Witness MVP: Automated Polecat Lifecycle

Implement the Witness agent - per-rig 'pit boss' that manages polecat lifecycles.

The Witness enables hands-free swarming by automating:
- Spawning polecats for ready work
- Monitoring worker health
- Processing shutdown requests
- Cleaning up worktrees when done
- Escalating stuck workers to Mayor

Without Witness, humans must manually spawn, monitor, and kill each polecat.

## Core Loop

```
while True:
  # Handle pending shutdowns
  for polecat in polecats where state == pending_shutdown:
    verify git clean
    kill session
    remove worktree
    delete branch

  # Spawn for ready work
  ready = bd ready --parent=<epic> if epic else bd ready
  for issue in ready:
    if active_workers < max_workers:
      gt spawn --issue <id>

  # Check worker health
  for polecat in active polecats:
    if stuck (no progress for 30 min):
      nudge or escalate

  sleep 60
```

## Blocking Bugs to Fix
- gt-dsfi: handoff deadlock
- gt-n7z7: refinery foreground race condition
- gm-c6b: mail coordination (town vs rig beads)


Human escalation: notify overseer when self-heal fails

Lightweight escalation extracted from Deacon epic (gt-5af).

**Implementation**: Config in town.json or similar:
```yaml
escalation:
  contact: steve@example.com  # or slack webhook
  triggers:
    - daemon_cant_restart
    - session_missing_5min
```

**Trigger points**:
- Go daemon can't restart a session after N attempts
- Agent detects it's stuck and can't recover
- Witness can't reach polecat

**Mechanism**:
- Simple: `gt mail send --human` already exists
- Enhanced: email/slack via external script

**Weight**: Small config + one code path in daemon
**Value**: High for unattended operation - human gets notified instead of silent failure


Auto-target: MRs for epic children target integration branch

Automatically target integration branches for epic children.

When 'gt mq submit' is called:
1. Parse source issue from branch
2. Check if issue has a parent epic
3. Check if integration/<epic> branch exists
4. If yes: set target=integration/<epic>
5. If no: set target=main

This ensures batch work automatically flows to integration branches.

Also update 'gt mq submit --epic' to explicitly target an epic's integration branch.

Reference: docs/merge-queue-design.md#integration-branches


gt rig info: Show detailed rig information

Add 'gt rig info <rig>' command to show detailed rig status.

Should show:
- Rig path and git URL
- Active polecats with status
- Refinery status
- Witness status
- Recent activity
- Beads summary (open issues count)


town handoff command (optional)

CLI commands for session handoff workflow (optional convenience).

## Commands

### gt handoff
Generate handoff interactively.
```
gt handoff [--send]
```
- Collects current state (status, inbox, beads)
- Prompts for additional notes
- --send: Mail to self and exit

### gt resume
Check for and display pending handoff.
```
gt resume
```
- Checks inbox for handoff message
- Displays formatted handoff if found
- Suggests next actions

## Implementation

These are convenience wrappers. The same workflow can be done manually:
```bash
# Manual handoff
town status > /tmp/handoff
town inbox >> /tmp/handoff
bd ready >> /tmp/handoff
# Edit and send
town mail send mayor/ -s "Session Handoff" -f /tmp/handoff
```

## Priority

P2 - Optional. Manual workflow works fine. Nice to have for UX.

## Notes

Part of session cycling workflow designed in gt-u82.


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

This proto enables nondeterministic idempotence for polecat work.
A polecat that crashes after any step can restart, read its molecule state,
and continue from the last completed step. No work is lost.

Variables:
- gt-test - The source issue ID being worked on


Test Epic: GGT MVP Validation


Speed up test suite

Tests are running slow during MQ processing. Investigate and optimize:
- Profile test execution time
- Look for slow tests (network, file I/O, sleeps)
- Consider parallel test execution
- Cache expensive setup where possible


Merge: gt-a95

branch: polecat/Ace
target: main
source_issue: gt-a95
rig: gastown


Merge: gt-3x1

branch: polecat/Slit
target: main
source_issue: gt-3x1
rig: gastown


Phase 2: Quiescent agents (Witness, Refinery)

Enable Witness and Refinery to sleep until triggered.

## Scope
- Wake triggers: gt spawn, MR submit, mail, Deacon ping
- Wake SLA: <1 minute
- mol-witness-patrol and mol-refinery-patrol definitions
- Quiescent entry/exit protocol

## Implementation
- Kill tmux session on quiescent entry
- Preserve sandbox (worktree, state files)
- Restart session on wake trigger
- Agent checks pinned, spawns default patrol if naked

Depends: Phase 1 complete


Activity feed from wisp state: gt patrol status

Enable mayor and gt tool to quickly see what patrol agents are doing.

## Problem

The mayor and gt tool cannot quickly see what the deacon (or other patrol agents) are doing.
Need a way to extract an activity feed from the current wisp state.

## Desired Commands

- gt patrol status: Show current patrol state (step, timing, cycle count)
- gt patrol history: Show recent patrol cycles (from digests)
- gt patrol feed: Live tail of patrol activity

## Data Sources

- .beads-wisp/issues.jsonl: Current wisp with step progress
- .beads/issues.jsonl: Digests from squashed patrols
- heartbeat.json: Last activity timestamp

## Use Cases

1. Mayor checking deacon: Is the deacon doing anything?
2. Debugging hangs: What step is it stuck on?
3. Operator monitoring: Dashboard of patrol health
4. Summaries for handoffs: Auto-generate patrol digest

## Related

- gt-id36: Deacon Kernel
- gt-3x0z: Wisp Molecule Integration


gt mail send should tmux-notify recipient

## Problem

When mail is sent via gt mail send, the recipient session does not get a tmux notification. In Python Gas Town (PGT), mail delivery triggers a tmux display-message or similar notification so the agent knows mail arrived.

## Expected Behavior

When gt mail send <addr> is called:
1. Mail is delivered to recipient inbox
2. If recipient has an active tmux session, send notification
3. Notification should be visible (display-message or bell)

## Current Behavior

Mail is delivered but no notification. Agent has to poll inbox to discover new mail.

## Impact

- Agents miss time-sensitive messages
- Heartbeat pokes from daemon will not wake agents
- Coordination is slower (polling vs push)

## Implementation Notes

After successful mail delivery, check if recipient has active session:
- gt session list can identify active sessions
- tmux display-message or send-keys can notify
- Could inject a visible prompt like "[MAIL] New message from <sender>"

## Reference

Check PGT implementation for how it handles this.


loop-or-exit

Decision: burn and loop if context low, exit for respawn if context high.


context-check

Assess own context usage. If high, prepare for handoff.


Merge: gt-70b3

type: merge-request
branch: polecat/Rictus
target: main
source_issue: gt-70b3
rig: gastown


Default polecat names: Mad Max theme instead of AdjectiveNoun

Current default naming for new polecats uses AdjectiveNoun convention.
Since rigs already provide namespacing, we can use more thematic names.

Suggestion: Use Mad Max / Fury Road character and vehicle names as defaults.
Examples: Furiosa, Nux, Slit, Morsov, Toast, Rictus, Warboy, etc.

Could also include:
- War Rig parts: Guzzler, Tanker, Pursuit
- Citadel roles: Imperator, Blackthumb, Organic
- Wasteland terms: Chrome, Witness, Shiny

Implementation:
- Add name generator in internal/polecat/ or similar
- Use when --create flag is used without explicit name
- Cycle through pool to avoid duplicates within a rig


Town Doctor molecule for harness health checks

Create a Town Doctor molecule that any Gas Town agent can run to diagnose and repair harness issues.

## Concept

Instead of just `gt doctor` as a CLI command with hardcoded checks, create a **molecule** (checklist workflow) that:
- Any agent (Mayor, Witness, Polecat) can instantiate
- Walks the agent through diagnostic steps
- Agent uses judgment to fix issues found
- Works as a structured troubleshooting guide

## Why a Molecule?

1. **Agent-driven**: The agent running it becomes "the doctor" temporarily
2. **Extensible**: Add new checks by updating the molecule, not code
3. **Contextual**: Agent can reason about issues, not just run scripts
4. **Self-healing**: Agent can fix problems it finds, not just report them

## Proposed Checks (molecule steps)

1. Verify harness structure (mayor/, .beads/, CLAUDE.md exist)
2. Validate config files (town.json, rigs.json parse correctly)
3. Check beads health (bd doctor, redirect validity)
4. Verify git state (clean working tree, proper remotes)
5. Check rig integrity (each registered rig exists, has config.json)
6. Validate agent clones (mayor/rig/, refinery/rig/ exist and are valid)
7. Check for orphaned worktrees/branches
8. Verify daemon state (if running)

## Integration

- `gt doctor` could instantiate the molecule for the current agent
- Or agent can run `bd ready` and pick up doctor tasks when prioritized
- Results logged to beads for audit trail

## Related

- gt-cr9: Harness Design & Documentation (completed)
- Molecules design in architecture.md


HTTP work client: CloudRun dispatch client

## Overview

HTTP client for dispatching work to Cloud Run and streaming results back.

## Implementation

```go
type WorkClient struct {
    serviceURL string
    httpClient *http.Client  // HTTP/2 enabled
}

func NewWorkClient(serviceURL string) *WorkClient {
    return &WorkClient{
        serviceURL: serviceURL,
        httpClient: &http.Client{
            Transport: &http2.Transport{},
            Timeout:   0,  // No timeout for streaming
        },
    }
}

func (c *WorkClient) DispatchWork(ctx context.Context, req WorkRequest) (<-chan WorkEvent, error) {
    // 1. POST to /work
    // 2. Return channel that streams WorkEvents
    // 3. Close channel when done/error
}
```

## Streaming Reader

```go
func (c *WorkClient) streamEvents(body io.Reader, events chan<- WorkEvent) {
    defer close(events)
    decoder := json.NewDecoder(body)
    for {
        var event WorkEvent
        if err := decoder.Decode(&event); err != nil {
            return
        }
        events <- event
    }
}
```

## Files

- `internal/cloudrun/client.go`

## Dependencies

Depends on: gt-9a2.7 (protocol types)
Used by: gt-9a2.8 (CloudRunOutpost)


load-context

Run gt prime and bd prime. Verify issue assignment.
Check inbox for any relevant messages.

Read the assigned issue (gt-test) and understand the requirements.
Identify any blockers or missing information.


Swarm package: Swarm, SwarmTask, SwarmState types

Define core swarm types.

## Types (in `internal/swarm/`)

```go
// SwarmState represents swarm lifecycle
type SwarmState string
const (
    SwarmCreated   SwarmState = "created"
    SwarmActive    SwarmState = "active"
    SwarmMerging   SwarmState = "merging"
    SwarmLanded    SwarmState = "landed"
    SwarmFailed    SwarmState = "failed"
    SwarmCancelled SwarmState = "cancelled"
)

// Swarm references a beads epic that tracks swarm work
type Swarm struct {
    ID          string      // matches beads epic ID
    RigName     string
    EpicID      string      // beads epic tracking this swarm
    BaseCommit  string      // git SHA all workers branch from
    Integration string      // integration branch name
    State       SwarmState
    CreatedAt   time.Time
    Workers     []string    // polecat names assigned
}

// SwarmTask represents a single task in the swarm (maps to beads issue)
type SwarmTask struct {
    IssueID   string  // beads issue ID
    Assignee  string  // polecat name
    Branch    string  // worker branch name
    State     string  // mirrors beads status
}
```

## Note

Swarm state is primarily stored IN beads. These types are in-memory representations for the SwarmManager to work with. No separate manifest.json files.


Create DEACON.md role context

Create ~/gt/DEACON.md with the Deacon's role context, wake cycle instructions, and command reference. Model after existing CLAUDE.md for Mayor.


CloudRun worker container: Dockerfile and entrypoint

## Overview

Docker container image for Cloud Run workers.

## Dockerfile

```dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o gt ./cmd/gt

FROM ubuntu:22.04

# Install Claude Code
RUN apt-get update && apt-get install -y     curl git nodejs npm     && npm install -g @anthropic-ai/claude-code     && apt-get clean

# Install gt
COPY --from=builder /app/gt /usr/local/bin/gt

# Worker entrypoint
COPY deploy/cloudrun/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

EXPOSE 8080
ENTRYPOINT ["/entrypoint.sh"]
```

## Entrypoint

```bash
#!/bin/bash
git config --global user.name "$GIT_USER"
git config --global user.email "$GIT_EMAIL"
exec gt worker serve --port 8080
```

## Files

- `deploy/cloudrun/Dockerfile`
- `deploy/cloudrun/entrypoint.sh`
- `deploy/cloudrun/README.md`

## Dependencies

Depends on: gt-9a2.11 (HTTP server - gt worker serve)


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

This proto enables nondeterministic idempotence for polecat work.
A polecat that crashes after any step can restart, read its molecule state,
and continue from the last completed step. No work is lost.

Variables:
- {{issue}} - The source issue ID being worked on


gt nudge should accept partial/fuzzy session names

Currently gt nudge requires the exact tmux session name (e.g., gt-gastown-crew-max). Should be more forgiving:

1. Accept partial matches when unambiguous (e.g., 'max' → gt-gastown-crew-max)
2. Accept shorthand like 'gastown/max' or 'crew/max'
3. Show helpful error with suggestions when ambiguous

Examples that should work:
- gt nudge max '...' → matches gt-gastown-crew-max
- gt nudge gastown/max '...' → matches gt-gastown-crew-max
- gt nudge beads-dave '...' → matches gt-beads-crew-dave


gt crew at: auto-prime when exec'ing Claude in-session

When running 'gt crew at <name>' from inside the target session, we exec Claude directly. But this means we can't send 'gt prime' afterward since we ARE the process.

Possible solutions:
1. Claude startup hook that runs gt prime
2. Pass prompt as argument to claude CLI
3. Wrapper script approach

Related: crew resume prompt also can't be sent in this path.


Update architecture.md: Engineer role and Beads merge queue

Update docs/architecture.md with recent design decisions:

1. Agent table: Change "Refinery" role to "Engineer"
   - Refinery = place/module/directory
   - Engineer = role (agent that works in the Refinery)

2. Merge Queue section: Document Beads-native model
   - MRs are beads issues with --type=merge-request
   - gt mq commands (submit, list, next, process, reorder)
   - Ordering via depends-on links

3. CLI section: Add gt mq commands

4. Key Design Decisions: Add decisions for:
   - #15: Merge Queue in Beads
   - #16: Engineer role (distinct from Refinery place)
   - #17: Session restart protocol for Engineer


Tmux status line: rig color themes and worker identity display

## Summary

Customize tmux status line for Gas Town workers with:
1. Per-rig configurable color themes
2. Clear worker name and role visibility

## Current Problem

- Only mayor shows in status line (and truncated)
- Can't tell which rig/worker you're looking at
- All sessions look the same

## Proposed Design

### Per-rig colors
```yaml
# In rig config or beads
theme:
  primary: '#ff6600'    # Orange for gastown
  secondary: '#333333'
  accent: '#ffcc00'
```

### Status line format
```
[gastown/Rictus] polecat | gt-70b3 | branch: polecat/Rictus
[beads/emma] crew | working | branch: main
[mayor] coordinator | idle
```

### Components
- Rig name with rig color
- Worker name
- Role (polecat/crew/mayor/witness/refinery)
- Current issue or status
- Branch name

## Configuration

Could use pinned beads for this (see gm-w13, beads-6v2):
- `bd show <rig>-theme` returns theme config
- Stored as pinned bead, always available
- Part of 'config in beads data plane' initiative

Implementation complete. Core features: per-rig color themes, dynamic status line with issue/mail indicators, gt theme/issue commands. Ready for testing.


Pinned Beads: Ongoing concerns and anchors

Pinned beads represent persistent concerns that do not close traditionally. Stay out of bd ready. Examples: Monitor production, Weekly syncs. Implementation: pinned: true field on bead.


CLI: doctor diagnostics and auto-repair

GGT completely lacks the doctor command which is critical for debugging.

Required Commands:
- gt doctor [<rig>] - Run diagnostic checks
- gt doctor --fix - Auto-repair common issues

Checks to Implement:
Workspace Level: Config validity, Mayor mailbox, Rig registry
Rig Level: Git state, clone health, witness/refinery presence, beads sync
Swarm Level: Stuck detection, zombie sessions, heartbeat health

PGT Reference: gastown-py/src/gastown/cli/dashboard_cmd.py


Phase 3: Callbacks and plugins

Mail-based callback protocol and plugin surface.

## Callbacks
- Polecat → Witness: shutdown requests
- Witness → Deacon: escalations, status
- Crew → Deacon: recycle requests
- Deacon → Mayor: escalations

## Plugins
- .beads/plugins.yaml registry
- Cooldown tracking
- Plugin runner in deacon patrol

Depends: Phase 2


Test MR

test


Phase 1.2: Daemon attachment detection

Daemon polls Deacon's pinned bead to detect naked state.

## Implementation
- Daemon knows Deacon's pinned bead ID
- Every heartbeat cycle: bd show <pinned> --json
- Parse attached_molecule field
- If null/empty: Deacon is naked

## Actions on Naked
- Spawn mol-deacon-patrol
- Attach to Deacon's pinned
- Nudge Deacon to start

## Failsafes
- Keepalive file monitoring
- Stale detection (>10min no progress)
- Force nudge on stale

Depends: gt-rana.1


Tmux wrapper: session operations

Wrapper for tmux session operations via subprocess.

## Interface

```go
type Tmux struct{}

func NewTmux() *Tmux

// Session lifecycle
func (t *Tmux) NewSession(name, workDir string) error
func (t *Tmux) KillSession(name string) error
func (t *Tmux) HasSession(name string) (bool, error)
func (t *Tmux) ListSessions() ([]string, error)

// Session interaction
func (t *Tmux) SendKeys(session, keys string) error
func (t *Tmux) CapturePane(session string, lines int) (string, error)
func (t *Tmux) AttachSession(session string) error

// Window operations (if needed)
func (t *Tmux) SelectWindow(session string, index int) error
```

## Session Naming

Convention: `gt-<rig>-<polecat>` (e.g., `gt-wyvern-Toast`)

## Implementation

- Shell out to tmux binary
- CapturePane uses `tmux capture-pane -p -t <session> -S -<lines>`
- SendKeys uses `tmux send-keys -t <session> '<keys>' Enter`

## Error Handling

- "no server running": tmux not started (not an error for HasSession)
- "session not found": session doesn't exist
- Wrap all tmux errors with context

## Environment

Requires TMUX_TMPDIR or uses default socket. Don't assume tmux is running.


Plugin: merge-oracle (merge queue analysis)

Example plugin that analyzes changesets before Refinery processes them. Builds overlap graph, classifies disjointness (parallel-safe vs needs-sequencing), uses LLM for semantic complexity, identifies high-risk patterns. Based on merge-orchestration proposal. See docs/architecture.md.


Polecats should not push branches to remote

## Current Behavior

Polecats push their branches to origin (e.g., `polecat/furiosa`), which pollutes the remote with many short-lived branches.

## Desired Behavior

Polecats should only commit locally. The Refinery handles all remote pushes:
1. Polecat works on local `polecat/<name>` branch
2. Polecat signals done (state → idle)
3. Refinery pulls from local polecat branch
4. Refinery runs tests, merges to main
5. Refinery pushes main to remote
6. If PR review needed, Refinery creates the PR

## Benefits

- Clean remote (no branch pollution)
- Clear responsibility (Refinery is the quality gate)
- Simpler cleanup (local branches deleted with worktree)
- Less noise in GitHub UI

## Trade-offs

- If polecat crashes before Refinery merges, code is lost locally
- But beads issue remains open, another polecat can redo the work
- This is acceptable for ephemeral workers

## Implementation

In polecat CLAUDE.md or landing protocol:
- Remove `git push origin HEAD` from workflow
- Replace with just `git commit` + signal done
- Refinery handles the rest


Test: Alpha to Beta

Sibling communication test


gt mq list: show queue with status/priority/age

Implement 'gt mq list' command to display the merge queue.

Output format:
ID          STATUS       PRIORITY  BRANCH                    WORKER  AGE
gt-mr-001   ready        P0        polecat/Nux/gt-xyz        Nux     5m
gt-mr-002   in_progress  P1        polecat/Toast/gt-abc      Toast   12m
gt-mr-003   blocked      P1        polecat/Capable/gt-def    Capable 8m
            (waiting on gt-mr-001)

Options:
- --ready: show only ready-to-merge (no blockers, not in progress)
- --status STATUS: filter by status
- --worker WORKER: filter by worker
- --epic EPIC: show MRs targeting integration/EPIC

Under the hood: bd list --type=merge-request with filters.

Reference: docs/merge-queue-design.md#gt-mq-list


Swarm: report generation

Generate markdown reports for completed swarms.

## Command
```
gt swarm report <swarm-id> [--save <file>]
```

## Report Content

### Header
- Swarm ID and title
- Created/completed timestamps
- Duration
- Rig name

### Task Summary
| Task | Assignee | Status | Duration |
|------|----------|--------|----------|
| gt-xxx | Toast | merged | 15m |
| gt-yyy | Nux | merged | 22m |

### Worker Contributions
- Commits per worker
- Issues closed per worker
- Lines changed (optional)

### Timeline
- Chronological events from events.jsonl
- Key milestones (started, first merge, landing)

### Issues Encountered
- Conflicts resolved
- Failed tasks (if any)
- Escalations

## Implementation
```go
func GenerateReport(swarmID string) (*SwarmReport, error)
func (r *SwarmReport) ToMarkdown() string
```

## Storage
- Save to <rig>/.gastown/swarms/<id>/report.md
- Or user-specified path with --save

## PGT Reference
gastown-py/src/gastown/swarm/manager.py generate_report()

## Acceptance Criteria
- [ ] Markdown report generated
- [ ] Includes all sections above
- [ ] Auto-saved to swarm directory
- [ ] --save allows custom path


Test Task 2: Add comment to version.go


Work on gt-fix-bugs: Fix blocking infrastructure bugs. Se...

Work on gt-fix-bugs: Fix blocking infrastructure bugs. See issue for details. Run 'bd show gt-fix-bugs' to see the full issue.


Deacon marching orders: pinned bead with rounds molecule

Create a pinned bead that defines the Deacon's rounds molecule - its "kernel".

## Concept

Like `gt prime` gives agents their context, a pinned bead gives the Deacon
its operating instructions. This bead defines:

1. The rounds molecule (steps to execute each wake)
2. Registered plugins (scheduled, event-triggered)
3. Configuration (timeouts, thresholds, escalation rules)

## Pinned Bead Structure

```yaml
# gt-deacon-kernel (pinned)
title: "Deacon Kernel Configuration"
type: policy
pinned: true

molecule: mol-deacon-rounds
  steps:
    - session-check: "Check context budget, cycle if needed"
    - health-scan: "Check Mayor, Witnesses, Refineries, Crew"
    - lifecycle: "Process pending lifecycle requests"
    - plugins: "Run due scheduled plugins"
    - events: "Process timer callbacks, event subscriptions"
    - complete: "Update heartbeat, return to wait"

plugins:
  scheduled:
    - name: beads-hygiene
      schedule: "0 2 * * *"  # 2 AM daily
    - name: branch-cleanup
      schedule: "0 4 * * 0"  # 4 AM Sundays

  event_triggers:
    - event: "issue.created"
      plugin: work-oracle
    - event: "mr.submitted"
      plugin: review-oracle

config:
  session_cycle_threshold_turns: 50
  session_cycle_threshold_hours: 4
  health_scan_timeout_seconds: 60
  plugin_timeout_minutes: 30
  escalation_after_failures: 3
```

## Reading Marching Orders

On wake, Deacon:
1. `bd show --pinned` to find the kernel bead
2. Parse molecule steps
3. Execute in order

## Updating the Kernel

To change Deacon behavior:
1. `bd update gt-deacon-kernel` with new config
2. Next wake cycle picks up changes
3. No code changes required

## Bootstrap

If no pinned bead exists, Deacon uses hardcoded defaults from DEACON.md.
First installation creates the pinned bead.


Batch work landing report generation

Generate reports on batch work completion.

## Trigger

When all children of an epic are closed, generate a completion report.

## Report Contents

- Epic metadata (ID, title, created by, duration)
- Task summary (completed counts, timing)
- Per-task details (issue, assignee, time taken)
- Git stats (commits merged, lines changed)
- Cleanup stats (branches deleted)

## Output Locations

1. Mail to Mayor - summary report
2. Optional: save to file with --save flag

## Command

```bash
gt report --epic <epic-id> [--save report.md]
```

## Format

Markdown with sections:
- Summary
- Tasks
- Workers
- Timeline

## Note

This replaces the swarm-based reporting (gt-662). Reports are generated from epic/issue data, not from separate swarm state files.

## Reference

PGT: swarm/report.py (for format ideas, ignore swarm ID patterns)


Work on gt-o9j: Fix tmux status bar polecat count - exclu...

Work on gt-o9j: Fix tmux status bar polecat count - exclude static roles (mayor, deacon, witnesses, refineries, docs, hop). Run 'bd show gt-o9j' for details.


Polecat cleanup should refuse to lose uncommitted work

The system should stubbornly refuse to lose work from a polecat.

## Current Problem

- gt spawn --force bypasses safety checks
- gt shutdown doesn't check for uncommitted work
- Witness cleanup doesn't check git status

## Desired Behavior

Before any polecat cleanup, check:
1. git status - any uncommitted changes?
2. git stash list - any stashes?
3. Unpushed commits on branch?
4. Unsynced beads changes?

If ANY of these exist:
- REFUSE to clean up
- Print clear error message listing what would be lost
- Require explicit --nuclear flag to force (not just --force)

## Implementation

Add to cleanupPolecat() in witness/manager.go:
```go
func (m *Manager) checkUncommittedWork(polecatName string) error {
    dir := m.polecatDir(polecatName)

    // Check git status
    if hasUncommitted, _ := git.HasUncommittedChanges(dir); hasUncommitted {
        return fmt.Errorf("polecat %s has uncommitted changes", polecatName)
    }

    // Check stashes
    if stashCount, _ := git.StashCount(dir); stashCount > 0 {
        return fmt.Errorf("polecat %s has %d stashes", polecatName, stashCount)
    }

    // Check unpushed commits
    if unpushed, _ := git.UnpushedCommits(dir); unpushed > 0 {
        return fmt.Errorf("polecat %s has %d unpushed commits", polecatName, unpushed)
    }

    return nil
}
```

## Affected Commands

- gt shutdown
- gt rig shutdown
- Witness cleanup
- gt spawn --force (should warn if overwriting)


bd ready --type: missing type filter for MQ integration

bd ready lacks --type flag that engineer.go expects.

## Code (internal/refinery/engineer.go)
readyMRs, err := e.beads.ReadyWithType("merge-request")

## Actual bd ready
No --type flag - only supports assignee, label, priority filters.

## Impact
Refinery can't find merge-requests in queue, so MQ doesn't process anything.

## Fix Options
1. Add --type flag to bd ready
2. Use bd list --type=merge-request --status=open instead
3. Both (ready filters for unblocked, list for all)

This is blocking the entire MQ pipeline.


gt mail inbox doesn't find crew worker mail - identity mismatch

## Problem

Crew workers don't see their handoff messages when running `gt mail inbox` from their working directory.

## Root Cause

gt derives identity from cwd path, but crew workers have a different path structure:
- **cwd**: `/Users/stevey/gt/beads/crew/dave`
- **gt derives**: `beads/crew/dave` (wrong)
- **should be**: `beads/dave` (crew workers use `rig/name` format)

Messages sent to `beads/dave` don't show up because gt is looking for `beads/crew/dave`.

## Workaround

Use explicit identity flag:
```bash
gt mail inbox --identity "beads/dave"
```

## Fix

Identity detection in gt should handle crew/ subdirectory:
- Path `<rig>/crew/<name>` should derive identity as `<rig>/<name>`
- This matches how polecats work: `<rig>/polecats/<name>` → `<rig>/<name>`

## Affected

All crew workers in all rigs.


CLI: witness commands (start, stop, status)

Witness daemon CLI commands.

## Commands

### gt witness start
Start the witness daemon for a rig.
```
gt witness start <rig> [--interval <seconds>]
```
- Starts background daemon process
- Default heartbeat interval: 30s
- Logs to <rig>/witness/witness.log

### gt witness stop
Stop the witness daemon.
```
gt witness stop <rig>
```
- Graceful shutdown
- Completes current heartbeat cycle

### gt witness status
Show witness status.
```
gt witness status <rig> [--json]
```
Output:
- Running/stopped
- Last heartbeat time
- Polecats being monitored
- Recent nudges/escalations

### gt witness logs
View witness logs.
```
gt witness logs <rig> [--follow] [--lines <n>]
```
- --follow: Continuous output (like tail -f)
- --lines: Number of lines (default 50)

## Daemon Management

Witness runs as background process:
- PID stored in <rig>/witness/witness.pid
- Uses nohup for persistence
- Logs structured JSON events

## Implementation

```go
var witnessCmd = &cobra.Command{Use: "witness"}
witnessCmd.AddCommand(startCmd, stopCmd, statusCmd, logsCmd)
```

Start launches daemon via exec, status reads PID file and pings process.


gt nudge should accept flexible session identifiers

Currently `gt nudge` requires the exact tmux session name (e.g., `gt-gastown-furiosa`).

It should also accept:
- `gastown/furiosa` (rig/polecat format)
- `furiosa` (polecat name, infer rig from cwd or require if ambiguous)

The session list command shows `gastown/furiosa` format, but nudge rejects it:
```
gt session list → shows 'gastown/furiosa'
gt nudge gastown/furiosa 'msg' → 'session not found'
gt nudge gt-gastown-furiosa 'msg' → works
```

Should normalize all these formats to the tmux session name internally.


Configuration in Beads: use pinned beads for rig/agent config

## Summary

Move configuration from JSON files into Beads data plane using pinned beads.

## Motivation

- Config becomes versionable and syncable like issues
- Agents can read config via `bd show`
- Unified data model for everything
- Supports the 'Beads as Universal Data Plane' vision (gt-aqm)

## Config Types to Migrate

### Rig-level (pinned per rig)
- Theme/colors for tmux status line
- Default branch naming conventions
- Merge queue settings
- Witness thresholds

### Agent-level (pinned per role)
- Handoffs (already planned - gt-cu7r)
- Agent preferences
- Current focus/context

### Town-level (pinned at town root)
- Cross-rig settings
- Federation config
- Global themes

## Implementation

1. Implement StatusPinned (beads-6v2) ✓ in progress
2. Create config pinned beads on rig init
3. Add `bd config get/set` commands that read/write pinned beads
4. Migrate existing config.json fields

## Naming Convention

```
<prefix>-cfg-<scope>
gt-cfg-theme      # gastown theme
bd-cfg-merge      # beads merge settings
gm-cfg-town       # town-level config
```

## Dependencies

- beads-6v2: Add StatusPinned to beads schema
- gm-w13: Pinned Beads epic


Create rig .runtime/ for rig runtime state

Move ephemeral rig state to .runtime/:
- Create <rig>/.runtime/ directory
- Move .gastown/witness.json → .runtime/witness.json
- Move .gastown/refinery.json → .runtime/refinery.json
- Move .gastown/namepool.json (state portion) → .runtime/namepool-state.json
- Update .gitignore to ignore .runtime/
- Update all code references


Add harness overview to Mayor priming

Update gt prime Mayor context to explain the harness concept: umbrella repo for GT installation, rigs underneath, Mayor sits above all rigs


Test

Body


Session cycling UX: smooth transitions via TUI wrapper

## Problem

Current CLI agent session cycling is painful:
- Shell → CC starts → priming → context loads → ready → work → exit/crash → repeat
- Each cycle is 30-60 seconds of cold boot
- No continuity between shell and agent's inner state
- Raw "session not running, starting..." loop is the baseline

## GGT Advantages (already have)

- Beads: Work state survives session death completely
- Mail: Handoff notes from past-self to future-self
- Prime commands: Structured context reload

## Gap: Transition Mechanics

Ideas to explore when actively using CLI:

1. **In-band cycling** - `/restart` or `/cycle` command, agent handles own restart without dropping to shell

2. **Hot standby** - TUI maintains pre-warmed session in background, switch to already-primed agent

3. **Persistent wrapper** - Bubbletea TUI stays running across session cycles, CC sessions come/go inside it

4. **Session pooling** - Keep 2-3 primed sessions ready, never wait for cold start

## Deferred

Deliberately P4 until we're actively using the simpler CLI and feel the pain firsthand.


Worker prompting: Beads write access

Add beads write access section to polecat AGENTS.md.template.

## Beads Access Section for Prompting

```markdown
## Beads Access

You have **full beads access** - create, update, and close issues.

### Quick Reference

```bash
# View work
bd ready                    # Issues ready (no blockers)
bd list                     # All open issues
bd show <id>                # Issue details

# Create issues
bd create --title="Fix bug" --type=bug --priority=2
bd create --title="Add feature" --type=feature

# Update issues
bd update <id> --status=in_progress    # Claim work
bd close <id>                          # Mark complete

# Sync (required before merge!)
bd sync                     # Commit beads changes to git
```

### When to Create Issues

Create beads issues when you discover work that:
- Is outside your current task scope
- Would benefit from tracking
- Should be done by someone else

**Good examples**:
```bash
bd create --title="Race condition in auth" --type=bug --priority=1
bd create --title="Document API rate limits" --type=task --priority=3
```

**Don't create for**:
- Tiny fixes you can do in 2 minutes
- Vague "improvements" with no scope
- Work already tracked elsewhere

### Beads Sync Protocol

**CRITICAL**: Always sync beads before merging!

```bash
bd sync                    # Commits beads changes
git add .beads/
git commit -m "beads: sync"
```

If you forget to sync, beads changes are lost when session ends.
```

## Implementation

Add to AGENTS.md.template polecat section.


gt rig reset: clear stale mail on reset/land

## Problem

When resetting or landing a rig/town, stale mail messages can confuse agents on startup. Old handoff messages, daemon notifications, and inter-agent mail should be cleaned up as part of reset.

## Current State

- `gt rig reset` exists but doesn't clear mail
- Stale messages accumulate (e.g., daemon SHUTDOWN messages)
- Agents may read outdated context on startup

## Proposed Behavior

`gt rig reset` and `gt town reset` should:
1. Close all open messages (`--type=message`) in the relevant beads
2. Optionally preserve pinned handoff beads (clear content, keep bead)
3. Log what was cleaned up

```bash
gt rig reset gastown          # Clears gastown mail
gt rig reset gastown --mail   # Only clear mail, keep other state
gt town reset                 # Clears all town-level mail
gt town reset --all           # Clears mail in all rigs too
```

## Implementation

1. Query `bd list --type=message --status=open`
2. Close each with reason 'Cleared during reset'
3. For pinned handoffs: `bd update <id> --description=''` instead of close


gt prime: Refinery context detection and output

Update gt prime to detect Refinery role:
- Detect from directory: refinery/rig/ = Refinery
- Show handoff bead reference
- Show merge queue status
- Show polecat branches with unmerged commits
- Show last actions summary


MQ metrics: pending count, processing time, success rate

Implement merge queue metrics collection.

Metrics to track:
- mq_pending_count: MRs waiting
- mq_processing_time: Time from submit to merge (histogram)
- mq_success_rate: Merges vs rejections
- mq_conflict_rate: How often conflicts occur
- mq_test_failure_rate: Test failures

Storage options:
- Simple: JSON file with rolling stats
- Advanced: Prometheus-compatible metrics endpoint

Display via:
- gt mq stats: summary statistics
- Dashboard widget (separate task)

Reference: docs/merge-queue-design.md#observability


Update templates for Propulsion Principle

Overhaul agent prompts to embody the Universal Gas Town Propulsion Principle:

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

Templates to update:
- [ ] deacon.md.tmpl - Check hook first, no decision logic
- [ ] polecat.md.tmpl - Propulsion startup, follow molecule
- [ ] witness.md.tmpl - Sling wisps when spawning agents
- [ ] refinery.md.tmpl - Accept slung epics

Key changes:
1. Remove 'should I run this?' decision points
2. Add 'check your hook' as step 1 of startup
3. Make molecule-following the default mode
4. Simplify - agents don't think, they execute


Refinery startup: Use Claude agent instead of foreground mode

WIP found in stash: Refactor refinery startup to spawn Claude as the refinery agent rather than using gt refinery start --foreground.

Changes needed:
- Use refineryDir (refinery/rig) as working directory
- Start Claude with --dangerously-skip-permissions
- Wait for shell ready, then Claude ready
- Send gt prime, then refinery startup prompt
- Remove foreground mode complexity

Related: gt-n7z7 (refinery --foreground race condition bug)


Refinery Engineer: Role prompting and CLAUDE.md

Create refinery/CLAUDE.md with Chief Merge Engineer role context. Include:
- Role identity and responsibilities
- Decision authority (merge order, test frequency, binary rebuilds)
- Communication patterns (Witness, Deacon)
- Session lifecycle (handoff bead protocol)
- Key commands reference


Work on ga-p6r: Add handoff protocol to spawn priming. En...

Work on ga-p6r: Add handoff protocol to spawn priming. Ensure polecats receive handoff context when spawned. When done, submit MR (not PR) to integration branch for Refinery.


Polecat beads not synced with rig beads

When gt spawn assigns an issue to a polecat, the polecat cannot find the issue because:

1. Rig beads at /gt/gastown/.beads contains gt-th7
2. Polecat beads at /gt/gastown/polecats/dementus/.beads does NOT have gt-th7
3. bd sync in polecat dir pulls from beads-sync branch which doesn't have the new issue
4. Rig bd sync uses 'main' branch, causing a branch mismatch

The polecat gets a work assignment for an issue it literally cannot see.

## Root Cause

- Rig beads and polecat beads are separate git-tracked copies
- No mechanism to propagate newly created issues from rig to polecats before assignment
- Sync branch configuration mismatch between rig and polecats

## Fix Options

1. gt spawn should sync rig beads before assigning work
2. gt spawn should sync polecat beads after assignment
3. Use shared beads (symlink or same DB) instead of copies
4. Push new issues immediately on create

Note: This sync mismatch is resolved by gt-9nf (fresh polecats). Rather than fixing sync between stale clones, we'll always create fresh worktrees. This issue documents the root cause for posterity.


Patrols: Cyclic molecules for autonomous maintenance

## Vision

Patrols are **cyclic molecules** - workflow loops that give Gas Town its autonomous nervous system. While regular molecules are DAGs that terminate, patrols loop forever, performing maintenance tasks at varying cadences.

This is the "steam engine" of Gas Town: converting episodic Claude sessions into continuous autonomous operation.

## Core Concepts

### 1. Cyclic Molecules

Regular molecule:     A -> B -> C -> done
Patrol molecule:      A -> B -> C --+
                      ^             |
                      +-------------+

Patrols have a loop_to field specifying where to restart.

### 2. Cooldown-Aware Steps (Atoms)

Steps encode their own cadence. When patrol reaches a step:
1. Check: now - last_run > cooldown?
2. If yes: execute, update last_run
3. If no: skip (immediately close)

The patrol runner is simple - steps self-skip. Complexity distributed into atoms.

### 3. The Beacon

The heartbeat that fires patrol triggers:
- Internal ticker in Deacon (goroutine)
- Or external cron firing gt deacon tick
- Or mail-based triggers

Without beacon, nothing proactive happens.

### 4. Session Reset as Patrol Step

Connects to auto-handoff (gt-bcwn). Session reset is a patrol step, not a separate mechanism.

### 5. Multi-Role Patrols

Each supervisor has its own patrol:

**Deacon patrol:** health-check (30s), session-gc (5m), beacon-tick (10s)
**Witness patrol:** orphan-scan (10m), stuck-check (2m), molecule-progress (1m)
**Refinery patrol:** queue-check (30s), pr-status (1m), merge-ready (30s)

### 6. Cadence Tiers

- Critical (10-30s): Health checks
- Active (1-5m): Progress, nudges
- Maintenance (10-30m): Orphans, GC
- Periodic (1h+): Reports

### 7. Best-Effort Scheduling

Not real-time - more like cron. No hard deadlines. Catch-up, dont pile-up.
Priority preemption (mail interrupts patrol). Graceful degradation under load.

## Open Questions

1. State persistence: Beads (self-describing) or file (faster)?
2. Interruption: How does urgent mail preempt patrol?
3. Error recovery: Backoff? Escalate? Circuit breaker?
4. Coordination: Can patrols send mail to trigger other patrols?

## Related

- gt-bcwn: Auto-handoff (session reset is a patrol step)
- Molecule system (patrols extend molecules with loops)
- Deacon lifecycle management

## Metaphor

Claude was fire. Claude Code was steam. Gas Town is the steam engine. Beads is the train tracks.

The steam engine converts episodic combustion into continuous rotary motion.
Gas Town converts episodic Claude sessions into continuous autonomous work.


Fix blocking bugs (gt-dsfi, gt-n7z7, gm-c6b)

Fix bugs blocking Witness functionality:

1. gt-dsfi: handoff deadlock
   - Polecats hang when trying to exit
   - Blocks shutdown request handler

2. gt-n7z7: refinery foreground race condition
   - Sometimes detects parent as already running
   - Blocks reliable Refinery startup

3. gm-c6b: mail coordination
   - Cross-rig mail should use town-level database
   - Affects Witness <-> Mayor communication

These should be fixed early as they'll block integration testing.

Fixed gt-dsfi and gt-n7z7. Issue gm-c6b not found in database.


Per-epic config overrides: custom merge settings

Allow per-epic merge configuration overrides.

Epic can specify merge_config in its description:
  merge_config:
    run_tests: true
    test_command: 'go test -race ./...'
    on_conflict: assign_back

When processing MRs for an epic:
1. Load rig-level merge_queue config
2. Check if epic has merge_config
3. Merge epic config over rig config
4. Use merged config for processing

Use cases:
- Risky refactors: more thorough testing
- Urgent fixes: skip some checks
- Experimental work: different test suite

Reference: docs/merge-queue-design.md#per-epic-overrides