Standardize agent bead naming: prefix-rig-role-name

## The Problem

Agent bead IDs use INCONSISTENT naming patterns:

| Current (WRONG) | Should Be (prefix-rig-role-name) |
|-----------------|----------------------------------|
| gt-witness-gastown | gt-gastown-witness |
| gt-refinery-gastown | gt-gastown-refinery |
| gt-crew-gastown-max | gt-gastown-crew-max |
| gt-polecat-gastown-Toast | gt-gastown-polecat-Toast |

Town-level agents (no rig) are OK:
- gt-mayor ✓
- gt-deacon ✓

## The Convention

```
prefix-rig-role-name

Where:
- prefix: always 'gt'
- rig: rig name (absent for town-level agents)
- role: witness|refinery|crew|polecat|mayor|deacon
- name: agent name (absent for singleton roles like witness/refinery)
```

Examples:
- `gt-gastown-witness` (rig=gastown, role=witness, no name)
- `gt-gastown-crew-max` (rig=gastown, role=crew, name=max)
- `gt-beads-polecat-Toast` (rig=beads, role=polecat, name=Toast)
- `gt-mayor` (no rig, role=mayor, no name)

## Files to Update

### Agent bead ID generation
- internal/cmd/status.go (lines 316-335)
- internal/daemon/lifecycle.go (lines 546-579)
- internal/cmd/crew_add.go
- internal/polecat/manager.go
- internal/rig/manager.go
- internal/doctor/agent_beads_check.go
- internal/cmd/prime.go
- internal/session/names.go (session names vs bead IDs)

### Commands to verify
- gt status - displays agent beads
- gt doctor - creates missing agent beads
- gt rig add - creates witness/refinery beads
- gt crew add - creates crew beads
- gt sling - routes by agent ID
- gt mol status - looks up agent by ID

## Migration

1. Update all ID generation code
2. Create new agent beads with correct IDs
3. Migrate hook/role slots to new beads
4. Update any mail addresses
5. Delete old incorrectly-named beads

## Also from this session

Role bead slot cleanup was done - CreateAgentBead now calls bd slot set.
But legacy description parsing still exists in daemon/lifecycle.go.

## Reference
- ~/gt/docs/agent-as-bead.md
- Session 2025-12-29: Fixed role bead patterns (gt-crew-role etc)


Swarm: ephemeral rig support

PGT has ephemeral rigs for swarms - temporary worker groups that are destroyed after landing.

Missing Features:
- gt swarm init [--rig <name>|--git-url <url>] [--num-workers N]
- gt swarm worker add/remove/list <rig-id>
- gt swarm rigs - List ephemeral rigs
- gt swarm destroy <rig-id> - Destroy ephemeral rig

Directory structure:
<workspace>/mayor/workers/<rig-id>/
├── rig.json (metadata)
├── alice/ (git clone)
├── bob/
└── carol/

PGT Reference: gastown-py/src/gastown/ephemeral.py

Note: Beads issue gt-kmn.12 mentions this but implementation is missing.


Add --account flag to gt spawn and gt crew attach

Add --account=<handle> flag. Precedence: GT_ACCOUNT env > --account flag > default from config.


Swarm remaining gt-8tmz P3/P4 issues

## Swarm Plan for Molecule Algebra Completion

Encapsulates the remaining swarmable work from gt-8tmz (Molecule Algebra epic).

### Swarmable Issues (6 total)

**Batch 1 - Parallel (3 polecats):**
- gt-8tmz.10: Rename Engineer in Box to Shiny (simple rename)
- gt-8tmz.36: Validate expanded step IDs are unique (validation)
- gt-8tmz.31: Formula validation specification (docs)

**Batch 2 - Sequential (1 polecat):**
- gt-8tmz.34: Expansion var overrides → gt-8tmz.35: Inline step expansion
  (dependency chain - .35 depends on .34)

**Batch 3 - Solo (1 polecat):**
- gt-8tmz.30: Proto debugging and inspection tools (add --graph)

### Hold for Human (7 issues - need design decisions)
- gt-8tmz.19: Meta-formulas (schema design)
- gt-8tmz.20: Org inheritance (policy structure)
- gt-8tmz.21: Conditional aspects (when clause syntax)
- gt-8tmz.22: Review dimensions as aspects (refactor)
- gt-8tmz.28: Error handling policy
- gt-8tmz.29: Versioning strategy
- gt-8tmz.37: Nested expansion recursion

### Code Location
All work is in beads repo: /Users/stevey/gt/beads/crew/emma
- internal/formula/*.go
- cmd/bd/cook.go

### Execution
Hand to Witness for polecat dispatch, or execute manually with polecats.


implement

Implement the solution for gt-1wmw. 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


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)


Move polecat pending tracking from Deacon to Witness

Problem: gt deacon pending handles polecat observation at the wrong level. Hierarchy should be Witness→polecats, Deacon→Witnesses.

Solution:
1. Add gt witness pending - shows pending polecats in this rig
2. Route POLECAT_STARTED mail to Witness (not just Deacon)
3. Deacon keeps backup role but does not directly manage polecats

Depends on gt-0yqqw (messaging infrastructure) for proper routing.


Molecule converge: iterate until AI says done

Work isn't 'done' until AI is confident it's done. Fixes the 85% problem.

**From VC**: internal/iterative/converge.go - 3-7 iterations with AI convergence detection. ~600 lines.
Target: 20%+ more issues discovered. Observed: ~25% average improvement.

**Gas Town implementation**: Molecule converge config:
```yaml
converge:
  strategy: ai
  min_iterations: 3
  max_iterations: 7
  confidence: 0.85
```

Polecat iterates, AI checks convergence. Stop when AI is confident or max reached.

**Value**: Raw agents get to ~85% and stop. Iteration catches the remaining 15%.

**VC metrics**: Convergence rate >70%, mean 4-5 iterations for complex work.


gt mq integration land: merge integration branch to main

Implement 'gt mq integration land <epic>' command.

Actions:
1. Verify all MRs targeting integration/<epic> are merged
2. Verify integration branch exists
3. Merge integration/<epic> to main (--no-ff)
4. Run tests on main
5. Push to origin
6. Delete integration branch
7. Update epic status

Options:
- --force: land even if some MRs still open
- --skip-tests: skip test run
- --dry-run: preview only

This creates a single merge commit for the entire epic's work.

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


Witness Patrol

Per-rig worker monitor patrol loop with progressive nudging.


Digest: mol-deacon-patrol

Patrol #13: Stable


mol-polecat-arm: Add nudge_text variable definition

The mol-polecat-arm formula references `{{nudge_text}}` in the execute step but doesn't define it in the variables section.

## Current variables section

```yaml
variables:
  - name: polecat_name
    required: true
  - name: rig
    required: true
```

## Missing

```yaml
  - name: nudge_text
    required: false
    default: "How's progress? Need any help?"
    description: Text to send when nudging the polecat
```

## Usage in formula

```bash
tmux send-keys -t gt-{{rig}}-{{polecat_name}} "{{nudge_text}}" Enter
```

## Fix

Add nudge_text to the variables section with a sensible default.


Phase verbs: pour and wisp commands

Implement the phase transition verbs:
- bd pour <proto> - instantiate as persistent mol
- bd wisp <proto> - instantiate as ephemeral wisp
- Update bd mol bond to inherit phase from target

These replace the current --wisp flag with cleaner verb semantics.


Digest: mol-deacon-patrol

Patrol complete: cleaned 2 orphaned processes, 3 stale locks, all agents healthy


Merge: valkyrie-1767074338488

attached_args: Code review

branch: polecat/valkyrie-1767074338488
target: main
source_issue: valkyrie-1767074338488
rig: gastown

CODE REVIEW (furiosa): REJECT

Issue: Commit modifies CLAUDE.md which is gitignored on main.

Findings:
1. CLAUDE.md is in .gitignore (clone-specific file)
2. CLAUDE.md is NOT tracked on main branch
3. Polecat manager has installCLAUDETemplate() to generate this file locally per worktree
4. The commit adds a file that should not be committed

Recommendation: Do not merge. CLAUDE.md should be locally generated, not committed.

This merge request has no valid changes to merge.


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


End of patrol cycle decision.

End of patrol cycle decision.

If queue non-empty AND context LOW:
- Burn this wisp, start fresh patrol
- Return to inbox-check

If queue empty OR context HIGH:
- Burn wisp with summary digest
- Exit (daemon will respawn if needed)

instantiated_from: mol-refinery-patrol
step: burn-or-loop


Merge polecat/slit: docs bd mol bond/squash/burn CLI

Branch: polecat/slit

## Summary
Added comprehensive CLI reference documentation for the three molecule lifecycle commands to molecules.md:

- **bd mol bond**: Instantiate proto into Mol (durable) or Wisp (ephemeral)
- **bd mol squash**: Complete molecule and generate digest
- **bd mol burn**: Abandon molecule without digest

Includes argument tables, behavior descriptions, examples, and a lifecycle diagram showing the steam engine metaphor mapping.

Closes: gt-odvf


Digest: mol-deacon-patrol

Patrol 5: stable


Digest: mol-deacon-patrol

Patrol 18: All clear


Swarm learning: Session cleanup missing from swarm workflow

## Problem

After Enders Game swarm completed (18 issues merged), 16 polecat sessions were left running but idle. No automated cleanup occurred.

## What Should Happen

1. Witness detects polecat completed work (idle at prompt)
2. Witness verifies git state is clean
3. Witness shuts down session
4. Witness reports completion to Mayor

## GGT Components

- gt-cxx: Witness context cycling (covers self-cycling)
- gt-u1j.9: Witness daemon heartbeat loop
- gt-kmn.6: Witness swarm landing protocol

## Recommendation

Add to Witness responsibilities:
- Monitor for 'work complete' signals (DONE keyword, idle detection)
- Automated session shutdown after verification
- Swarm completion reporting to Mayor

See also: architecture.md 'Worker Cleanup (Witness-Owned)' section which describes this but it wasn't implemented in PGT.


Digest: mol-deacon-patrol

Patrol 11: all clear


Daemon: configurable heartbeat interval

Heartbeat interval is hardcoded to 60s. Should be configurable via:
- town.json config
- Command line flag
- Environment variable

Default 60s is reasonable but some deployments may want faster/slower.


Crew workers: design documentation and remaining work

## Summary

Crew workers are user-managed persistent workspaces within a rig, distinct from polecats.

## Current Implementation

### Commands (all working)
- `gt crew add <name>` - Create workspace (git clone)
- `gt crew list` - List workspaces with status
- `gt crew at <name>` - Attach to tmux session
- `gt crew remove <name>` - Remove workspace
- `gt crew pristine [<name>]` - git pull + bd sync
- `gt crew refresh <name>` - Context cycle with handoff mail
- `gt crew status [<name>]` - Detailed status
- `gt crew rename <name>` - Rename workspace

### Crew vs Polecat

| Aspect | Crew | Polecat |
|--------|------|---------|
| Lifecycle | User-managed | Witness-managed |
| Scheduling | Manual | `gt spawn` |
| Merge flow | Direct push OK | Integration branch → refinery |
| Garbage collection | Never | Auto on completion |
| Identity | Long-lived (emma, dave) | Ephemeral (Nux, Toast) |

## Known Bugs

- **gt-70b3**: detectSender() doesn't recognize crew workers
- **gt-vdp0**: Crew CLAUDE.md shows Refinery template

## Potential Enhancements

1. Rebase helper in `gt crew pristine` for conflict resolution
2. Cross-rig crew support (crew worker in multiple rigs?)
3. Better mail identity auto-detection for crew


tmux link-window auto-selects new window, causing agent confusion

## Summary

When running `gt crew at <other>` from inside a tmux session, the linked window auto-selects, causing the user to unknowingly switch agents.

## Root Cause

`internal/tmux/tmux.go:535-538` - `LinkWindow` doesn't use `-d` flag:
```go
_, err := t.run("link-window", "-s", source)  // Missing -d!
```

By default, `tmux link-window` selects the newly linked window.

## Reproduction

1. Be in Max's tmux session talking to Max
2. Ask Max to run `gt crew at joe`
3. Max creates Joe's session and links it
4. User is now in Joe's window without realizing it
5. Max appears to have 'disappeared'

## Fix

Add `-d` flag to prevent auto-selection:
```go
_, err := t.run("link-window", "-s", source, "-d")
```

## Related

- gt-09i4: Unify tmux session lifecycle (broader epic Max filed)


Refinery Role Definition

You are the Refinery - merge queue processor for your rig. You process
completed polecat work, merging it to main one branch at a time with
sequential rebasing.

Your mission: Process the merge queue sequentially, rebasing each branch
atop the current baseline before merging.

default_molecule: mol-refinery-patrol
capabilities:
  - merge_queue_processing
  - sequential_rebase
  - conflict_resolution
  - verification_gates

## The Engineer Mindset

You are Scotty in the engine room. The merge queue is your warp core.

The Beads Promise: Work is never lost. If you discover ANY problem:
1. Fix it now (preferred if quick), OR
2. File a bead and proceed (tracked for cleanup crew)

There is NO third option. Never "disavow" by noting something exists and moving on.

The Scotty Test: Before proceeding past any failure, ask yourself:
"Would Scotty walk past a warp core leak because it existed before his shift?"

## Propulsion Principle

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

Your work is defined by the mol-refinery-patrol molecule. Execute steps:
- bd ready (find next step)
- bd show <step-id> (see what to do)
- bd close <step-id> (mark complete)

## Sequential Rebase Protocol

WRONG (parallel merge - causes conflicts):
  main -> branch-A (old main) + branch-B (old main) = CONFLICTS

RIGHT (sequential rebase):
  main -> merge A (rebased on main) -> merge B (rebased on main+A)

After every merge, main moves. Next branch MUST rebase on new baseline.

## Verification Gate

The handle-failures step is a verification gate:
- Tests PASSED: Gate satisfied, proceed to merge
- Tests FAILED (branch caused): Abort, notify polecat, skip branch
- Tests FAILED (pre-existing): MUST fix OR file bead - cannot proceed without

## Commands

### Patrol
- gt mol status - Check attached patrol
- bd ready / bd show / bd close - Step management
- bd mol spawn <mol> --wisp - Spawn patrol wisp

### Git Operations
- git fetch origin - Fetch all remote branches
- git branch -r | grep polecat - List polecat branches
- git rebase origin/main - Rebase on current main
- git push origin main - Push merged changes

### Communication
- gt mail inbox - Check for messages
- gt mail send <addr> -s "Subject" -m "Message" - Notify workers


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.


gt mq list: doesn't show submitted MRs

After submitting MRs with gt mq submit, gt mq list gastown shows empty queue.

## Reproduction
1. gt mq submit --issue gt-h5n.5 --branch polecat/Scabrous
2. gt mq list gastown → (empty)
3. bd list --type=merge-request → shows the MR

## Expected
gt mq list should show submitted MRs

## MR example
gt-ts4u has rig: gastown in description, type=merge-request, status=open


orphan-check

Find abandoned work. Check for in_progress issues with no active agent.


Centralize session name construction patterns

Session name patterns like fmt.Sprintf("gt-%s-<role>", rigName) scattered across files:
- witness.go:287
- refinery.go:383
- start.go:275
- crew_helpers.go:68-70

Also: sessionToAgentID logic duplicated in sling.go:365-391 and handoff.go:374-402.

Suggestion: Create session_names.go with WitnessSessionName(), RefinerySessionName(), CrewSessionName() functions plus AgentIdentity type with FromSessionName()/ToSessionName() methods.


Digest: mol-deacon-patrol

Patrol 18


Witness emits activity events

Witness emits events to activity stream for patrol activity:

Events to emit:
- patrol_started: When witness begins patrol cycle
- polecat_checked: When witness checks a polecat
- polecat_nudged: When witness nudges a stuck polecat
- escalation_sent: When witness escalates to Mayor/Deacon
- patrol_complete: When patrol cycle finishes

This replaces stats tracking in .runtime/witness.json


Digest: mol-witness-patrol

Patrol cycle 2: Processed 3 POLECAT_DONE (nux=ESCALATED, slit=DEFERRED, furiosa=COMPLETED). Wrong-rig issue escalated to Mayor. All 3 gastown polecat sessions stopped.


Digest: mol-deacon-patrol

Patrol 2: Quiet cycle, all healthy, orphan gt-mol-aux persists


Remove .gastown/ after migration complete

Final cleanup:
- Remove .gastown/ directories at town and rig levels
- Remove daemon/ and deacon/ directories (replaced by .runtime/)
- Update .gitignore to remove old patterns
- Verify all tests pass with new structure


Digest: mol-deacon-patrol

Patrol 3: Routine


Git safety audit module

Port git_audit.py safety checks to Go.

## Purpose

Before destroying polecat clones, verify no code is at risk.

## Checks

1. Uncommitted changes (staged and unstaged)
2. Unpushed commits
3. Git stashes
4. Local-only branches (not tracking remote)

## Beads-Only Classification

Some files are safe to discard:
- .beads/*
- .claude/settings.json

Changes only affecting these = "beads-only" = safe to destroy.

## Interface

```go
type GitAuditResult struct {
    Polecat              string
    Path                 string
    UncommittedFiles     []string
    UncommittedIsBeadsOnly bool
    UnpushedCommits      int
    Stashes              []StashInfo
    StashesAreBeadsOnly  bool
    LocalBranches        []string
    Error                error
}

func (r *GitAuditResult) HasCodeAtRisk() bool

func AuditPolecat(name string, path string) *GitAuditResult
func AuditPolecats(polecats []PolecatInfo) []*GitAuditResult
```

## Reference

PGT: swarm/git_audit.py


check-refinery

Ensure the refinery is alive and processing merge requests.

Needs: inbox-check


mol-deacon-patrol

[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
Deacon patrol molecule template. Label: template


Digest: mol-deacon-patrol

Patrol 11: Quick cycle, all quiet


Polecat Lifecycle Events: Refinery-Witness Coordination

## Problem

Polecat work completion is currently treated as a single event (MR submission), but the true completion is when the Refinery merges the work. This creates a lifecycle gap:

1. Polecat submits MR → considered "done" by Witness
2. But MR might fail to merge (conflicts, test failures)
3. No one notifies anyone when merge actually succeeds

## Solution: Two-Event Lifecycle

**Event 1: MR Submitted**
- `gt mq submit` notifies Witness
- Witness verifies submission was clean
- Polecat can go idle (but worktree retained)
- If submission had issues, Witness can help

**Event 2: MR Merged**
- Refinery sends `LIFECYCLE: work merged` to Witness
- Witness updates polecat state to `merged`
- Worktree now eligible for full cleanup/recycling

## Village Sibling Watch

For robustness, patrol roles check on their siblings:
- Refinery checks Witness via `gt peek`
- Witness checks Refinery via `gt peek`
- Creates defense in depth - if primary notification fails, someone catches it

## Recovery

If Refinery misses sending lifecycle notification:
- Witness polecat-scan can detect: polecat in mr_submitted but MR shows merged
- Deacon orphan-check can detect: merged MRs with stale polecats


Implement

Implement the solution for gt-8tmz.10. 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.


Digest: mol-deacon-patrol

Patrol 13: Quiet


Digest: mol-deacon-patrol

Patrol 10: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 5: All clear


Digest: mol-deacon-patrol

Patrol 10: All healthy, 1 in_progress issue (max working)


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, archived 17 routine handoffs, cleaned 1 orphan process and 1 stale lock


Digest: mol-deacon-patrol

Patrol 1: No mail, all agents healthy (mayor/witnesses/refineries OK), 0 polecats active, 2 orphaned mols for removed furiosa polecat noted


Auto-restart patrol agents after N loops

All patrol roles should auto-restart to keep context usage low. Role-specific heuristics:

**Deacon**:
- 20 patrol loops without major incident
- Immediate restart after ANY extraordinary action (lifecycle request, remediation, escalation)
- Rationale: Keep context short so there's headroom if something big comes up

**Witness**:
- Based on polecats processed (not loop count)
- Restart after processing N polecats (spawns, nudges, decommissions)
- Suggested N: 10-15 polecats

**Refinery**:
- Based on MRs processed (not loop count)
- Restart after processing N merge requests
- Suggested N: 5-10 MRs (merges are context-heavy)

Benefits:
- Keeps context fresh (better focus/performance)
- Reduces cost (quadratic increase vs conversation length)
- Preserves headroom for handling surprises
- Simple and predictable (no context estimation needed)

Each role tracks their metric in state file and hands off when threshold reached.


Digest: mol-deacon-patrol

P12: stable


Digest: mol-deacon-patrol

Patrol 16: routine


Digest: mol-deacon-patrol

Patrol 13: routine


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy


Check mail for MR submissions, escalations, messages.

```bash
gt mail inbox
# Process any urgent items
```

Handle shutdown requests, escalations, and status queries.

instantiated_from: mol-refinery-patrol
step: inbox-check


Simplify mail wisps: remove dual-routing, use ephemeral flag

## Context

gt-lg66 implemented dual-inbox architecture with separate .beads-wisp/ directory.
This was over-engineered. See bd-bkul for the simpler approach.

## Work

Once beads implements bd-bkul (ephemeral flag in single db):

1. Revert/simplify router.go:
   - Remove resolveWispDir()
   - Remove shouldBeEphemeral() auto-detection (beads handles this)
   - Send() just passes --ephemeral flag to bd create

2. Revert/simplify mailbox.go:
   - Remove wispDir field
   - Remove listFromDir/getFromDir dual-source logic
   - Remove closeInDir dual-source logic
   - Single query, beads returns both types with Source marked

3. Keep in mail.go:
   - --ephemeral flag (passed through to bd)
   - (ephemeral) display indicator

4. Keep in spawn.go:
   - Ephemeral: true on lifecycle messages

## Depends On

bd-bkul: Simplify wisp architecture in beads


Digest: mol-deacon-patrol

Patrol 3: all healthy, mayor running, witnesses running


mol-deacon-patrol

Mayor's daemon patrol loop.

The Deacon is the Mayor's background process that runs continuously, handling callbacks, monitoring rig health, and performing cleanup. Each patrol cycle runs these steps in sequence, then loops or exits.


Digest: mol-deacon-patrol @ 2025-12-24 19:44

Patrol 7: All healthy


Digest: mol-deacon-patrol

Patrol 3: All healthy, no issues


Digest: mol-deacon-patrol

Patrol 7: All clear


End-to-end integration test

Create and run end-to-end integration test.

## Test Scenario

1. Clean state: no polecats, fresh beads
2. Create test issue: simple documentation fix
3. Verify Deacon sees it: bd ready shows issue
4. Trigger Deacon: send heartbeat or wait
5. Verify spawn: gt polecats shows new polecat
6. Watch polecat work: tmux attach
7. Verify completion: issue closed, MR created

## Test Script

```bash
#!/bin/bash
# e2e-test.sh

# 1. Clean state
gt polecat remove --all
bd create "Test: update README typo" --type=task --priority=1

# 2. Verify ready
bd ready | grep "update README"

# 3. Wait for Deacon or trigger
# (manual for v0.1)

# 4. Watch
gt status
gt polecats gastown

# 5. Wait for completion
# (manual observation for v0.1)

# 6. Verify
bd list --status=closed | grep "update README"
```

## Success Criteria

- Issue created and visible in bd ready
- Polecat spawned and working
- Issue closed with commit reference
- No manual intervention (except observation)


Digest: mol-deacon-patrol

Patrol 5: All healthy


Wisp directory and format

Define and implement the .beads-wisp directory structure.

## Directory Structure

```
<clone>/.beads-wisp/
  hook-<agent>.wisp.yaml     # Slung work for this agent
  patrol-<id>.wisp.yaml      # Patrol cycle state (future)
```

## Wisp File Format

```yaml
type: slung-work | patrol-cycle
created_at: ISO timestamp
created_by: entity who created it

# For slung-work:
bead_id: gt-xxx
context: optional message

# For patrol-cycle (future):
formula: mol-deacon-patrol
current_step: inbox-check
step_states: {...}
```

## Key Properties

- NOT git tracked (.beads-wisp/ in .gitignore)
- Ephemeral - burned after use
- Local to each clone
- Fast writes (no sync needed)

## Implementation

- internal/wisp/dir.go - Directory creation/management
- internal/wisp/types.go - Wisp type definitions
- internal/wisp/io.go - Read/write operations


gt spawn: add --polecat flag for explicit worker selection

Currently gt spawn requires positional arg format:
```
gt spawn gastown/Angharad --issue gt-xyz
```

But I tried the more intuitive flag form:
```
gt spawn --issue gt-xyz --polecat Angharad
```

This failed with 'unknown flag: --polecat'.

The flag form is more discoverable and consistent with other commands. Add --polecat flag as alternative to positional arg.


Add witness plugin hook support

Implement plugin directories for witness patrol.

Structure:
  <rig>/plugins/witness/
  ├── pre-inspection/
  │   └── stale-branch-check/
  │       └── CLAUDE.md
  └── post-action/
      └── mq-health/
          └── CLAUDE.md

run-plugins step scans these directories and bonds mol-plugin-runner for each.


Digest: mol-deacon-patrol

Patrol 15: Mayor OK, 11 sessions


Phase 4.2: Witness/Refinery patrol molecules

Extend ephemeral patrol pattern to Witness and Refinery.

## Witness Patrol Cycle

mol-witness-patrol-cycle:
1. scan-polecats: Check each polecat status
2. detect-stalls: Find stuck/idle polecats
3. nudge-or-escalate: Take action on stalls
4. log-status: Record cycle results
→ Squash with summary

## Refinery Patrol Cycle

mol-refinery-patrol-cycle:
1. scan-queue: Check merge queue
2. process-ready: Merge ready MRs
3. handle-failures: Deal with conflicts/failures
4. log-status: Record cycle results
→ Squash with summary

## Quiescent Mode

When no work: just log 'no activity' summary.
Witness and Refinery can sleep between cycles until triggered.


Documentation overhaul: User Guide approach

## Problem

Current docs are:
1. **Grandiose** - Too much vision, belongs in ~/gt/docs (HOP), not here
2. **Verbose** - Need bullets/tables, not sections. Too many separate files.
3. **Bottom-up** - Written as we built. Users need top-down.

Gas Town is a simple agent orchestrator (4-10 → 20-30 agents). Not a manifesto.

## Target Structure

### 1. Features at a Glance
- Persistent agent identities with mail inboxes and "work hooks"
- Sling work to agents, pinned to their hook
- Universal Propulsion: If hook is pinned, RUN IT
- Hooks survive crash, shutdown, compaction, restart
- Self-sling for auto-restart workflows
- Pin individual beads or entire epics

### 2. Available Workflows
- tmux mode vs no-tmux (raw Claude Code)
- Full Gas Town vs partial (single roles)
- Modular and resilient - one role at a time

### 3. Cooking Formulas
- Molecules = chains of issues (railroad tracks)
- Formulas = step descriptions (atoms)
- Cook formulas → molecules → durable workflows
- Examples: release molecule, deacon patrol, polecat workflow, shiny

### 4. (Optional) MEOW Deep Dive
- Structured epics as chained work graphs
- Serial/parallel branches, gates, loops, algebra
- States of matter, polymorphic bond operators
- But users just need to cook formulas

## Deliverable

One README + maybe one or two supporting docs. Radically condensed.


Deacon: Hierarchical health-check orchestrator

Replace daemon heartbeats with Deacon - an AI agent that keeps Gas Town running.

## Core Concept

The Deacon is a **Claude agent** (not just a Go process) that:
- Lives at town root in gt-deacon session
- Has its own mailbox (deacon/ identity in town beads)
- Is poked by a minimal Go daemon every ~60s (if idle)
- Monitors Mayor and Witnesses proactively
- Handles lifecycle requests (restart/cycle) from Mayor, Witnesses, AND Crew

## Architecture

```
Minimal Go Daemon (just watches Deacon)
         |
         v
     Deacon (Claude agent)
         |
    +----+----+
    v         v
  Mayor    Witnesses --> Polecats (Witness-managed)
    |         |
    +----+----+
         |
      Crew (lifecycle only, not monitored)
```

## Deacon Responsibilities

**Proactive monitoring:**
- Mayor health (tmux session, keepalive freshness)
- Witness health (tmux sessions, keepalive freshness)

**Reactive lifecycle:**
- Process restart/cycle requests from Mayor, Witnesses, Crew
- Kill session, create new, prime, verify startup

**Escalation:**
- Mail human (configurable) if issues can't be resolved

## Key Files

- ~/gt/DEACON.md - Role context
- ~/gt/deacon/ - State directory
  - heartbeat.json - Written each wake cycle (daemon checks this)
  - state.json - Health tracking, last scan results
- ~/gt/.beads/ - Town beads with deacon/ mail identity

## Wake Cycle

1. Write heartbeat (prevents daemon from poking)
2. Check mail (lifecycle requests)
3. Quick health scan (Mayor, Witnesses)
4. Process lifecycle requests
5. Remediate unhealthy agents
6. Update state

## Session Patterns

- Deacon: gt-deacon
- Mayor: gt-mayor
- Witness: gt-<rig>-witness
- Crew: gt-<rig>-<name> (e.g., gt-gastown-max)

## Relation to Policy Beads

Future: Deacon behavior configurable via policy beads (gt-3zw).
Initial implementation uses sensible defaults.


Digest: mol-deacon-patrol @ 2025-12-24 19:27

Patrol 14


Digest: mol-deacon-patrol

Patrol 1: All healthy - Mayor OK, 2 witnesses, 2 refineries, 0 polecats, 8 sessions, no callbacks


gt-mayor

gt-mayor

role_type: mayor
rig: null
agent_state: stopped
hook_bead: null
role_bead: gt-mayor-role
cleanup_status: null


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.


Digest: mol-deacon-patrol

P4: stable


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


Digest: mol-deacon-patrol

Patrol 13: all quiet


Digest: mol-deacon-patrol

Patrol 17: All healthy


Digest: mol-deacon-patrol

Patrol cycle 2: all healthy, no action required


Digest: mol-deacon-patrol

Patrol 13: All healthy


Design molecule parameterization

Enable protos to accept parameters for customization.

## Use Cases

1. rig-spinup needs rig name: `gt sling rig-spinup --param rig=newproject`
2. agent-restart needs agent: `gt sling agent-restart --param agent=gastown/witness`
3. code-review needs scope: `gt sling code-review --param scope=src/auth/`

## Proposed Syntax

### In Proto

```markdown
## Step: create-rig-structure
mkdir -p ~/gt/${rig}/refinery ~/gt/${rig}/witness
```

### In Sling

```bash
gt sling rig-spinup mayor/ --param rig=newproject --wisp
```

### In Bonded Molecule

Interpolation happens at bond time. Step descriptions have concrete values.

## Implementation

1. Proto declares params in frontmatter: `params: [rig]`
2. gt sling validates required params provided
3. bd mol bond receives params, interpolates descriptions
4. Bonded molecule has concrete step text

## Edge Cases

- Missing required param → error
- Unused param → warning
- Param in step title → interpolate there too


Digest: mol-deacon-patrol

Patrol 18: Nominal


Test Patrol Parent

[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
Test parent for Christmas Ornament pattern


Digest: mol-deacon-patrol

Patrol 20: All healthy, handoff triggered


Digest: mol-deacon-patrol

Patrol cycle 6: All healthy


Digest: mol-deacon-patrol

Patrol #10: Stable


gt rig shutdown: Gracefully stop all rig agents

Add 'gt rig shutdown <rig>' command to gracefully stop all agents in a rig.

Should:
- Stop all polecat sessions
- Stop refinery
- Stop witness
- Optionally wait for graceful shutdown with timeout


Replace WaitForClaudeReady with gt peek for steady-state agent observation

## Problem

WaitForClaudeReady uses regex to detect Claude's prompt, which is a ZFC violation.

## Architectural Fix

**Bootstrap (ZFC violation acceptable):**
During cold town startup, no AI is available. Regex to get Deacon online is acceptable.

**Steady State (proper ZFC):**
Once any agent is running, AI should observe AI:
- Deacon starting polecats → Deacon uses gt peek
- Deacon restarting → Mayor watches via gt peek
- Mayor restarting → Deacon watches via gt peek

## Implementation

1. Keep WaitForClaudeReady for daemon bootstrap only
2. Update gt deacon trigger-pending to use gt peek
3. Document bootstrap vs steady-state distinction


Merge fix/spawn-beads-path branch to main

Branch has gt nudge command; main has notification deduplication. Both valuable.

Key insight: Only ~10 commits diverged each way in mayor/rig.
- Branch: 9509afa feat(nudge): Add gt nudge command (MISSING from main)
- Main: d2fccd5 slot-based notification deduplication (KEEP)

Merge plan:
1. git merge fix/spawn-beads-path --no-ff
2. Keep nudge.go from branch
3. Keep notification.go from main
4. Merge tmux.go (both NudgeSession AND SendKeysReplace)
5. go build && go test
6. Deploy to ~/.local/bin/gt


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

This molecule is bonded dynamically by mol-witness-patrol's survey-workers step.
Each polecat being monitored gets one arm that runs in parallel with other arms.

## Variables

| Variable | Required | Description |
|----------|----------|-------------|
| polecat_name | Yes | Name of the polecat to inspect |
| rig | Yes | Rig containing the polecat |

## Step: capture
Capture recent tmux output for toast.

```bash
tmux capture-pane -t gt-gastown-toast -p | tail -50
```

Record:
- Last activity timestamp (when was last tool call?)
- Visible errors or stack traces
- Completion indicators ("Done", "Finished", etc.)

## Step: assess
Categorize polecat state based on captured output.

States:
- **working**: Recent tool calls, active processing
- **idle**: At prompt, no recent activity
- **error**: Showing errors or stack traces
- **requesting_shutdown**: Sent LIFECYCLE/Shutdown mail
- **done**: Showing completion indicators

Calculate: minutes since last activity.
Needs: capture

## Step: load-history
Read nudge history for toast from patrol state.

```
nudge_count = state.nudges[toast].count
last_nudge_time = state.nudges[toast].timestamp
```

This data was loaded by the parent patrol's load-state step and passed
to the arm via the bonding context.
Needs: assess

## Step: decide
Apply the nudge matrix to determine action for toast.

| State | Idle Time | Nudge Count | Action |
|-------|-----------|-------------|--------|
| working | any | any | none |
| idle | <10min | any | none |
| idle | 10-15min | 0 | nudge-1 (gentle) |
| idle | 15-20min | 1 | nudge-2 (direct) |
| idle | 20+min | 2 | nudge-3 (final) |
| idle | any | 3 | escalate |
| error | any | any | assess-severity |
| requesting_shutdown | any | any | pre-kill-verify |
| done | any | any | pre-kill-verify |

Nudge text:
1. "How's progress? Need any help?"
2. "Please wrap up soon. What's blocking you?"
3. "Final check. Will escalate in 5 min if no response."

Record decision and rationale.
Needs: load-history

## Step: execute
Take the decided action for toast.

**nudge-N**:
```bash
tmux send-keys -t gt-gastown-toast "{{nudge_text}}" Enter
```

**pre-kill-verify**:
```bash
cd polecats/toast
git status                    # Must be clean
git log origin/main..HEAD     # Check for unpushed
bd show <assigned-issue>      # Verify closed/deferred
```
If clean: kill session, remove worktree, delete branch
If dirty: record failure, retry next cycle

**escalate**:
```bash
gt mail send mayor/ -s "Escalation: toast stuck" -m "..."
```

**none**: No action needed.

Record: action taken, result, updated nudge count.
Needs: decide

## Output

The arm completes with:
- action_taken: none | nudge-1 | nudge-2 | nudge-3 | killed | escalated
- result: success | failed | pending
- updated_state: New nudge count and timestamp for toast

This data feeds back to the parent patrol's aggregate step.
---
bonded_from: mol-polecat-arm
bonded_to: gt-5glf
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Hardcoded session ID prefixes and paths

Multiple hardcoded values throughout code:
- internal/mail/router.go: 'gt-mayor', 'gt-' session prefixes
- internal/lock/lock.go: '.runtime', 'agent.lock' paths
- Session ID generation uses string literals

Should move to:
- constants package for prefixes
- config for customizable paths

Low priority but improves maintainability.


Digest: mol-deacon-patrol


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.


Refactor gt swarm to use beads backing

Migrate gt swarm commands from .runtime/swarms.json to beads molecules.

Current gt swarm stores state in .runtime/swarms.json - violating discovery over tracking.
The refactored version should use bd swarm create/status to work with beads molecules.

Implementation:
- gt swarm create calls bd swarm create
- gt swarm status calls bd swarm status
- gt swarm list queries bd list --mol-type=swarm
- Remove .runtime/swarms.json dependency

CROSS-RIG DEPENDENCIES (must complete first in beads repo):
- bd-oxgi: mol_type schema field
- bd-fa1q: bd swarm create command
- bd-5x0j: bd swarm status command

Reference: ~/gt/docs/swarm-architecture.md


Daemon: Implement exponential backoff based on activity file

Modify daemon heartbeat logic to use exponential backoff when idle.

Read ~/gt/daemon/activity.json on each heartbeat.
Compute idle duration: time.Since(activity.Timestamp)
Adjust next ticker interval based on idle duration:

| Idle Duration | Next Heartbeat |
|---------------|----------------|
| 0-5 min       | 5 min (base)   |
| 5-15 min      | 10 min         |
| 15-45 min     | 30 min         |
| 45+ min       | 60 min (max)   |

Implementation:
1. Add activity file reading to daemon heartbeat
2. Replace fixed ticker with dynamic interval calculation
3. Reset to base interval when activity is fresh

No counter tracking needed - pure discovery from single timestamp.

CROSS-RIG DEPENDENCY: Also requires beads:bd-v8ku (assigned to beads/crew/dave)


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


Create mol-install-go-binary molecule

Create a single-step molecule for building and installing the gt binary.

## Molecule Definition
\`\`\`markdown
## Molecule: install-go-binary
Single step to rebuild and install the gt binary after code changes.

## Step: install
Build and install the gt binary locally.

Run from the rig directory:
\`\`\`
go build -o gt ./cmd/gt
go install ./cmd/gt
\`\`\`

Verify the installed binary is updated:
\`\`\`
which gt
gt --version  # if we have version command
\`\`\`
\`\`\`

## Implementation
1. Add to builtin_molecules.go
2. Update SeedBuiltinMolecules to include it
3. Run gt molecule seed

## Acceptance
- [ ] mol-install-go-binary exists in beads
- [ ] Can be instantiated standalone
- [ ] Can be included by other molecules


Add merge-request type to Beads schema

Define the merge-request bead type with fields:
- branch: source branch (e.g., polecat/Nux/gt-xxx)
- target_branch: destination (main or integration/xxx)
- source_issue: the work being merged (gt-xxx)
- worker: who did the work
- rig: which rig
- merge_commit: (filled on close) SHA of merge commit
- close_reason: (filled on close) success/failure details

This may require beads schema changes or just convention.


bd ready --blockers: prioritize issues that block other work

bd ready should prioritize issues that are blocking other work.

**From VC**: Blocker-first prioritization in GetReadyWork(). ~100 lines.
Algorithm: baseline-failure first, then discovered:blocker, then by priority.

**Gas Town implementation**: CLI flag or default behavior:
```bash
bd ready --blockers-first  # Or make this default
```

Checks dependency graph. Issues with many dependents surface first.

**Value**: Unblocks parallelism faster. Critical path gets cleared.

**VC lesson**: Without blocker priority, work can starve on discovered issues.


test pin fix


Check own context limit

Check own context limit.

The Deacon runs in a Claude session with finite context. Check if approaching the limit:

```bash
gt context --usage
```

If context is high (>80%), prepare for handoff:
- Summarize current state
- Note any pending work
- Write handoff to molecule state

This enables the Deacon to burn and respawn cleanly.


MessagingConfig: Fix error message inconsistency in validation

Negative value errors don't wrap ErrMissingField while empty-list errors do. Should be consistent - either all wrap a sentinel or none do.


Add gt rig rename command

Allow renaming a rig after creation. Similar to gt crew rename, this should:

- Update the directory name
- Update mayor/rigs.json entry
- Update the rig's config.json
- Handle running agents gracefully (require shutdown first or --force)

Use case: User creates a rig, later wants to change its name for better organization.


Digest: mol-deacon-patrol

Patrol 13: nominal


Bug: refinery --foreground detects parent session as already running

When gt refinery start gastown runs:
1. Creates tmux session gt-gastown-refinery
2. Sends 'gt refinery start gastown --foreground' into the session
3. The foreground command checks HasSession() - finds the session it's inside
4. Returns 'already running' error

The foreground mode check should either:
- Skip the tmux session check (only check PID)
- Use a different indicator that the daemon loop is running
- Pass a flag to indicate we're being called from the background starter

Workaround: Manually run 'gt refinery start gastown --foreground' from a fresh session.


Digest: mol-deacon-patrol

Patrol 18: routine


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)


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


load-context

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

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


Patrol formulas: Inconsistent variable placeholder syntax

The patrol formulas use inconsistent syntax for variable placeholders:

## Inconsistency

| Formula | Syntax | Examples |
|---------|--------|----------|
| mol-polecat-arm | `{{var}}` | `{{polecat_name}}`, `{{rig}}` |
| mol-witness-patrol | `<var>` | `<rig>`, `<handoff-bead-id>` |
| mol-refinery-patrol | `<var>` | `<polecat-branch>` |

## Expected

All formulas should use consistent syntax, probably `{{var}}` since that's what
the variables section defines.

## Fix

Update mol-witness-patrol and mol-refinery-patrol to use `{{var}}` syntax
where appropriate, or document that `<var>` is for human-filled placeholders
vs `{{var}}` for cook-time interpolation.


Overhaul autonomous-mode guidance with ledger/capability framing

Re-read all relevant docs in ~/gt/docs (especially hop/) and overhaul the autonomous-mode guidance in role templates with a stronger "why" framing.

Current state:
- Theory of Operation explains "system stalls if you wait"
- Steam engine metaphor (piston, gearbox, flywheel)
- Physics not politeness language

Enhancement direction (without revealing HOP explicitly):
1. Frame work as "contributing to a ledger of demonstrated capability"
2. Emphasize quality: "your work history is visible, every completion matters"
3. Add the redemption arc: "bad work can be overcome through consistent good work"
4. Strengthen the "proving the model" angle: "every autonomous completion is evidence this works at scale"
5. Consider adding "your CV grows with every completion" concept

Files to update:
- internal/templates/roles/*.md.tmpl (all role templates)
- internal/cmd/prime.go (AUTONOMOUS MODE output)
- Possibly ~/gt/docs/philosophy.md or similar

Constraints:
- Gas Town cannot explicitly reference HOP
- Concepts and motivation are fine, just not the name or confidential details
- Should feel like natural evolution, not grafted-on messaging

Read first:
- ~/gt/docs/hop/CONTEXT.md
- ~/gt/docs/hop/BUSINESS_OVERVIEW.md
- ~/gt/docs/philosophy.md (if exists)
- All role templates

Deliverable: Updated templates and prime.go with stronger ledger/capability framing.


Digest: mol-deacon-patrol

Patrol 10: all healthy


Merge: gt-3x1.4

branch: polecat/Nux
target: main
source_issue: gt-3x1.4
rig: gastown


Gate issue type and bd gate create

Add type=gate to beads schema. Implement bd gate create command with --await flag. Gates are special issues that represent wait conditions. Example: bd gate create --await timer:5m --title 'Wait for cooldown'


Digest: mol-deacon-patrol

Patrol 20: All healthy, 2 crew active


Merge: gt-lnji

branch: polecat/nux
target: main
source_issue: gt-lnji
rig: gastown


Merge: cheedo-1767074334708

attached_args: Code review

branch: polecat/cheedo-1767074334708
target: main
source_issue: cheedo-1767074334708
rig: gastown


Digest: mol-deacon-patrol

Patrol 11: routine


Demo recording

Record a terminal demo of the tracer bullet.

## Recording Tool

Use asciinema:
```bash
brew install asciinema
asciinema rec gastown-demo.cast
```

## Demo Script

1. Show gt status (the town)
2. Show bd ready (available work)
3. Show Deacon running (tmux session)
4. Trigger spawn (create issue, Deacon picks it up)
5. Show polecat working (tmux attach briefly)
6. Show completion (bd list, issue closed)
7. Show MR created (bd list --type=merge-request)

## Tips

- Practice run first
- Keep it under 3 minutes
- Add commentary (terminal echo or voiceover)
- Show the key moments clearly

## Output

- gastown-demo.cast (asciinema file)
- gastown-demo.gif (optional, for embedding)
- YouTube/Vimeo upload (optional)


Digest: mol-deacon-patrol

Patrol 13: Routine


Digest: mol-deacon-patrol

P15: stable


Digest: mol-deacon-patrol

Patrol 9: Routine


Digest: mol-deacon-patrol

Patrol 19: all healthy


ensure-refineries

Parallel container: Start all rig refineries.

## Execution
Children execute in parallel. Container completes when all children complete.

## Children
- ensure-gastown-refinery
- ensure-beads-refinery

## Verify
All child refinery steps pass verification.


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.


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.


Digest: mol-deacon-patrol

Patrol 5: Quick cycle, all quiet


Validate expanded step IDs are unique


gt sling: use mail queue for patrol roles (witness, refinery, deacon)

When slinging work to patrol agents, queue via mail instead of replacing hook.

**Rationale:**
Patrol agents run continuous loops. Replacing their hook with discrete work breaks patrol continuity - when the task completes, the patrol stops.

**New behavior for patrol roles (witness, refinery, deacon):**
1. Check if patrol is running (hook has patrol molecule attached)
2. If patrol running:
   - Don't touch hook (patrol stays pinned)
   - Send work assignment mail
   - Print 'Queued for next patrol cycle'
3. If patrol NOT running:
   - Start default patrol for that role (mol-witness-patrol, mol-refinery-patrol, mol-deacon-patrol)
   - Send work assignment mail
   - Print 'Started patrol and queued work'

**New flags:**
- --urgent: Interrupt current patrol cycle, process this work immediately
- --replace: Explicitly terminate patrol and pin discrete work (break-glass)

**No change for:**
- Polecat, Crew, Mayor (discrete task agents - current behavior)

**Dependencies:**
- Patrol templates must have 'check inbox' step (verify/add)
- Need to know default patrol molecule for each role


Test Patrol Parent

[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
Test parent for Christmas Ornament pattern


Digest: mol-deacon-patrol

Patrol 12: routine


Digest: mol-deacon-patrol

Patrol cycle 12: nominal


Review: Witness patrol template changes (gt-h1n5)

Polecat rictus implemented significant witness.md.tmpl changes: banners, wisp-based execution, handoff bead attachment, loop-or-exit, patrol summary. Review for correctness and consistency with deacon pattern.


Digest: mol-deacon-patrol

Patrol 20: final check, all healthy, handoff threshold


Use cmd.OutOrStdout instead of fmt.Print in refinery

refinery/manager.go and refinery/engineer.go use fmt.Print/Println directly for user output (30+ occurrences). This breaks testability and doesn't follow cobra best practices. Should use cmd.OutOrStdout() or pass an io.Writer.

Affected files:
- internal/refinery/manager.go (lines 222, 360-361, 369, 387-393, 519, 537, 672)
- internal/refinery/engineer.go (lines 190-211, 249, 294-297, 325-353, 362-366)


gt-gastown-polecat-slit

gt-gastown-polecat-slit

role_type: polecat
rig: gastown
agent_state: done
hook_bead: null
role_bead: gt-polecat-role
cleanup_status: has_stash


gt mail inbox: identity auto-detection fails for refinery

When running from ~/gt/gastown/refinery or ~/gt/gastown/refinery/rig, 'gt mail inbox' detects identity as 'mayor/' instead of 'gastown/refinery'.

Workaround: Use --identity flag explicitly:
  gt mail inbox --identity gastown/refinery

This breaks the refinery patrol because it can't see its MERGE_READY messages.

Expected: Running from gastown/refinery should auto-detect identity as gastown/refinery.

Related: The refinery has 9 unread MERGE_READY messages that aren't being processed because of this bug.


Remove all hardcoded gastown dependencies from gt codebase

The Go codebase should not have hardcoded dependencies on gastown (the rig name).

Found in prime.go outputDeaconPatrolContext() - FIXED in this session.

Other potential issues to audit:
- Check all patrol context functions (Witness, Refinery) for similar patterns
- Ensure rig-specific paths are derived from context, not hardcoded
- Test with a different rig name to verify

The principle: Gas Town should work with any rig name, not just gastown.


inspect-workers

Capture output for each working polecat.

```bash
gt peek <rig>/<polecat>
```

Needs: survey-workers


Digest: mol-deacon-patrol

Patrol 17: all healthy


bd pin command fails: invalid field for update: pinned

In beads v0.32.0, `bd pin <id>` fails with 'invalid field for update: pinned'. The pinned field exists in the schema but update logic doesn't handle it.

Repro:
```
bd create 'test issue'
bd pin <id>
# Error: invalid field for update: pinned
```

Expected: Issue should be pinned.

This blocks gt mail send --pinned from working.


Clean up ~/gt root directory cruft

The town root has accumulated various directories and files that need review:

**To evaluate:**
- daemon/ - old daemon code? move or delete?
- deacon/ - WIP deacon work? consolidate with gastown?
- mayor/ - old mayor structure?
- AGENTS.md - is this still used?
- gt binary at root - should be gitignored

**Already correct:**
- .beads/, .claude/, .gastown/, .runtime/ - runtime dirs
- beads/, gastown/ - rig directories
- docs/hop/ - strategic docs
- CLAUDE.md - mayor context

Clean up, consolidate, update .gitignore as needed.


Digest: mol-deacon-patrol

Patrol 6: Nominal


Refinery: Add lifecycle-notify step to patrol

After successful merge in handleSuccess(), send lifecycle notification to Witness.

## Implementation

1. Add new mail type: `LIFECYCLE: work merged`
2. In engineer.go handleSuccess(), after closing MR and source issue:
   ```
   gt mail send <rig>/witness -s "LIFECYCLE: work merged" -m "
   Worker: <polecat>
   MR: <mr-id>
   Issue: <source-issue>
   Commit: <merge-commit>
   Action: Polecat work merged. Worktree eligible for recycling.
   "
   ```

3. Update mol-refinery-patrol to include lifecycle-notify step between merge-push and loop-check

## Acceptance
- Successful merges send mail to Witness
- Mail includes worker name, MR id, source issue, commit SHA


Digest: mol-deacon-patrol

Patrol 6: all quiet


Day 1.7: Define per-rig agent bead ID pattern

Document and implement the agent bead ID pattern for per-rig agents.

Pattern: gt-<role>-<rig>
Examples:
- gt-witness-gastown
- gt-refinery-gastown
- gt-refinery-beads
- gt-polecat-gastown-nux

Town-level agents (no rig):
- gt-mayor
- gt-deacon

This pattern enables:
- Consistent lookup: bd show gt-witness-gastown
- Routing: routes.jsonl maps prefixes
- Filtering: bd list --type=agent --rig=gastown

Update:
- agent-as-bead.md with examples
- bd create --type=agent to validate pattern


Extract interfaces for Git and Tmux to enable testing

Git and Tmux packages use concrete types that make testing difficult:

internal/git/git.go:
- Git struct with 40+ methods
- No interface - tests must use real git
- Many packages directly depend on concrete type

internal/tmux/tmux.go:
- Tmux struct with 30+ methods
- No interface - tests must use real tmux
- Contains Claude-specific detection logic mixed in

Suggestion:
1. Extract GitOperations interface with common operations
2. Extract TmuxRunner interface for subprocess operations
3. Allow mock injection for unit tests
4. Move Claude-specific tmux logic to internal/claude/


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


Meta-formulas: formula generators

Support meta-formulas that generate multiple formulas from a template. Example: multi-lang-shiny that generates shiny-go, shiny-python, shiny-typescript from a for-each loop over languages. Enables DRY formula libraries.


Day 2.3: Agent writes state on lifecycle events

Agents update their bead state using bd agent state command:
- On startup: bd agent state gt-<role> running
- On shutdown: bd agent state gt-<role> stopped
- On stuck: bd agent state gt-<role> stuck

State is self-reported, not inferred.

Implementation: Wire up agent lifecycle hooks (SessionStart, SessionEnd, health checks) to call bd agent state.

Parent: gt-d0jqp


Test Patrol Parent

[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
Test parent for Christmas Ornament pattern


Test gate for verification


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


Digest: mol-deacon-patrol

Patrol 14: All healthy, no messages


Digest: mol-deacon-patrol

Cycle 10: quiet


gt prime should detect mayor role from any rig's mayor/ folder

Currently gt prime only detects the Mayor role when run from town root (~/gt). It should also detect Mayor when run from:
- ~/gt/gastown/mayor/rig (rig's internal mayor dir)
- Any path containing /mayor/ under a rig

This would allow the mayor session to work correctly regardless of which rig directory it's attached to.


Day 3.3: Witness sends MERGE_READY to refinery

When polecat completes work:
1. Witness detects completion (hook_bead closed, state=stopped)
2. Witness sends mail to refinery: MERGE_READY
3. Mail includes branch name and work bead ID

Parent: gt-hwka3


gt sling: nudge crew/mayor if session is running

When slinging to crew or mayor, if they have an active tmux session, send a nudge notification so they know work has landed on their hook.

Currently only slingToPolecat nudges (lines 514-521 in internal/cmd/sling.go).

Missing nudge in:
- slingToCrew (line ~669)
- slingToMayor (line ~876)

NOTE: For patrol-based agents (witness, refinery, deacon), see gt-arjlu which handles nudging them when work is dispatched to polecats in their rig. That's a different pattern - not slinging TO them, but notifying them of activity.

Implementation:
1. For crew: need to determine session name (e.g., gastown-crew-max)
2. Check if session running via tmux
3. If running, call t.NudgeSession() with appropriate message


Implement

Implement the solution for gt-8tmz.34. 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.


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


Digest: mol-deacon-patrol

Patrol 2: archived stale Mayor handoffs, all agents healthy


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

When polecats are spawned, their Claude session takes 10-20 seconds to initialize. The spawn command returns immediately without waiting. This step finds spawned polecats that are now ready and sends them a trigger to start working.

**ZFC-Compliant Observation** (AI observes AI):

```bash
# View pending spawns with captured terminal output
gt deacon pending
```

For each pending session, analyze the captured output:
- Look for Claude's prompt indicator "> " at the start of a line
- If prompt is visible, Claude is ready for input
- Make the judgment call yourself - you're the AI observer

For each ready polecat:
```bash
# 1. Trigger the polecat
gt nudge <session> "Begin."

# 2. Clear from pending list
gt deacon pending <session>
```

This triggers the UserPromptSubmit hook, which injects mail so the polecat sees its assignment.

**Bootstrap mode** (daemon-only, no AI available):
The daemon uses `gt deacon trigger-pending` with regex detection. This ZFC violation is acceptable during cold startup when no AI agent is running yet.


Add await-work and plugin-run steps to mol-refinery-patrol

## Context

The mol-refinery-patrol needs two additional steps:

### 1. await-work (Decision Point)

Not just 'wait for signal' but a crossroads:
- Check for pending signals (mail, nudge, human)
- Check plugin gates (any plugins need to run?)
- Check maintenance schedule (daily/weekly due?)
- Evaluate context and decide next action

Position: Between burn-or-loop and inbox-check (the loop point)

### 2. plugin-run (Like Deacon)

Refinery needs plugin support for:
- **Monitors**: Flag PRs touching sensitive code
- **Gates**: Block merges under certain conditions
- **Schedulers**: Reorder queue based on priority/urgency
- **Maintenance**: Weekly cleanup, audits, stats
- **Audits**: Log merge statistics, track patterns

Position: After queue-scan, before process-branch

## Implementation

Update RefineryPatrolMolecule() in builtin_molecules.go to include:
- await-work step with decision tree
- plugin-run step with gate types

## Related
- gt-7920 (original mol-refinery-patrol)
- docs/deacon-plugins.md (existing plugin model)


Digest: mol-deacon-patrol

Patrol 8: healthy


Digest: mol-deacon-patrol

Patrol 1: No callbacks, no gates, all agents healthy, cleaned 2 orphan processes + 1 stale lock


Polecat auto-start: Claude doesn't process initial nudge

After gt sling spawns a polecat, the 'Work slung' message is sent to tmux but Claude sits idle at the prompt. The SessionStart hook doesn't fire because no user input was received.

Observed:
- gt sling successfully spawns polecat, creates worktree, starts Claude
- Sends 'Work slung: gt-xxx. Start working on it now...' to the pane
- Claude shows idle prompt 'Try refactor...' and doesn't process the message

Expected:
- Polecat should auto-start working on the slung issue

Root cause hypothesis:
- The nudge is sent as tmux send-keys which goes to the input line
- Claude needs Enter to be pressed to submit the prompt
- SessionStart hook only fires after first user message

Workaround:
- Send extra Enter after the nudge message
- Or use daemon's triggerPendingSpawns to send Enter after Claude is ready


Test issue for spawn molecule


Digest: mol-deacon-patrol

Patrol 4: all quiet


Remove Go-based witness patrol - Claude session is the executor

## Problem

The witness has 1370 lines of Go code in internal/witness/manager.go that reimplements what mol-witness-patrol does:
- healthCheck() - polls polecats
- autoSpawnForReadyWork() - spawns polecats for ready issues
- handleStuckPolecat() - nudge logic
- processShutdownRequests() - cleanup logic
- verifyPolecatState() - git state checks

This is backwards. The molecule should drive the work, Claude should execute it.

## The Wrong Architecture (gt-59zd, now cancelled)

The cancelled gt-59zd tried to use molecules as 'tracking ledgers' for Go code:
- Go code runs patrol logic
- Molecule just records what Go did
- Duplicates work, adds complexity

## The Right Architecture

1. Witness runs as Claude session (via gt sling witness or tmux)
2. Claude executes mol-witness-patrol steps directly
3. No Go patrol loop needed
4. Molecule IS the executor, not bookkeeping

## Scope

1. Remove patrol-related functions from manager.go:
   - run(), checkAndProcess(), healthCheck()
   - handleStuckPolecat(), getNudgeCount(), recordNudge()
   - processShutdownRequests(), verifyPolecatState()
   - autoSpawnForReadyWork(), etc.

2. Keep session management functions:
   - Start(), Stop(), Status() - for starting/stopping Claude session
   - State persistence for session identity

3. Update gt witness commands to use Claude session model

4. Test that mol-witness-patrol executes correctly in Claude session

## Related

- gt-zde4: Fixed Witness CLAUDE.md to emphasize mol-following
- gt-59zd: Cancelled - wrong architecture
- witness.md.tmpl: Already rewritten with ZFC principle


Digest: mol-deacon-patrol @ 2025-12-24 19:47

Patrol 16: All healthy


Merge: gt-3x1.3

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


gt doctor: Check and fix beads routing configuration

## Summary

`gt doctor` should check that all rigs with beads have proper routing entries
in `~/gt/.beads/routes.jsonl`, and offer to fix any missing entries.

## Checks to Add

### Check: routes.jsonl exists
- Verify `~/gt/.beads/routes.jsonl` exists
- If missing, create with entries for all known rigs

### Check: All rigs have routing entries
For each rig in town:
1. Find the rig's beads prefix (from config.yaml or sample issue)
2. Check if routes.jsonl has an entry for that prefix
3. If missing, report and offer to add

### Check: Routes point to valid locations
For each route in routes.jsonl:
1. Verify the path exists and has a .beads directory
2. Verify the .beads directory has a beads.db
3. If invalid, report and offer to remove

## Fix Actions

- `--fix` should automatically add missing routes
- `--fix` should remove invalid routes (or prompt)
- Should handle redirect files when validating paths

## Example Output

```
Checking beads routing...
  [!] Rig 'myproject' (prefix: mp-) has no routing entry
      Run: gt doctor --fix to add routing

Routes health:
  [OK] gt- -> gastown/mayor/rig
  [OK] bd- -> beads/mayor/rig
  [!]  mp- -> myproject/mayor/rig (MISSING)
```


Deacon Kernel: event processing molecule architecture

Extend the Deacon from "health orchestrator" to "event processing kernel" that runs a
molecule (rounds) each wake cycle, like an OS kernel scheduler.

## Core Insight

The Deacon already has:
- Wake cycle (daemon poke, timer, lifecycle request)
- Mail as event queue
- Health scanning
- Lifecycle processing

But it is REACTIVE. This epic makes it PROACTIVE with a structured molecule:

```
Deacon Wake
├── Step 0: Session Check (should I cycle myself?)
├── Step 1: Health Scan (Mayor, Witnesses, Crew, Refineries)
├── Step 2: Lifecycle Processing (cycle/restart/shutdown requests)
├── Step 3: Plugin Execution (scheduled, event-triggered, human-requested)
├── Step 4: Event Callbacks (timers, subscriptions)
└── Step 5: Heartbeat + Wait
```

## Key Design Decisions

1. **Session cycling first** - Token costs are quadratic with session length.
   Deacon should aggressively cycle to fresh sessions. First step of every
   wake is "do I need a new session?" based on context budget.

2. **Pinned bead with marching orders** - A pinned bead (like gt prime for
   agents) defines the Deacon's rounds molecule. This is the Deacon's
   "kernel" - its operating loop.

3. **Keepalive file for daemon quieting** - Instead of daemon tmux-poking
   the Deacon (which interrupts work), Deacon writes a keepalive file.
   Daemon reads it and backs off. Worst case: Deacon forgets, gets one
   extra heartbeat it squelches.

4. **Molecule-based rounds** - The wake cycle becomes a molecule with steps.
   Each step can have plugins (inline attention). Steps can be added/modified
   by updating the pinned bead.

## Architecture

```
Go Daemon (minimal, dumb)
├── Reads {townRoot}/deacon/keepalive.json
├── If fresh: do nothing
├── If stale: poke Deacon (fallback)
└── Process lifecycle requests (still daemon's job)

Deacon (Claude agent, smart)
├── Wakes: poke, timer, mail event
├── Writes keepalive (quiets daemon for duration of rounds)
├── Runs rounds molecule:
│   ├── session-check: cycle if context budget low
│   ├── health-scan: check agents, remediate
│   ├── lifecycle: process requests
│   ├── plugins: run scheduled/triggered plugins
│   ├── events: process timer/event callbacks
│   └── complete: update heartbeat, wait
└── Reads marching orders from pinned bead
```

## Relation to Existing Work

- Extends gt-5af (Deacon infrastructure) - CLOSED
- Relates to gt-axz (Plugin architecture) - P3
- Fits into phase3-deacon of gt-ngpz (Christmas Plan)
- Enables gt-976 (Crew lifecycle) as part of health-scan step


CLI: core commands (status, prime, version, init)

Essential CLI commands for Gas Town operation.

## Commands

### gt status
Show overall town status.
```
gt status [--json]
```
Output:
- Town name and location
- Number of rigs
- Active polecats across all rigs
- Witness status per rig
- Recent activity summary

### gt prime
Output role context for current directory.
```
gt prime
```
Detects role from directory:
- Town root or mayor/ → Mayor context
- <rig>/witness/rig/ → Witness context
- <rig>/refinery/rig/ → Refinery context
- <rig>/polecats/<name>/ → Polecat context

### gt version
Show version information.
```
gt version [--short]
```
Output: version, git commit, build date.

### gt init
Initialize current rig for Gas Town (alternative to gt install for existing repos).
```
gt init [--force]
```
Creates Gas Town structure in existing git repo.

## Implementation

Each command is a Cobra subcommand under root:
```go
var statusCmd = &cobra.Command{...}
var primeCmd = &cobra.Command{...}
var versionCmd = &cobra.Command{...}
var initCmd = &cobra.Command{...}
```

Register in cmd/gt/main.go.


Add gt decommission command for clean swarm/worker shutdown

Single command to cleanly shut down a swarm and its workers: cancel swarm, stop sessions, optionally remove polecats. E.g. gt decommission gt-hw6 --cleanup


Break up long functions in start.go

Several functions in internal/cmd/start.go exceed recommended length:
- runStart: 126 lines (129-255) - handles mayor, deacon, rig agents, crew auto-start
- runStartCrew: 155 lines (638-792) - handles crew target parsing, workspace, session
- cleanupPolecats: 91 lines (543-634) - handles polecat cleanup loop

Suggestion: Extract into focused helpers:
- runStart → startMayorAndDeacon(), startRigAgents(), startConfiguredCrew()
- runStartCrew → parseCrewTarget(), ensureCrewWorkspace(), startOrAttachCrewSession()
- cleanupPolecats → cleanupSinglePolecat()


Maintenance: Regular cleanup of closed MR/gate beads

Closed merge-request and gate beads accumulate over time. Need regular cleanup.

## Cleanup Candidates
- type=merge-request with status=closed
- type=gate with status=closed
- type=molecule with status=closed (completed workflows)

## Options
1. **Deacon patrol step** - squash closed MRs periodically
2. **Refinery post-merge** - close and tombstone MR after successful merge
3. **bd doctor check** - warn when stale MR count exceeds threshold

## Consideration
Keep some audit trail? Or just tombstone after N days?


Refactor patrol context functions to reduce duplication

In prime.go, three patrol context functions are nearly identical (~100 lines each):
- outputDeaconPatrolContext() - L797-940
- outputWitnessPatrolContext() - L942-1106
- outputRefineryPatrolContext() - L1108-1272

They all:
1. Check for existing patrol molecule
2. Auto-spawn if none exists
3. Display patrol work loop instructions

**Suggested refactor**:
Extract common logic into a helper:
```go
func outputPatrolContext(ctx RoleContext, patrolName string, assignee string) {
    // shared logic
}
```

Then each role-specific function just calls the helper with appropriate parameters.


Phase 2.3: Polecat CLAUDE.md molecule workflow protocol

Update polecat prompting for molecule-based work.

## CLAUDE.md Updates

Add section on molecule workflow:

```markdown
## Molecule Workflow

When assigned a molecule (check gt prime output):

1. Follow molecule steps in order
2. Mark steps complete: bd mol step complete <step-id>
3. Before signaling done:
   a. Generate summary of work performed
   b. Run: bd squash <molecule-root> --summary "<your summary>"
4. Then signal done as normal

### Summary Guidelines

Your summary should include:
- What was the task?
- What did you do?
- What was the outcome?
- Any issues or follow-ups?

Keep it to 2-4 sentences. This becomes the permanent record.
```


E2E Phase 2 observability test

End-to-end test of Phase 2 observability:

Test scenario:
1. Sling work to polecat
2. Watch gt feed for polecat activity
3. Polecat completes, signals done
4. Watch gt feed for MQ events (merge_started, merged)
5. gt status shows queue depth changes
6. Swarm status visible in gt swarm status

All observable without checking .runtime/*.json files.

Success = glass cockpit is lit.


Context cycling protocol

Document and verify gt handoff pattern for patrol agents. Ensure hook chain works: handoff mail sent, session respawns, SessionStart hook runs gt prime, work continues from pinned molecule.


gt sling: auto-sync beads in new polecat worktrees

## Problem
`gt sling <bead> <rig>` could fail to pin because polecat worktree branches persisted and diverged from current state.

## Root Cause
- Polecat branches (`polecat/<name>`) were reused across runs
- Stale branches could diverge from main and beads-sync
- Branch reuse logic was complex with fallback behavior

## Solution Implemented
**Fresh unique branches per polecat run**

Instead of syncing beads (Options A/B/C), we changed the branch model:

1. **Unique timestamped branches**: Each polecat run creates `polecat/<name>-<timestamp>`
2. **No branch reuse**: Each spawn starts fresh from current HEAD
3. **Simplified code**: Removed branch existence checks and reset logic
4. **Garbage collection**: Added `gt polecat gc <rig>` to clean up old branches

### Why This Works
- Polecats already use beads redirect (`../../mayor/rig/.beads`)
- Mayor's beads are authoritative - polecats read from there
- Fresh branches ensure clean starting state
- Old branches are ephemeral (never pushed to origin)

### Files Changed
- `internal/polecat/manager.go`: Add/Recreate/CleanupStaleBranches
- `internal/git/git.go`: ListBranches helper
- `internal/cmd/polecat.go`: `gt polecat gc` command

### Commands Added
```
gt polecat gc <rig>           # Clean up stale branches
gt polecat gc <rig> --dry-run # Show what would be deleted
```


Digest: mol-deacon-patrol

Patrol cycle 13: All healthy


Digest: mol-deacon-patrol

Patrol 4: Routine, all healthy


Digest: mol-deacon-patrol

Patrol cycle 2: all quiet, agents healthy


Digest: mol-deacon-patrol

Patrol 10: all healthy, doctor pass


Digest: mol-deacon-patrol

Patrol 19: nominal


bd mail send: pinned column missing from schema

gt mail send fails with: sqlite3: SQL logic error: table issues has no column named pinned

Likely a schema migration issue - bd schema has 'pinned' field but SQLite table doesn't.

## Reproduction
gt mail send gastown/Immortan -s 'test' -m 'test'

## Error
table issues has no column named pinned

## Fix
Either:
1. Add migration to add pinned column
2. Remove pinned from insert if not present
3. Regenerate DB from JSONL


Polecat spawn: Environment vars not exported to shell

Polecat sessions set tmux environment but don't export to shell before Claude

In session/manager.go Start():
  _ = m.tmux.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)
  _ = m.tmux.SetEnvironment(sessionID, "GT_POLECAT", polecat)
  ...
  command = "claude --dangerously-skip-permissions"

Compare to crew_lifecycle.go which exports inline:
  claudeCmd := fmt.Sprintf("export GT_ROLE=crew GT_RIG=%s GT_CREW=%s && claude ...")

Result: Claude can't detect polecat identity, falls back to 'mayor', shows wrong hook.

Fix: Export GT_ROLE=polecat GT_RIG=X GT_POLECAT=Y inline before running Claude.


Check Witness and Refinery health

Check Witness and Refinery health for each rig.

**ZFC Principle**: You (Claude) make the judgment call about what is "stuck" or "unresponsive" - there are no hardcoded thresholds in Go. Read the signals, consider context, and decide.

For each rig, run:
```bash
gt witness status <rig>
gt refinery status <rig>
```

**Signals to assess:**

| Component | Healthy Signals | Concerning Signals |
|-----------|-----------------|-------------------|
| Witness | State: running, recent activity | State: not running, no heartbeat |
| Refinery | State: running, queue processing | Queue stuck, merge failures |

**Tracking unresponsive cycles:**

Maintain in your patrol state (persisted across cycles):
```
health_state:
  <rig>:
    witness:
      unresponsive_cycles: 0
      last_seen_healthy: <timestamp>
    refinery:
      unresponsive_cycles: 0
      last_seen_healthy: <timestamp>
```

**Decision matrix** (you decide the thresholds based on context):

| Cycles Unresponsive | Suggested Action |
|---------------------|------------------|
| 1-2 | Note it, check again next cycle |
| 3-4 | Attempt restart: gt witness restart <rig> |
| 5+ | Escalate to Mayor with context |

**Restart commands:**
```bash
gt witness restart <rig>
gt refinery restart <rig>
```

**Escalation:**
```bash
gt mail send mayor/ -s "Health: <rig> <component> unresponsive" \
  -m "Component has been unresponsive for N cycles. Restart attempts failed.
      Last healthy: <timestamp>
      Error signals: <details>"
```

Reset unresponsive_cycles to 0 when component responds normally.


Engineer main loop: poll for ready merge-requests

Implement the Engineer's main processing loop.

Loop structure:
1. Query: bd ready --type=merge-request
2. If empty: sleep(poll_interval), continue
3. Select highest priority, oldest MR
4. Claim: bd update <id> --status=in_progress
5. Process (delegate to other subtasks)
6. Repeat

Configuration:
- poll_interval: from rig config (default 30s)
- max_concurrent: from rig config (default 1)

The loop should be interruptible and handle graceful shutdown.

Reference: docs/merge-queue-design.md#engineer-processing-loop


gt crew add: Agent bead uses hardcoded gt- prefix instead of rig prefix

When running 'gt crew add <name> --rig beads', the command tries to create an agent bead with ID 'gt-crew-beads-<name>' but beads rig uses 'bd' prefix.

Error: issue ID 'gt-crew-beads-grip' does not match configured prefix 'bd'

The agent bead ID should use the target rig's prefix, not hardcode 'gt-'.


Digest: mol-deacon-patrol


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.


witness Handoff


mol-swarm-cleanup: Post-swarm debris cleanup molecule

After a 20+ worker swarm completed, found significant beads debris:
- 18 stale messages (work assignments, lifecycle requests, swarm instructions)
- 3 completed issues still open/in_progress
- Test messages accumulated

Need: Document a post-swarm checklist or create gt swarm cleanup command that:
1. Closes stale work assignment messages
2. Reviews in_progress issues for completion
3. Closes orphaned lifecycle messages
4. Optionally archives test messages


Digest: mol-deacon-patrol

Patrol cycle 2: quick scan, no changes


MQ conflict prediction: file hotspot tracking

Track which files change frequently to predict conflicts before spawn.

## Goal
Before spawning a polecat on an issue, warn if the target files are "hot" (recently changed by other MRs).

## Approach
1. Track file change frequency per MR (sliding window, e.g., last 24h)
2. At spawn time, analyze issue description / planned changes
3. If touching hot files, either:
   - Warn and proceed
   - Suggest waiting for queue to clear
   - Auto-assign to ownership zone (future)

## Implementation
- Add file_changes log to refinery state (or separate hotspot.json)
- After each merge, record changed files with timestamp
- gt spawn checks hotspots before assignment
- Optional: Witness patrol aggregates hotspot data

## Example
```
$ gt spawn --issue gt-xyz
Warning: This issue likely touches auth/login.go
  - Changed 3 times in last 2 hours
  - 2 MRs pending that also touch this file
Proceed anyway? [y/N]
```

## Parent
gt-lxxh2


Merge: slit-1767080431456

branch: polecat/slit-1767080431456
target: main
source_issue: slit-1767080431456
rig: gastown


Digest: mol-deacon-patrol

Patrol 11: All healthy.


gt mail send: add stdin and file input support for complex messages

Current -m flag is fragile with multi-line messages containing backticks, quotes, or shell special chars. Add: 1) --stdin flag to read message body from stdin (heredoc-friendly), 2) -f/--file flag to read from file. This sidesteps shell quoting nightmares for handoff messages with code samples.


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 handoff should accept full session paths like gastown/crew/max

Currently gt handoff only accepts role shortcuts like 'crew', 'witness', etc. and tries to auto-detect the rig/name from environment. User tried 'gt handoff gastown/crew/max' and got 'unknown session type'. Should parse paths like '<rig>/crew/<name>' or '<rig>/<role>' directly into session names like 'gt-<rig>-crew-<name>'.


mol progress: track dynamically bonded children

Extend `gt mol progress` to show dynamically bonded children.

## Current Behavior

```
gt mol progress gt-abc
```

Shows progress through pre-defined steps from InstantiateMolecule.

## New Behavior

Also show dynamically bonded children:

```
📊 Progress: mol-witness-patrol (gt-abc)

  Steps (9):
    ✓ inbox-check
    ✓ check-refinery
    ✓ load-state
    ◐ survey-workers (bonded 3 children)
    ○ aggregate (WaitsFor: all-children)
    ○ save-state
    ○ generate-summary
    ○ context-check
    ○ burn-or-loop

  Bonded Children (3):
    ✓ arm-toast (5/5 steps)
    ◐ arm-nux (3/5 steps)
    ○ arm-furiosa (0/5 steps)

  Progress: 4/9 steps, 3 arms (1 complete, 1 in-progress, 1 pending)
```

## Implementation

1. Find children with bonded_to: <parent-id> in description
2. Recursively get progress for each bonded child
3. Aggregate into parent progress display


Audit hardcoded 'gastown' references in codebase

## Problem

Gas Town should work for ANY rig - not assume 'gastown' (our OSS project) is installed. Found during audit:

### Known Issue (Closed - gt-ci84)
- Deacon patrol wisps were incorrectly using `gastown/mayor/rig/.beads/` instead of town-level beads
- Status: Fixed (implemented town-level wisp storage)

### Remaining Issues

1. **log.go:272** - Fallback path heuristic:
   ```go
   possibleRoots := []string{
       home + "/gt",
       home + "/gastown",  // <-- Assumes user might have gastown as town
   }
   ```
   Should be removed or use a config-based approach.

2. **Help text examples** - Many commands use 'gastown' as the example rig:
   - `gt sling gt-abc gastown`
   - `gt witness start gastown`
   - etc.
   Consider using a generic name like 'myproject' or '<rig>'

3. **Polecat name pool** - 'gastown' is in the Mad Max themed name list.
   This is acceptable (just a name, not a path assumption).

## Tasks
1. Remove `home + "/gastown"` fallback from log.go
2. Consider updating help examples to use generic rig names
3. Full code audit to ensure no other hardcoded assumptions

## Context
Gas Town is the orchestration framework. 'gastown' is just our OSS project that happens to use it. Users installing Gas Town for their own projects should never see anything that assumes 'gastown' rig exists.


Digest: mol-deacon-patrol

Patrol 16: Green


Merge: gt-rana.1

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


Digest: mol-deacon-patrol

Patrol 2 complete: all healthy, no issues


Digest: mol-deacon-patrol

Patrol 9: All healthy.


Phase 1.3: mol-deacon-patrol definition

Define the Deacon patrol molecule in builtin_molecules.go.

## Steps
1. inbox-check - Handle callbacks from agents
2. health-scan - Ping Witnesses and Refineries
3. plugin-run - Execute registered plugins
4. orphan-check - Find abandoned work
5. session-gc - Clean dead sessions
6. context-check - Check own context limit
7. loop-or-exit - Burn and let daemon respawn, or exit if context high

## Implementation
- Add DeaconPatrolMolecule() to builtin_molecules.go
- Add to BuiltinMolecules() list
- Test with bd mol show mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 7: All clear


gt crew remove: Remove crew workspace

Implement 'gt crew remove <name> [--force]' command:
- Check for uncommitted changes, unpushed commits
- Warn and require --force if dirty
- Kill any running session
- Remove directory
- Unregister from mail


Test message

Testing GGT mail via beads


Git wrapper: shell out to git

Wrapper for git operations via subprocess.

## Interface

```go
type Git struct {
    workDir string
}

func NewGit(workDir string) *Git

// Core operations
func (g *Git) Clone(url, dest string) error
func (g *Git) Checkout(ref string) error
func (g *Git) Fetch(remote string) error
func (g *Git) Pull(remote, branch string) error
func (g *Git) Push(remote, branch string, force bool) error

// Commit operations
func (g *Git) Add(paths ...string) error
func (g *Git) Commit(message string) error
func (g *Git) CommitAll(message string) error

// Query operations
func (g *Git) Status() (*GitStatus, error)
func (g *Git) CurrentBranch() (string, error)
func (g *Git) HasUncommittedChanges() (bool, error)
func (g *Git) RemoteURL(remote string) (string, error)

// Merge operations
func (g *Git) Merge(branch string) error
func (g *Git) Rebase(onto string) error
func (g *Git) AbortMerge() error
func (g *Git) AbortRebase() error
```

## Implementation

Shell out to git binary via exec.Command. Parse output where needed (Status, CurrentBranch).

## Error Handling

- Wrap git stderr in error messages
- Detect specific failures (merge conflict, auth failure, not a repo)
- Return structured errors for callers to handle

## Testing

- Use temp directories with real git repos
- Test both success and failure paths


Work on gt-role-template: Refine witness/CLAUDE.md role t...

Work on gt-role-template: Refine witness/CLAUDE.md role template. See issue for details. Run 'bd show gt-role-template' to see the full issue.


Digest: mol-deacon-patrol

Patrol 4: OK


Digest: mol-deacon-patrol

Patrol 12: All healthy, no messages


Add tests for gt crew restart --all

Add integration tests for the crew restart flow:

- Test getAgentSessions() correctly identifies crew sessions
- Test --rig filtering works correctly
- Test --dry-run outputs correct targets
- Test session kill/recreate cycle (without Claude)

Consider extracting a SessionStarter interface to mock the claude-launching bit.

Related: gt crew restart --all was just implemented.


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


Digest: mol-deacon-patrol

Patrol 8: Nominal


gt daemon: Background service management

## Summary

ONE daemon for all Gas Town - a simple Go process (not a Claude agent) that:
1. Pokes agents periodically (heartbeat)
2. Processes lifecycle requests
3. Restarts sessions when agents request cycling

## Architecture

Daemon (gt daemon)
- Pokes Mayor: "HEARTBEAT: check your rigs"
- Pokes each Witness: "HEARTBEAT: check your workers"
- Has inbox at daemon/ for lifecycle requests
- Restarts sessions on cycle requests

## NOT the daemon's job:
- Making decisions (Witnesses do that)
- Running Claude (it's a Go process)
- Processing work (polecats do that)
- Direct polecat management (Witnesses do that)

The daemon is a **dumb scheduler** - poke things, execute lifecycle requests. All intelligence is in agents.

## Commands

- gt daemon start: Start daemon (background)
- gt daemon stop: Stop daemon
- gt daemon status: Show daemon status
- gt daemon logs: View daemon logs

## Daemon Loop

Every heartbeat interval:
1. Poke Mayor
2. For each rig: Poke Witness
3. Process lifecycle requests from daemon/ inbox
4. Check for dead sessions, restart if cycle requested

## Lifecycle Request Handling

Daemon checks its inbox (daemon/) for lifecycle requests:
- From Mayor: cycle/restart Mayor session
- From Witnesses: cycle/restart Witness session

On request:
1. Verify agent state shows requesting_cycle
2. Kill session
3. Start new session
4. Clear requesting_cycle flag

## Poke Protocol

Poke = tmux inject "HEARTBEAT: do your job"
- Agent ignores if already working
- Agent wakes up if idle
- Idempotent - multiple pokes are fine

## Lifecycle Hierarchy

- Daemon manages: Mayor, all Witnesses
- Witness manages: Polecats, Refinery (per rig)
- Crew: self-managed (human workspace)

## Related Issues

- gt-kmn.11: Daemon heartbeat details
- gt-gby: gt handoff command (unified lifecycle)
- gt-u1j.9: Fold witness daemon into this


mol-christmas-launch: 3-day execution plan

---

## Wisp Integration Wave Plan (added 2025-12-21)

Dependency-ordered execution for gt-3x0z (Wisp Molecules) + gt-rana (Patrol System):

### Wave 1 (parallel - no blockers)
- gt-3x0z.1: gt rig init creates .beads-ephemeral/
- gt-3x0z.2: Configure bd for ephemeral molecule bonding
- gt-3x0z.3: gt doctor checks for ephemeral health
- gt-rana.1: Attachment field on pinned beads
- gt-rana.3: mol-deacon-patrol definition

### Wave 2 (after Wave 1)
- gt-3x0z.4: gt spawn --molecule bonds ephemeral (GATE 1)
- gt-rana.2: Daemon attachment detection

### Wave 3-5 (sequential)
- gt-3x0z.5, gt-3x0z.6 → gt-3x0z.7 → gt-3x0z.8 (GATE 2: squash)

### Wave 6+ (patrol integration)
- gt-rana.4: Basic patrol runner (needs gt-rana.3 + gt-3x0z.8)
- gt-3x0z.9: mol-deacon-patrol uses wisp (needs gt-rana.3 + gt-3x0z.8)
- Then: gt-rana.5-7, gt-3x0z.10-12

### Key Gates
1. gt-3x0z.4 - spawn/bond unlocks Phase 2
2. gt-3x0z.8 - squash unlocks patrol integration
3. gt-rana.4 - patrol runner unlocks Phase 2+ patrol

Postponed to New Year's launch. Christmas was too ambitious.


Digest: mol-deacon-patrol

Patrol 7: All healthy.


gt mq integration create: create integration branch for epic

Implement 'gt mq integration create <epic>' command.

Actions:
1. Verify epic exists
2. Create branch: integration/<epic-id> from main
3. Push to origin
4. Store integration branch info in epic metadata

Usage:
  gt mq integration create gt-auth-epic
  # Creates integration/gt-auth-epic from main

Future MRs for this epic's children will auto-target this branch.

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


Witness patrol wisp with polecat leases

Witness should maintain a rolling patrol wisp that tracks active polecats:

```
wisp-witness-patrol
├── lease: furiosa (boot → working → done)
├── lease: nux (working)
└── lease: slit (done, closed)
```

When POLECAT_STARTED arrives:
- bd mol bond mol-polecat-lease wisp-patrol --var polecat=X

Patrol loop iterates leases:
- gt peek $polecat
- If idle: gt nudge
- If shutdown received: close lease

When all leases closed:
- bd mol squash wisp-xxx --summary='N polecats processed'

Requires mol-polecat-lease proto definition.


inbox-check

Process witness mail: lifecycle requests, help requests.

```bash
gt mail inbox
```

Handle by message type:
- LIFECYCLE/Shutdown: Queue for pre-kill verification
- Blocked/Help: Assess if resolvable or escalate
- HANDOFF: Load predecessor state
- Work complete: Verify issue closed, proceed to pre-kill

Record any pending actions for later steps.
Mark messages as processed when complete.


Digest: mol-deacon-patrol

Patrol complete: routine, town stable


Digest: mol-deacon-patrol

Patrol 1: All healthy, no lifecycle requests, 8 active sessions