Add parallel step support to molecules

Enable steps to run in parallel within a molecule.

## Current State

Molecules have linear step dependencies via "Needs:" directive.
Steps run sequentially.

## Proposed Change

Add parallel grouping:

```markdown
## Step: ensure-witnesses
Parallel: true

### Sub-steps
- ensure-gastown-witness
- ensure-beads-witness
```

Or via frontmatter:

```yaml
---
parallel: [ensure-witnesses, ensure-refineries]
---
```

Steps in parallel group:
- Start simultaneously
- Parent step closes when all children complete
- Failures in one dont block others

## Implementation

1. Parse parallel directive in proto
2. When bonding, create child steps with same dependency
3. Executor spawns parallel children concurrently
4. Track completion, close parent when all done

## For Mayor Bootstrap

Mayor can check all witnesses in parallel, then all refineries,
rather than sequentially. Faster boot time.


Digest: mol-deacon-patrol

Patrol 14: All healthy.


Digest: mol-deacon-patrol

Patrol 13: All healthy


Test Patrol for Bonding

Parent issue for mol bond CLI test


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 673/1023)


Session ended: gt-gastown-organic


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 273/1023)


Digest: mol-deacon-patrol

Patrol cycle 8: All healthy


Messaging infrastructure: lists, queues, and channels

## Problem

Current messaging is point-to-point only:
- Mail: A → B (durable, polling)
- Nudge: A → B (ephemeral, real-time)

No support for broadcast, work queues, or pub/sub patterns.

## Design

### Addressing Syntax

| Prefix | System | Resolution | Storage | Claim? |
|--------|--------|------------|---------|--------|
| `agent/` | Mail | Direct | Recipient inbox | N/A |
| `@group` | Mail | Dynamic (filesystem) | Fan-out (N copies) | No |
| `list:name` | Mail | Static config | Fan-out (N copies) | No |
| `queue:name` | Mail | Static config | Shared (1 copy) | Yes |
| `announce:name` | Mail | Static config | Shared (1 copy) | No |
| `#channel` | Nudge | Dynamic (tmux) | None (ephemeral) | No |

### Dynamic Aliases

- `@rig/gastown` → scan ~/gt/gastown/ for agent dirs (witness, refinery, crew/*, polecats/*)
- `@town` → scan ~/gt/ for all agent dirs
- `@witnesses` → for each rig, include <rig>/witness
- `@crew/gastown` → scan ~/gt/gastown/crew/*
- `#rig/gastown` → scan tmux for gastown/* sessions
- `#town` → scan tmux for all Gas Town sessions

**Mail** resolves against filesystem (agents that exist)
**Channels** resolve against tmux (agents that are running)

### Static Config

Location: `~/gt/config/` (JSON format, machine-edited)

```json
// lists.json
{
  "oncall": ["mayor/", "gastown/witness", "beads/witness"],
  "cleanup/gastown": ["gastown/witness", "deacon/"]
}
```

### Work Queue Semantics

- `gt mail send queue:cleanup/gastown -s "Task" -m "..."`
- `bd update <msg-id> --claim` → atomic claim (sets assignee + in_progress)
- If already claimed, returns error "already claimed by X"

### Use Cases

1. **Polecat spawn**: `gt mail send @rig/gastown` → Witness + Deacon both notified
2. **Polecat cleanup**: `gt mail send queue:cleanup/gastown` → first to claim handles it
3. **Town broadcast**: `gt mail send @town -s "Handoff now"` → everyone gets copy
4. **Real-time alert**: `gt channel publish #witnesses "Swarm incoming"`

## Implementation Tasks

1. Create ~/gt/config/ directory structure
2. Implement dynamic alias resolution (filesystem scan)
3. Implement static list lookup (config/lists.json)
4. Add fan-out at send time for @/list: addresses
5. Implement queue: with shared storage
6. Add `bd update --claim` for work queue semantics
7. Implement channel resolution (tmux scan)
8. Add `gt channel publish` command


Refinery and witness rigs should redirect .beads to mayor rig

The refinery's rig clone and witness rig clones should have their .beads directories redirect to the mayor's rig beads (like polecats do).

Current state:
- Polecats have .beads symlinked/redirected to mayor rig beads
- Refinery and witness have their own .beads (or none)

Desired state:
- refinery/rig/.beads -> mayor/rig/.beads (or equivalent redirect)
- witness/rig/.beads -> mayor/rig/.beads (or equivalent redirect)

This ensures all rig agents share the same issue tracking state.


Add Deacon heartbeat mechanism

Deacon writes deacon/heartbeat.json on each wake. Go daemon reads it to decide whether to poke. Add heartbeat read/write helpers.


Move disk 4: B → A

Move disk 4 from peg B to peg A. (Move 712/1023)


Digest: mol-deacon-patrol

Patrol #7


Digest: mol-deacon-patrol

Cycle 17


Design: Failure modes and recovery

Document failure modes and recovery strategies for Gas Town operations.

## Critical Failure Modes

### 1. Agent Crash Mid-Operation

**Scenario**: Polecat crashes while committing, Witness crashes while verifying

**Detection**:
- Session suddenly gone (tmux check fails)
- State shows 'working' but no session
- Heartbeat stops (for Witness)

**Recovery**:
- Doctor detects via ZombieSessionCheck
- Capture any recoverable state
- Reset agent state to 'idle'
- For Witness: auto-restart via supervisor or manual gt witness start

### 2. Git State Corruption

**Scenario**: Merge conflict, failed rebase, detached HEAD

**Detection**:
- Git commands fail
- Dirty state that won't commit
- Branch diverged from origin

**Recovery**:
- gt doctor reports git health issues
- Manual intervention recommended
- Severe cases: remove clone, re-clone

### 3. Beads Sync Conflict

**Scenario**: Two polecats modify same issue

**Detection**:
- bd sync fails with conflict
- Beads tombstone mechanism handles most cases

**Recovery**:
- Beads has last-write-wins semantics
- bd sync --force in extreme cases
- Issues may need manual dedup

### 4. Tmux Failure

**Scenario**: Tmux server crashes, socket issues

**Detection**:
- All sessions inaccessible
- "no server running" errors

**Recovery**:
- Kill any orphan processes
- tmux kill-server && tmux start-server
- All agent states reset to idle
- Re-spawn active work

### 5. Claude API Issues

**Scenario**: Rate limits, outages, context limits

**Detection**:
- Sessions hang or produce errors
- Repeated failure patterns

**Recovery**:
- Exponential backoff (handled by Claude Code)
- For context limits: session cycling (mail-to-self)
- For outages: wait and retry

### 6. Disk Full

**Scenario**: Clones, logs, or beads fill disk

**Detection**:
- Write operations fail
- git/bd commands error

**Recovery**:
- Clean up logs: rm ~/.gastown/logs/*
- Remove old polecat clones
- gt doctor --fix can clean some cruft

### 7. Network Failure

**Scenario**: Can't reach GitHub, API servers

**Detection**:
- git fetch/push fails
- Claude sessions hang

**Recovery**:
- Work continues locally
- Queue pushes for later
- Sync when connectivity restored

## Recovery Principles

1. **Fail safe**: Prefer stopping over corrupting
2. **State is recoverable**: Git and beads have recovery mechanisms
3. **Doctor heals**: gt doctor --fix handles common issues
4. **Emergency stop**: gt stop --all as last resort
5. **Human escalation**: Some failures need Overseer intervention

## Implementation

- Document each failure mode in architecture.md
- Ensure doctor checks cover detection
- Add recovery hints to error messages
- Log all failures for debugging


Molecule await-signal step type

Add await-signal as a molecule step type for patrol agents.

## Step Definition

```toml
[[steps]]
id = "await-signal"
type = "wait"
backoff = { base = "30s", multiplier = 2, max = "10m" }
description = "Wait for signal, then check reality"
```

## Behavior

1. Sleep for current backoff interval
2. Wake immediately on nudge (or timeout expires)
3. Proceed to next step (check-reality)
4. If no work found, loop back with increased backoff
5. If work found, reset backoff to base

## Implementation Options

A. Formula-level: Define in TOML, agent interprets
B. Code-level: Agent implements wait loop with backoff

Option A is cleaner but needs formula parser support.
Option B works now but less declarative.

## Used By

- mol-witness-patrol (first step)
- mol-refinery-patrol (first step)


Update config location: .gastown/ → config/

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

Hidden directories are poorly discovered by AI agents.


Digest: mol-deacon-patrol

Cycle 13


Direct formula-to-wisp instantiation (skip proto)

For massive ephemeral workflows (e.g., million-step Towers of Hanoi), allow:

bd wisp towers-of-hanoi --var disks=20

This would cook + wisp in one step, never materializing the proto. Useful when:
- The proto would be huge (1M+ steps)
- The work is ephemeral (wisp, not mol)
- You don't need the intermediate artifact

Implementation: streaming cook that emits directly to wisp storage.

Related: towers-of-hanoi.formula.yaml demonstrates the use case.


Add --fart as easter egg alias for bd mol bond

Add a hidden alias for the bond command:

```bash
bd mol fart mol-polecat-work --wisp
# equivalent to:
bd mol bond mol-polecat-work --wisp
```

## Context
The fart joke: instantiating a proto can produce either:
- A Mol (solid/substantial output)
- A Wisp (gas/ephemeral output)

## Implementation
- Add 'fart' as an alias in the mol subcommand
- No documentation needed (easter egg)
- Maybe a fun message: 'Bonding molecule...' or similar

Low priority, just for fun.


Merge: furiosa-dogs

branch: polecat/furiosa-dogs
target: main
source_issue: furiosa-dogs
rig: gastown


gt-gastown-polecat-splendid

gt-gastown-polecat-splendid

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: gt-zqt4d
role_bead: gt-polecat-role
cleanup_status: null
active_mr: gt-rbjo3
notification_level: null


Digest: mol-deacon-patrol

Patrol cycle 11: All 3 rigs healthy. No incidents.


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 379/1023)


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 998/1023)


Digest: mol-deacon-patrol

Patrol 5: routine, all healthy


Move disk 4: C → B

Move disk 4 from peg C to peg B. (Move 408/1023)


Witness for gastown - monitors polecat health and progress.

role_type: witness
rig: gastown
agent_state: dead
hook_bead:
role_bead: gt-witness-role

Marked dead by daemon at 2026-01-02T02:35:24-08:00 (was running, last update too old)


Move disk 10: A → C

Move disk 10 from peg A to peg C. (Move 512/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 845/1023)


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 722/1023)


Digest: mol-deacon-patrol

Patrol cycle 3: all systems nominal


Merge: gt-h6eq.3

branch: polecat/dag
target: main
source_issue: gt-h6eq.3
rig: gastown


Move disk 6: C → B

Move disk 6 from peg C to peg B. (Move 480/1023)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 703/1023)


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


CLI: rig commands (add, list, show, remove)

GGT needs rig management commands.

Missing Commands:
- gt rig add <git-url> [--name NAME] - Add rig to workspace
- gt rig list - List all rigs with status
- gt rig show <rig> - Show detailed rig info
- gt rig remove <rig> - Remove a rig

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

Current State:
- gt init creates rig structure but no ongoing management
- Rig discovery in internal/rig/manager.go but not exposed via CLI


P4: Graceful degradation without tmux

Low-priority: Add graceful degradation for environments without tmux.

Current state: Patrol formulas use tmux capture-pane for observing agent state.

tmux-independent alternatives (degraded mode):
1. Tail Claude Code session logs if available
2. Rely solely on agent bead state (less real-time)
3. Use claude --output-file and tail that
4. IPC mechanisms (named pipes, sockets)

NOT launch-blocking. By summer 2025, Claude Code is expected to add signaling and reflection features that will obviate tmux scraping.

For now:
- Keep tmux as primary observation mechanism
- Document the tmux dependency
- Add --no-tmux flag that falls back to bead-only observation

This is P4 backlog - address after liftoff.


Merge: slit-1767141951901

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


Digest: mol-deacon-patrol

Patrol 14: OK


Remove keepalive file infrastructure

The keepalive mechanism (~/gt/daemon/activity.json) is deprecated in favor of feed-based wake.

TODO:
1. Remove keepalive.TouchTownActivity() calls from gt commands
2. Remove keepalive.ReadTownActivity() from daemon
3. Delete internal/keepalive package
4. Update daemon to use longer base heartbeat (recovery-focused)

Whitelist consideration: Some read-only commands might need to wake (TBD - none identified yet)


Digest: mol-deacon-patrol

Patrol cycle 57: All healthy


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy


Digest: mol-deacon-patrol

Patrol cycle 8: All 6 agents healthy


Deacon patrol refactor: detect → dispatch

Refactor Deacon patrol to delegate heavy work to dogs:
- check-conditions → sling to dog (not inline execution)
- Pool maintenance step (spawn/retire/refresh)
- Completion mail handling from dogs
- Keep patrol lightweight (detection only)


Merge: gt-92l

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


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.

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Polecat wisp architecture: Proto → Wisp → Mol pattern

Design the three-layer architecture for polecat lifecycle:

## The Insight

Polecats should run a ONE-SHOT WISP (not looping like patrols):

**Step 1: Onboard**
- Read full polecat protocol (polecat.md template)
- Learn Gas Town operation, exit strategies, molecule protocol
- This is the 'how to be a polecat' education

**Step 2: Execute Mol**
- Run the assigned molecule (the actual work item)
- Could span multiple sessions via session continuity
- The mol is pure work content (epic, issue, feature)

**Step 3: Cleanup**
- Run final step of the wisp
- Self-delete / request shutdown

## Three Layers

- **Proto**: polecat.md template (instructions for being a polecat)
- **Wisp**: One-shot harness instantiated from proto (wraps the mol)
- **Mol**: The work item (issue/epic being processed)

## Why This Matters

1. **Separation of concerns**: Protocol (how) vs Work (what)
2. **Reusability**: Same wisp harness wraps any mol
3. **Extensibility**: Plugin points for custom behavior
4. **Session continuity**: Wisp handles multi-session, not the mol
5. **Blurred control/data planes**: Intentional in Gas Town

## Design Questions

1. How does proto (polecat.md) become a wisp instance?
2. What are the plugin/extension points?
3. Should all 'engineer in a box' mols use proto → wisp → mol?
4. How does this relate to refinery/deacon patterns?


Digest: mol-deacon-patrol

Cycle 200: Final cycle of session, all agents healthy, handoff triggered


Merge: nux-mjw3mn8o

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


Digest: mol-deacon-patrol

Patrol cycle 13: All healthy - Witness/Refinery running, 7 polecats monitored


Digest: mol-deacon-patrol

Patrol 11: quick pass


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 326/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 263/1023)


Digest: mol-deacon-patrol

Patrol 21: all healthy, no lifecycle requests, 4 in-progress issues noted, handoff triggered at threshold


Move disk 2: C → B

Move disk 2 from peg C to peg B. (Move 78/1023)


Digest: mol-deacon-patrol

Patrol 3: quiet, health OK


Digest: mol-deacon-patrol

Patrol 9: nominal


Digest: mol-deacon-patrol

Patrol 17: nominal


mol-deacon-patrol


Move disk 7: B → C

Move disk 7 from peg B to peg C. (Move 192/1023)


Swarm learning: Witness needs automated context cycling

Furiosa hit 2% context during swarm work. Witness role needs automated detection of low context and should trigger session cycling before agents get stuck. Add to Witness responsibilities in prompts.md.


gt mq reject: manual MR rejection

Implement 'gt mq reject <id> --reason "..."' for manual rejection.

Actions:
1. Verify MR exists and is open
2. Close MR with close_reason=rejected
3. Notify worker via mail (optional)
4. Do NOT close source issue (work not done)

Options:
- --reason REASON: required explanation
- --notify: send mail to worker

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


Add WaitsFor parsing to molecule steps

Add WaitsFor field to MoleculeStep struct and parse 'WaitsFor: all-children' (and future variants) from molecule descriptions.

This enables:
- mol progress to understand fanout patterns
- Validation that WaitsFor references valid constructs
- Future automated orchestration

Implementation:
1. Add WaitsFor []string to MoleculeStep struct
2. Add waitsForLineRegex to parse 'WaitsFor: ...' lines
3. Update ParseMoleculeSteps to extract WaitsFor
4. Update tests


test


Polecat management: add, remove, list, state

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

## Data Model

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

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

## Interface

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

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

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

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

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

## Add Flow

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

## Remove Flow

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

## State Persistence

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


Harness & Priming: Document architecture and update all role contexts


End-to-end swarm integration test

Full integration test for swarm lifecycle.

Test scenario:
1. Create a small epic with 3-4 issues and dependencies
2. Run bd swarm validate - should pass
3. Run gt swarm create with the epic
4. Verify swarm molecule created with mol_type=swarm
5. Run gt swarm status - verify ready front
6. Simulate issue completion (bd close)
7. Verify ready front advances
8. Complete all issues
9. Verify swarm auto-closes

Can be manual test documented in test file, or automated.

Dependencies: gt-kc7yj.2 (Witness integration), gt-kc7yj.3 (completion detection)


Merge: toast-1767140378007

branch: polecat/toast-1767140378007
target: main
source_issue: toast-1767140378007
rig: gastown


Digest: mol-deacon-patrol

Patrol 18: all clear


Digest: mol-deacon-patrol

Patrol complete


Add orphaned-attachments doctor check

Add gt doctor check for molecules attached to non-existent agents.

Check: orphaned-attachments
Warning if: Handoff bead exists for agent that no longer has worktree
Fix suggestion: Re-sling to active agent or close molecule


mol-sync-workspace: Split handle-dirty-state into focused steps


Implement gt agent state command for label-based state

Add gt agent state command:
- gt agent state <agent-bead> - Get all labels
- gt agent state <agent-bead> --set key=value - Set label
- gt agent state <agent-bead> --incr key - Increment numeric label
- gt agent state <agent-bead> --del key - Delete label

Labels stored on agent beads enable operational state (idle:N, backoff:2m, etc).


inspect-workers

Capture output for each working polecat.

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

Needs: survey-workers


Move disk 4: C → B

Move disk 4 from peg C to peg B. (Move 936/1023)


Digest: mol-deacon-patrol

Patrol complete: all healthy, no events


BUG: Daemon heartbeat too slow (10 min) for stuck agent detection

The daemon's recoveryHeartbeatInterval is set to 10 MINUTES (daemon.go:134).

This means if an agent gets stuck, it can waste up to 10 minutes before Boot is spawned to triage.

Suggested fix: Reduce heartbeat to 2-3 minutes, or add a separate fast-path stuck-detection check.

Related: hq-nsx0g


Witness swarm integration

Add swarm coordination to Witness patrol.

The Witness should be able to:
1. Receive swarm assignments via mail (SWARM: subject prefix)
2. Query ready front and dispatch to available polecats
3. Monitor polecat progress on swarm tasks
4. Detect completion and close swarm molecule
5. Use Christmas Ornament pattern for arm-bonding (optional)

Implementation:
- Add swarm handling to mol-witness-patrol formula
- Mail trigger: SWARM in subject
- Dispatch: bd ready --parent=<epic> to find ready issues
- Assign: gt sling <issue> to available polecat
- Monitor: Check polecat status during patrol
- Complete: When bd ready --parent returns empty and all closed

Reference: ~/gt/docs/swarm-architecture.md - Witness Integration section

Dependencies: gt-kc7yj.1 (gt swarm refactor)


Engineer session restart protocol

Implement session restart flow for when the Engineer needs to split work:

1. Engineer creates subtask(s) in Beads assigned to self
2. Engineer sends handoff mail to self (🤝 HANDOFF)
3. Engineer sends restart request to Witness
4. Witness verifies:
   - Handoff mail exists in Engineer outbox/sent
   - Subtasks filed in Beads
5. Witness restarts the Refinery session (new Engineer context)

This enables "occasionally consistent, eventually convergent" work patterns.
The Refinery continues; the Engineer gets fresh context.


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 156/1023)


Digest: mol-deacon-patrol

Patrol 3: routine checks, all healthy


Digest: mol-deacon-patrol

Patrol 88: All healthy


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 127/1023)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 655/1023)


Digest: mol-deacon-patrol

P4: stable


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.

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Test message

Testing GGT mail via beads


Merge: imperator-1767106079026

branch: polecat/imperator-1767106079026
target: main
source_issue: imperator-1767106079026
rig: gastown


Digest: mol-deacon-patrol

Patrol 14: All healthy


Tmux status line: rig color themes and worker identity display

## Summary

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

## Current Problem

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

## Proposed Design

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

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

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

## Configuration

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

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


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 557/1023)


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 686/1023)


Digest: mol-deacon-patrol

P9: stable


Pillar 2: Patrol Ignition

Witness and Refinery patrol loops fire reliably.

Key deliverables:
- Witness patrol reads agent beads for polecat state
- Witness sends MERGE_READY to refinery on completion
- Refinery processes MERGE_READY mail
- Both send completion signals

Subsumes existing work:
- gt-6qyt1: Refinery event-driven merge queue
- gt-qpwv4: Witness detect completion
- gt-dtw9u: Witness active monitoring

Reference: ~/gt/docs/liftoff-plan.md

Parent: gt-oki8p


Digest: mol-deacon-patrol

Patrol 4 complete. All healthy.


Digest: mol-deacon-patrol

Patrol cycle 2: All 6 agents healthy, 3 polecats active (furiosa, nux, obsidian), beads refinery has 1 pending


Digest: mol-deacon-patrol

Patrol 38: all quiet


Digest: mol-deacon-patrol

Patrol 10: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol 15: quiet


Digest: mol-deacon-patrol

Patrol 15: clear


gt-polecat-gastown-furiosa

gt-polecat-gastown-furiosa

role_type: polecat
rig: gastown
agent_state: done
hook_bead: null
role_bead: null
cleanup_status: clean


Move disk 5: A → B

Move disk 5 from peg A to peg B. (Move 400/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 623/1023)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 205/1023)


gt-polecat-gastown-test-cat

gt-polecat-gastown-test-cat

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: null
role_bead: null


implement

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


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 757/1023)


Consolidate duplicate formatAge functions in feed TUI

formatConvoyAge in convoy.go is nearly identical to formatAge in view.go. Consolidate into one shared function.


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 63/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 1007/1023)


Swarm state persistence: manifest + state + events

Upgrade swarm persistence to match PGT pattern.

## Current State
Single .gastown/swarms.json with all swarms.

## Target State (per-swarm)
```
.gastown/swarms/
└── <swarm-id>/
    ├── manifest.json  # Immutable config
    ├── state.json     # Mutable progress
    ├── events.jsonl   # Audit log
    └── report.md      # Generated report
```

## File Schemas

### manifest.json (immutable after creation)
```json
{
  "id": "sw-1",
  "title": "Epic description",
  "epic_id": "gt-abc",
  "rig": "gastown",
  "base_commit": "abc123",
  "integration_branch": "swarm/sw-1",
  "target_branch": "main",
  "workers": ["Toast", "Nux"],
  "tasks": [{"id": "gt-xyz", "title": "..."}],
  "created_at": "2024-01-01T00:00:00Z"
}
```

### state.json (mutable)
```json
{
  "state": "active",
  "task_states": {
    "gt-xyz": {"state": "merged", "assignee": "Toast"}
  },
  "updated_at": "2024-01-01T01:00:00Z",
  "error": null
}
```

### events.jsonl (append-only audit)
```jsonl
{"event": "created", "ts": "...", "data": {...}}
{"event": "task_assigned", "ts": "...", "data": {...}}
{"event": "task_merged", "ts": "...", "data": {...}}
```

## Benefits
- Audit trail via events.jsonl
- Manifest immutability prevents corruption
- Cleaner separation of concerns
- Per-swarm isolation

## Migration
Keep backward compat with swarms.json during transition.

## Files to Modify
- internal/swarm/manager.go: Refactor persistence
- internal/cmd/swarm.go: SwarmStore → directory-based

## Acceptance Criteria
- [ ] Per-swarm directory structure
- [ ] Events logged to JSONL
- [ ] Manifest immutable after creation
- [ ] List command aggregates from directories


Digest: mol-deacon-patrol

Patrol 4: gastown+beads witnesses/refineries healthy


Detect cleanup needs

**DETECT ONLY** - Check if cleanup is needed and dispatch to dog.

**Step 1: Preview cleanup needs**
```bash
gt doctor -v
# Check output for issues that need cleaning
```

**Step 2: If cleanup needed, dispatch to dog**
```bash
# Sling session-gc formula to an idle dog
gt sling mol-session-gc deacon/dogs --var mode=conservative
```

**Important:** Do NOT run `gt doctor --fix` inline. Dogs handle cleanup.
The Deacon stays lightweight - detection only.

**Step 3: If nothing to clean**
Skip dispatch - system is healthy.

**Cleanup types (for reference):**
- orphan-sessions: Dead tmux sessions
- orphan-processes: Orphaned Claude processes
- wisp-gc: Old wisps past retention

**Exit criteria:** Session GC dispatched to dog (if needed).


Digest: mol-deacon-patrol

Patrol 15


Digest: mol-deacon-patrol

Patrol 14: Quiet


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 1005/1023)


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 #12


Deacon rounds molecule: the kernel execution loop

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

## Molecule Definition

```markdown
# mol-deacon-rounds

The Deacon kernel - executed on every wake cycle.

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

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

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

Needs: session-check

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

Needs: health-scan

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

Needs: lifecycle

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

Notify relevant agents or trigger actions.

Needs: plugins

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

Needs: events
```

## Execution

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

## Step Plugins

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

## Relation to bd mol

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


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 981/1023)


Digest: mol-deacon-patrol

Patrol 3: 3 rigs healthy, no incidents


Digest: mol-deacon-patrol

Cycle 196: Nominal


Code Review Convoy formula (first formula implementation)

## First Formula: Code Review Convoy

Implement the code review formula as proof of concept for formula molecules.

### Input
- PR number, branch, or file list

### Legs (parallel polecats)
| Leg | Focus | Output |
|-----|-------|--------|
| correctness | Logic errors, edge cases, off-by-ones | findings.md |
| performance | Bottlenecks, O(n²), allocations | findings.md |
| security | Injection, auth, data exposure | findings.md |
| elegance | Design clarity, abstractions | findings.md |
| resilience | Error handling, retries, timeouts | findings.md |
| style | Conventions, naming, formatting | findings.md |
| smells | Anti-patterns, god objects, coupling | findings.md |

### Synthesis
- Read all leg findings
- Deduplicate overlapping issues
- Prioritize by severity
- Produce unified review with sections

### Command
```bash
gt formula run code-review --pr=123
# Creates convoy hq-cv-xxx
# Spawns 7 polecats + 1 synthesis
# Lands with review-summary.md
```

### Implementation Steps
1. Define formula schema in beads
2. gt formula run command
3. Leg prompt templates
4. Output collection mechanism
5. Synthesis polecat spawning
6. Result attachment to convoy bead


Digest: mol-deacon-patrol

Patrol 7: All healthy.


Optimize: Share stepMap across control flow operators

In ApplyControlFlow, both ApplyBranches and ApplyGates call buildStepMap() separately:

```go
func ApplyBranches(steps []*Step, compose *ComposeRules) ([]*Step, error) {
    stepMap := buildStepMap(steps)  // Called here
    ...
}

func ApplyGates(steps []*Step, compose *ComposeRules) ([]*Step, error) {
    stepMap := buildStepMap(steps)  // Called again here
    ...
}
```

This is inefficient for large formulas. Options:

1. Pass stepMap as a parameter to ApplyBranches/ApplyGates
2. Create an internal version that accepts stepMap, keep public API unchanged
3. Build once in ApplyControlFlow and pass down

Low priority since formula sizes are typically small.


Digest: mol-deacon-patrol

Patrol #17


Digest: mol-deacon-patrol

Patrol 74: Routine


Merge: dementus-mjxofwf6

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


Mayor notification levels (Do Not Disturb mode)

## Problem

Mayor needs notification level control like iOS Do Not Disturb:
- **Verbose**: gt nudge tmux messages for mail, convoy events, escalations
- **Normal**: Important events only (convoy landed, escalations)
- **Muted/DND**: Silent - batch notifications for later review

## Use Cases

1. Running a swarm: Mute notifications, check convoy status manually
2. Waiting for work: Verbose - get nudged when mail arrives
3. Deep coordination: Normal - only interruptions that need attention

## Design Considerations

### Beads Data Plane Integration
- Notification preferences should be a bead slot (persistent across sessions)
- Events are already beads (mail, convoy status changes)
- Need event classification: urgency levels on beads?
- gt nudge should check notification level before firing

### State Location
- Mayor agent bead has slots for persistent state
- `notification_level`: verbose | normal | muted
- Could also have per-event-type overrides

### Commands
```bash
gt dnd on              # Mute notifications
gt dnd off             # Resume normal
gt dnd status          # Show current level
gt notify verbose      # All notifications
gt notify normal       # Default
gt notify muted        # DND mode
```

### Event Classification
Which events are which urgency?
- P0: Escalations from Witness, critical failures
- P1: Convoy landed, work completed
- P2: New mail, status updates
- P3: Informational (can always batch)

### Open Questions
1. Should DND auto-disable after convoy lands?
2. Per-convoy notification preferences?
3. How to surface batched notifications when DND ends?
4. Integration with tmux status line vs nudge popups?


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

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


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 758/1023)


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 348/1023)


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.

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 828/1023)


Digest: mol-deacon-patrol

Patrol cycle 5: All quiet.


Digest: mol-deacon-patrol

Patrol 89: All healthy


mol-deacon-patrol


decide-actions

Apply nudge matrix and queue actions.

Progressive nudge levels:
- Level 1: Gentle reminder
- Level 2: Stronger nudge
- Level 3: Final warning
- Level 4: Escalate to Mayor

Needs: inspect-workers


Exponential backoff for idle patrol agents

## Problem

Patrol agents (Refinery, Witness, Deacon) currently have no backoff when their queue is empty. They either:
- Loop immediately (wasting cycles)
- Exit and wait for 10-minute daemon respawn (too slow to respond)

## Solution: Feed-Driven Backoff

### The Pattern (from PRIMING.md)

> "Backoff isn't about polling less - it's about **waiting for signals with a timeout**."

Agents subscribe to `bd activity --follow` and wake on any beads mutation. The timeout increases exponentially during idle periods.

### Data Flow

```
bd/gt mutations → .events.jsonl → feed curator → .feed.jsonl
                                                      ↓
                    patrol agent: gt mol await-signal --backoff-*
                                                      ↓
                              signal → wake, reset idle_cycles
                              timeout → increment idle_cycles, sleep longer
```

### Backoff Formula

```
timeout = min(base × multiplier^idle_cycles, max)
```

| Idle Cycles | Timeout |
|-------------|---------|
| 0 | 30s |
| 1 | 1m |
| 2 | 2m |
| 3 | 4m |
| 4+ | 5m (capped) |

### Agent State Storage

Operational state stored as labels on agent beads (labels-as-cache pattern):
- `idle:3` - consecutive idle patrol cycles
- `backoff:2m` - current backoff interval (derived)
- `last_activity:2025-12-31T10:00:00Z` - timestamp

### Implementation Layers

**Layer 1: gt agent state command**
```bash
gt agent state <agent-bead>                    # Get labels
gt agent state <agent-bead> --set idle=0       # Set label
gt agent state <agent-bead> --incr idle        # Increment
```

**Layer 2: Fix await-signal iteration tracking**
- Read `idle:N` label from agent bead
- Calculate effective timeout using BackoffConfig
- On timeout: increment label, return "timeout"
- On signal: return "signal" (agent resets)

**Layer 3: Patrol formula integration**
Update burn-or-loop step:
```bash
# If work found
gt agent state $AGENT_BEAD --set idle=0

# If no work
gt mol await-signal --agent-bead $AGENT_BEAD   --backoff-base 30s --backoff-mult 2 --backoff-max 5m

# After 10 consecutive max-timeout cycles, exit for fresh session
```

**Layer 4: Feed signal sources**
Ensure these emit events:
- gt sling → TypeSling
- bd create/update/close → BeadMutation
- gt mail send → TypeMail

### ZFC Compliance

| Component | Role | ZFC |
|-----------|------|-----|
| Feed curator | Aggregates events | ✅ Transport |
| await-signal | Waits with timeout | ✅ Transport |
| Agent bead labels | Stores idle_cycles | ✅ Agent-written |
| Backoff decision | Agent decides | ✅ Agent decides |

Go code provides mechanics. **Agent decides** parameters, reset, and exit.

### Existing Infrastructure

- Feed Curator: internal/feed/curator.go ✅
- BackoffConfig: internal/beads/molecule.go ✅
- await-signal cmd: internal/cmd/molecule_await_signal.go (needs fix)
- Agent Beads: internal/beads/beads.go ✅
- Labels pattern: docs/operational-state.md ✅

### Exit Strategy

After N consecutive max-interval cycles (e.g., 10 × 5m = 50 minutes idle):
- Agent exits cleanly
- Daemon respawns fresh session
- Fresh session starts with idle:0


Digest: mol-deacon-patrol

Patrol cycle 26: All healthy, no incidents


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 717/1023)


Digest: mol-deacon-patrol

Patrol #6: Stable


Digest: mol-deacon-patrol

Patrol 3: All clear


Merge: gt-qz2l

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


Digest: mol-deacon-patrol

Patrol 16: all quiet


Design future federation model

Document how remote/federated refinery would work in the future.

## Options to document
1. Git bundles - portable patches, no branches on origin
2. Dedicated integration branch pattern (integration/*)
3. Hybrid - local for same-machine, bundles for remote

## Deliverable
Design doc in docs/federation-refinery.md or similar.
Not implementing now - just capturing the design for when needed.


Patrol Exponential Backoff System

Cost-saving await-signal model for patrol agents.

## The Problem

Patrol agents (witness, refinery) poll continuously even when idle, burning API credits.

## The Solution: Await-Signal

Agents don't poll constantly. They **wait for a signal**, then **discover reality**.

```
PATROL LOOP:
    await-signal (just wake me)
         ↓ awake
    check-reality (mail, beads, hook, git)
         ↓
    work found? → DO WORK → loop
         ↓ no
    increase backoff → loop
```

**Key principle (ZFC-aligned):** Signal carries no semantic meaning - just 'wake up'.
Agent discovers what to do by examining reality.

## Two-Level Wake

| Level | State | Command |
|-------|-------|---------|
| 1 | Running (backoff) | `gt nudge` clears backoff |
| 2 | Asleep | `gt rig boot` starts session |

**Boot+nudge pattern:**
```bash
gt rig boot <rig>              # Wake if asleep (idempotent)
gt nudge <rig>/witness 'wake'  # Clear backoff if running
```

## Backoff Curve

Base: 30s → 60s → 120s → 240s → ... → 10min cap

Resets on: nudge received, work found, deacon ping.

## Reference

See ~/gt/docs/patrol-system-design.md (Await-Signal Model section)


Merge: rictus-mjw3nj1a

branch: polecat/rictus-mjw3nj1a
target: main
source_issue: rictus-mjw3nj1a
rig: gastown
agent_bead: gt-gastown-polecat-rictus


Digest: mol-deacon-patrol

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


Move disk 1: A → C

Move disk 1 from peg A to peg C.


Digest: mol-deacon-patrol

Patrol 1: All healthy, no messages, no orphans


Review: Refinery patrol template changes (gt-qz2l)

Polecat dementus implemented refinery template changes: banners, wisp-based execution, propulsion protocol. Review for correctness and consistency with witness/deacon patterns.


Add org formula examples and tests

Create example organizational formula hierarchy and tests.

## Examples

Create in .beads/formulas/:
- acme-base.formula.yaml: Company-wide (security-audit aspect)
- acme-frontend.formula.yaml: extends acme-base, adds accessibility-audit
- acme-backend.formula.yaml: extends acme-base, adds sql-injection-scan

## Tests

1. Three-level inheritance resolves correctly
2. Aspect merge order is correct
3. exclude-aspects removes parent aspect
4. Cooking org formula produces expected steps
5. Error on missing parent formula


Merge: rictus-mjw3nj1a


Merge: rictus-1767138835254

branch: polecat/rictus-1767138835254
target: main
source_issue: rictus-1767138835254
rig: gastown


Digest: mol-deacon-patrol

Patrol 19: All healthy


Digest: mol-deacon-patrol

Patrol 2: Quiet cycle, all agents healthy


Digest: mol-deacon-patrol

Patrol 48: All healthy


Digest: mol-refinery-patrol

Patrol: merged 5 branches, closed 1 already-merged (dementus). No issues.


Burn and respawn or loop

Burn and let daemon respawn, or exit if context high.

Decision point at end of patrol cycle:

If context is LOW:
- Sleep briefly (avoid tight loop)
- Return to inbox-check step

If context is HIGH:
- Write state to persistent storage
- Exit cleanly
- Let the daemon orchestrator respawn a fresh Deacon

The daemon ensures Deacon is always running:
```bash
# Daemon respawns on exit
gt daemon status
```

This enables infinite patrol duration via context-aware respawning.


gt sling: patrol spawning must use wisp storage, not main DB

**P0 Launch Blocker**

gt sling to patrol roles (witness/refinery/deacon) currently spawns patrols into the main beads database instead of wisp storage. This will pollute the permanent database with ephemeral patrol cycles.

**Root cause:**
spawnMoleculeFromProto() with IsWisp=true uses `--db .beads-wisp/beads.db`, but the patrol TEMPLATE (e.g., gt-qp2w for mol-witness-patrol) only exists in the main database. So bd mol run fails with 'no issue found'.

**The fix:**
bd mol run needs to support reading the template from the main DB while writing the spawned instance to wisp storage. This is a cross-database spawn operation.

Options:
1. Add `--template-db` flag to bd mol run (read template from here, write instance to --db)
2. Copy template to wisp DB before spawning
3. Make bd mol run automatically check main DB for templates when using wisp storage

**Workaround applied (MUST REVERT):**
Set IsWisp=false in slingToWitness/slingToRefinery/slingToDeacon patrol spawning.

**Files:**
- internal/cmd/sling.go: lines 680, 883, 1050 (IsWisp: false)
- Needs fix in bd mol run (beads repo)


Resolve external dependencies

Resolve external dependencies across rigs.

When an issue in one rig closes, any dependencies in other rigs should be notified. This enables cross-rig coordination without tight coupling.

**Step 1: Check recent closures from feed**
```bash
gt feed --since 10m --plain | grep "✓"
# Look for recently closed issues
```

**Step 2: For each closed issue, check cross-rig dependents**
```bash
bd show <closed-issue>
# Look at 'blocks' field - these are issues that were waiting on this one
# If any blocked issue is in a different rig/prefix, it may now be unblocked
```

**Step 3: Update blocked status**
For blocked issues in other rigs, the closure should automatically unblock them (beads handles this). But verify:
```bash
bd blocked
# Should no longer show the previously-blocked issue if dependency is met
```

**Cross-rig scenarios:**
- bd-xxx closes → gt-yyy that depended on it is unblocked
- External issue closes → internal convoy step can proceed
- Rig A issue closes → Rig B issue waiting on it proceeds

No manual intervention needed if dependencies are properly tracked - this step just validates the propagation occurred.


Move disk 3: C → A

Move disk 3 from peg C to peg A. (Move 908/1023)


Remove gt mail dependency on bd mail commands

Replaced bd mail send/inbox/read/ack with bd create/list/show/close. Messages are now stored as beads issues with type=message.


Digest: mol-deacon-patrol

Patrol 4: 17 procs, healthy


gt done: Require pushed branch before MR creation

gt done currently creates MR bead without verifying the branch is pushed.

## Problem
Polecat can run `gt done` with unpushed commits. MR bead references a branch that doesn't exist on remote. Work is lost when polecat is nuked.

## Fix
In done.go runDone():
```go
// Before creating MR bead
status, err := g.CheckUncommittedWork()
if status.UnpushedCommits > 0 {
    return fmt.Errorf("branch has %d unpushed commits; run 'git push' first", status.UnpushedCommits)
}
```

## Already Have
- `computeCleanupStatus()` checks this but only reports, doesn't block
- Just need to make it a hard error


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 727/1023)


CLI: gt stop --all (emergency swarm kill)

Emergency kill command for swarm operations.

## Commands

```bash
gt stop --all              # Kill ALL sessions across all rigs
gt stop --rig <name>       # Kill all sessions in one rig
gt stop --rig <name> --graceful  # Try graceful first, then force
```

## Implementation

### --all flag
1. List all tmux sessions matching gt-*
2. For each: capture final output, kill session
3. Update all polecat states to idle
4. Log all killed sessions
5. Send mail to Mayor: "Emergency stop executed"

### --rig flag
1. List sessions for specific rig
2. Same as above but scoped

### --graceful flag
1. First, try to inject "exit" command
2. Wait 5 seconds
3. If still running, force kill

## Output

```
Stopping all Gas Town sessions...
  [wyvern] Toast: captured output, killed
  [wyvern] Capable: captured output, killed
  [beads] Nux: captured output, killed

3 sessions stopped.
All polecat states set to 'idle'.
Mail sent to mayor/.
```

## Safety

- Always capture output before killing
- Update state files to reflect reality
- Log all operations to gt.log
- Warn if uncommitted changes detected (but still kill)

## Dependencies

Needs: Tmux wrapper, Session management, Polecat management


Digest: mol-deacon-patrol

Patrol cycle 42: All agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol 20: All healthy, 17 sessions


Digest: mol-deacon-patrol

Patrol 7: Routine


gt polecat status shows idle when hook_bead is set in agent bead

gt polecat status gastown/furiosa shows State: idle, Issue: (none) but the agent bead gt-gastown-polecat-furiosa has hook_bead: gt-um6q and agent_state: running. The status command isn't reading hook_bead from the agent bead correctly.


Move disk 4: C → B

Move disk 4 from peg C to peg B. (Move 216/1023)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 511/1023)


Move disk 2: C → B

Move disk 2 from peg C to peg B. (Move 810/1023)


Digest: mol-deacon-patrol

Patrol 19: All agents healthy


Digest: mol-deacon-patrol

Patrol 20: final cycle


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)


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 898/1023)


Digest: mol-deacon-patrol

Patrol 16: All healthy


implement

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


Digest: mol-deacon-patrol

Patrol cycle 9: nominal


Dogs: Deacon's Helper Workers

## Overview

Dogs are reusable workers managed by the Deacon for infrastructure and cleanup tasks.
They parallel how Polecats serve the Witness, but at town level with cross-rig scope.

## Key Concepts

- **Dogs**: Deacon-managed, reusable, infrastructure/cleanup tasks
- **Kennel**: Where dogs live (`deacon/dogs/`)
- **Multi-rig worktrees**: Dogs have worktrees into multiple rigs for cross-rig work

## Cats vs Dogs

| Aspect | Polecats | Dogs |
|--------|----------|------|
| Manager | Witness | Deacon |
| Scope | Per-rig | Town (cross-rig) |
| Lifecycle | Ephemeral | Reusable |
| Work | Features | Infrastructure |
| Location | `<rig>/polecats/` | `deacon/dogs/` |

## Implementation

### Phase 1: Dog Infrastructure
- `gt dog add/remove/list/call/status` commands
- Kennel directory structure (`~/gt/deacon/dogs/`)
- Multi-rig worktree creation
- Dog state tracking

### Phase 2: Deacon Dispatch
- Sling support for `deacon/dogs` target
- Pool management (spawn/retire logic)
- Completion mail handling

### Phase 3: Infrastructure Formulas
- mol-convoy-cleanup
- mol-dep-propagate
- mol-digest-generate

### Phase 4: Deacon Refactor
- Patrol becomes detect → dispatch
- Heavy work moves to dog slings

## Reference

- docs/patrol-system-design.md#dogs-deacons-helper-workers
- docs/PRIMING.md (Role Taxonomy)


Digest: mol-deacon-patrol

Patrol 44: All healthy


Polecat health check loop

Implement the Witness health check loop:

Every 60 seconds:
1. List active polecats (gt polecats <rig>)
2. For each polecat, check:
   - Is tmux session still alive?
   - Is there a state.json with recent update?
   - Has there been git activity recently?
3. If stuck (no activity for configurable threshold):
   - First: nudge (send message asking for status)
   - Second: escalate to Mayor
   - Third: force kill after human confirmation

This is the 'health monitor' part of Witness.


Digest: mol-deacon-patrol

Patrol 2: All healthy, no messages, quiet cycle


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.

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


mol-deacon-patrol


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 447/1023)


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.


Digest: mol-deacon-patrol

P8: all polecats exited


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 565/1023)


Phase 1.2: Daemon attachment detection

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

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

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

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

Depends: gt-rana.1


Move disk 7: A → B

Move disk 7 from peg A to peg B. (Move 64/1023)


mol-refinery-patrol

Merge queue processor patrol loop.

The Refinery is the Engineer in the engine room. You process polecat branches, merging them to main one at a time with sequential rebasing.

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

## Merge Flow

The Refinery receives MERGE_READY mail from Witnesses when polecats complete work:

```
Witness                    Refinery                      Git
   │                          │                           │
   │ MERGE_READY              │                           │
   │─────────────────────────>│                           │
   │                          │                           │
   │                    (verify branch)                   │
   │                          │ fetch & rebase            │
   │                          │──────────────────────────>│
   │                          │                           │
   │                    (run tests)                       │
   │                          │                           │
   │                    (if pass)                         │
   │                          │ merge & push              │
   │                          │──────────────────────────>│
   │                          │                           │
   │ MERGED                   │                           │
   │<─────────────────────────│                           │
   │                          │                           │
```

After successful merge, Refinery sends MERGED mail back to Witness so it can
complete cleanup (nuke the polecat worktree).


Documentation: Ephemeral Polecat Merge Workflow

Document the new rebase-as-work architecture.

## Documents to Update

### docs/understanding-gas-town.md
- Polecat lifecycle (truly ephemeral)
- MR submission as exit point

### docs/refinery-workflow.md (new or update)
- Priority scoring
- Mechanical rebase handling
- Conflict-resolution task creation

### PRIMING.md
- Update polecat section
- Add note about rebase-as-work pattern

## Key Concepts to Document
- 'Polecat done at MR submit'
- 'Conflicts are new work'
- 'Convoy age creates pressure'
- 'Priority function is deterministic'


Patrol hygiene: Witness/Refinery/Deacon inbox cleanup

## Summary
Patrol roles should clean up their inboxes as part of normal operation, not let messages accumulate.

## Witness Patrol Cleanup
- POLECAT_STARTED: archive after acknowledging
- POLECAT_DONE: archive after cleanup complete
- LIFECYCLE requests: archive after processing
- Keep only: active work, unprocessed requests

## Refinery Patrol Cleanup
- MR Ready: archive after merge/reject decision
- Swarm notices: archive after dispatch
- Keep only: pending MRs in queue

## Deacon Patrol Cleanup
- Rotate daemon.log when >10MB
- Prune state.json of dead sessions
- Archive old daemon logs (gzip, date-suffix)

## Implementation
Each patrol molecule should have a 'cleanup' phase at end of cycle.

## Related
- mol-town-shutdown (nuclear cleanup)
- mol-witness-patrol, mol-refinery-patrol, mol-deacon-patrol


test with labels


Move disk 1: C → B

Move disk 1 from peg C to peg B.


Move disk 3: A → B

Move disk 3 from peg A to peg B. (Move 556/1023)


Witness: Block nuke if polecat has unpushed work

Witness nukes polecats on MERGED signal without checking if work is actually safe to delete.

## Problem
If witness receives MERGED for polecat X, it nukes X. But:
- MERGED might be for a stale MR (already merged via different path)
- Polecat might have NEW unpushed work since the MR was created
- Race condition between merge and nuke

## Fix
Before nuke, verify:
1. Get polecat's cleanup_status from agent bead
2. If cleanup_status != 'clean', escalate to Mayor instead of nuke
3. Optionally: verify the specific commit SHA is reachable from main

## Location
internal/witness/handlers.go HandleMerged() or the witness patrol formula


Digest: mol-deacon-patrol

Patrol 29: all quiet


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

Patrol 10: quiet


CloudRun persistent connections: HTTP/2 keepalive

## Overview

Implement persistent HTTP/2 connections to keep Cloud Run containers warm.

## Problem

Cloud Run has cold start latency when scaling from 0. Persistent connections keep containers warm.

## Implementation

```go
type PersistentConnectionManager struct {
    serviceURL string
    conn       net.Conn
    client     *http2.ClientConn
    mu         sync.Mutex
    lastUsed   time.Time
    keepAlive  time.Duration
}

func (m *PersistentConnectionManager) GetConnection() (*http2.ClientConn, error) {
    m.mu.Lock()
    defer m.mu.Unlock()

    // Reuse existing connection if healthy
    if m.client != nil && m.client.CanTakeNewRequest() {
        m.lastUsed = time.Now()
        return m.client, nil
    }

    // Create new connection
    return m.dial()
}

func (m *PersistentConnectionManager) keepAliveLoop() {
    ticker := time.NewTicker(m.keepAlive / 2)
    for range ticker.C {
        m.mu.Lock()
        if time.Since(m.lastUsed) > m.keepAlive {
            // Connection idle too long, close it
            m.close()
        } else {
            // Send ping to keep alive
            m.ping()
        }
        m.mu.Unlock()
    }
}
```

## Integration with CloudRunOutpost

```go
type CloudRunOutpost struct {
    // ...existing fields...
    connMgr *PersistentConnectionManager
}

func (o *CloudRunOutpost) Spawn(...) {
    conn, err := o.connMgr.GetConnection()
    // Use connection for work dispatch
}
```

## Config

```yaml
outposts:
  - name: cloudrun-burst
    type: cloudrun
    # ...
    keep_alive: 5m  # Keep connection warm for 5 minutes
```

## Files

- `internal/cloudrun/connection.go`

## Dependencies

Depends on: gt-9a2.8 (basic CloudRunOutpost)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 121/1023)


mol-deacon-patrol


Move disk 4: C → B

Move disk 4 from peg C to peg B. (Move 600/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 413/1023)


Add GitHub CI workflow for PRs

Gas Town has no CI. Add .github/workflows/ci.yml that runs tests and linter on PRs. Reference beads repo for example.


Test Patrol Parent

Test parent for Christmas Ornament pattern


Digest: mol-deacon-patrol

Patrol #17


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 299/1023)


Digest: mol-deacon-patrol

Patrol 20: Final patrol, 11 sessions healthy, no incidents


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 695/1023)


Test: release command verification


Digest: mol-deacon-patrol

Patrol 41 complete: All agents healthy, 2 convoys in progress (Hanoi, Messaging), health pings sent, 1 idle dog


Interrupt vs Queue mail semantics

Add priority/delivery semantics to mail messages.

## Semantics

| Type | Delivery | Use Case |
|------|----------|----------|
| Interrupt | tmux send-keys | Lifecycle, URGENT, stuck detection |
| Queue | Create message only | Normal mail, status, heartbeat |

## Implementation

- `bd mail send --interrupt` uses tmux send-keys notification
- Default is queue (agent checks with `gt mail check`)
- Urgent flag on messages for interrupt delivery

## Agent Side

- `gt mail check --quiet` - non-blocking check for queued mail
- `gt mail wait` - block until mail arrives (for idle agents)
- Heartbeats become queued, agent checks at natural breakpoints


Cook patrol formulas into proto beads

Use bd cook to transform formula YAML into proto beads with proper child beads for each step.

Verify with bd mol show that protos have all children.


gt status should show runtime state, not just structure

## Problem
`gt status` shows structural info (which crews exist) but not runtime reality (which sessions are running).

## Current Output
- Shows 'Crews: [dave emma zoey]' but doesn't indicate dave is crashed
- Missing Deacon from output entirely
- Hooks shown but unclear if agents are alive

## Expected
- Show which tmux sessions are actually running
- Indicate crashed/missing sessions with warning
- Include all roles (Mayor, Deacon, Witnesses, Refineries, Crews)
- Distinguish between:
  - Structure: what COULD run
  - Runtime: what IS running

## Example Better Output
```
Agents
   mayor          ✓ running (gt-mayor)
   deacon         ✓ running (gt-deacon)

Rigs
   beads
      witness     ✓ running
      refinery    ✓ running
      crew/dave   ✗ CRASHED (session missing)
      crew/emma   ✓ running
   gastown
      witness     ✓ running
      refinery    ✓ running
      crew/max    ✗ CRASHED (session missing)
```


Workspace detection: Find() walking up directory tree

Find workspace root by walking up directory tree looking for Gas Town markers.

## Detection Logic

Walk up from current directory, looking for:
1. `config/town.json` - Primary marker (visible config dir per gt-iib)
2. `mayor/` directory at town level - Secondary marker

Stop at filesystem root if neither found.

## Interface

```go
// Find locates the town root from the given directory
func Find(startDir string) (string, error)

// FindOrError is like Find but returns a user-friendly error
func FindOrError(startDir string) (string, error)
```

## Return Values

- Success: Absolute path to town root
- Not found: Empty string + specific error
- Error: Empty string + wrapped error

## Edge Cases

- Symlinks: Follow them (use filepath.EvalSymlinks)
- Permissions: Return error if can't read directory
- Nested towns: Return nearest ancestor (shouldn't happen in practice
EOF
)


Digest: mol-deacon-patrol

Patrol 75: Routine


Witness: Handle LIFECYCLE work-merged mail

Witness should process the `LIFECYCLE: work merged` notification from Refinery.

## Implementation

1. In Witness mail processing, add handler for subject containing "LIFECYCLE: work merged"
2. Parse worker name from mail body
3. Update polecat state to `merged` (new state - see sibling task)
4. Log completion for metrics
5. Worktree is now eligible for cleanup on next gc cycle

## Acceptance
- Witness correctly parses and handles work-merged mail
- Polecat state updated to merged
- No action taken if polecat already cleaned up (idempotent)


Digest: mol-deacon-patrol

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


Consolidate configuration architecture: three-tier model

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

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

## Proposed Architecture

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 53: All healthy


Digest: mol-deacon-patrol

Patrol 11: Routine


Digest: mol-deacon-patrol

Patrol 20: Nominal - Handoff threshold reached


Outpost integration tests: Mock and E2E testing

## Overview

Integration tests for the outpost system.

## Mock Outpost

```go
type MockOutpost struct {
    name        string
    maxWorkers  int
    spawnDelay  time.Duration
    spawnError  error
    workers     []*MockWorker
}

func (o *MockOutpost) Spawn(issue string, cfg WorkerConfig) (Worker, error) {
    if o.spawnError != nil {
        return nil, o.spawnError
    }
    time.Sleep(o.spawnDelay)
    worker := &MockWorker{id: uuid.New().String(), issue: issue}
    o.workers = append(o.workers, worker)
    return worker, nil
}
```

## Unit Tests

```go
func TestOutpostManager_SelectOutpost(t *testing.T) {
    // Test policy-based selection
}

func TestOutpostManager_SpawnWithRetry(t *testing.T) {
    // Test retry logic with transient failures
}

func TestCloudRunOutpost_CostTracking(t *testing.T) {
    // Test cost calculation and caps
}
```

## Integration Tests (with mocked Cloud Run)

```go
func TestCloudRunOutpost_Integration(t *testing.T) {
    // Start mock HTTP server
    server := httptest.NewServer(mockWorkHandler())
    defer server.Close()

    outpost := NewCloudRunOutpost(OutpostConfig{
        ServiceURL: server.URL,
    })

    worker, err := outpost.Spawn("test-issue", WorkerConfig{})
    // Assert worker created, events streamed
}
```

## E2E Tests (requires real Cloud Run)

```go
// +build e2e

func TestCloudRunOutpost_E2E(t *testing.T) {
    if os.Getenv("CLOUDRUN_SERVICE_URL") == "" {
        t.Skip("CLOUDRUN_SERVICE_URL not set")
    }
    // Test against real Cloud Run service
}
```

## Files

- `internal/outpost/mock_test.go`
- `internal/outpost/manager_test.go`
- `internal/outpost/cloudrun_test.go`
- `internal/cloudrun/integration_test.go`

## Dependencies

Depends on: gt-9a2.8 (CloudRunOutpost), gt-9a2.15 (error handling)
Lower priority - can be done after implementations work.


gt session start --issue doesn't pin work to hook

When starting a polecat with --issue, the work isn't pinned to the hook:
  gt session start beads/Toast --issue bd-oxgi

After session starts, 'gt mol status' shows empty hook.

The polecat had to manually discover the work via bd ready. The --issue flag should call 'gt hook attach' or equivalent to pin the work.


Merge: nux-1767080427756

branch: polecat/nux-1767080427756
target: main
source_issue: nux-1767080427756
rig: gastown


Extend gt nudge to support channel:name syntax

Add channel support to internal/cmd/nudge.go.

CURRENT BEHAVIOR:
gt nudge <session> <message> - nudges single session

NEW BEHAVIOR:
gt nudge channel:<name> <message> - nudges all members of channel

IMPLEMENTATION:
1. Detect if target starts with 'channel:'
2. If so, extract channel name
3. Load messaging.json via config.LoadMessagingConfig
4. Look up NudgeChannels[name]
5. Resolve each member pattern to session names (use existing resolution logic)
6. Call t.NudgeSession() for each

PATTERN RESOLUTION:
- Literal: gastown/witness → session name
- Wildcards: gastown/polecats/* → expand via getAgentSessions()
- @groups: @town → expand via parseGroupAddress() patterns

FILE: internal/cmd/nudge.go
TESTS: Add TestNudgeChannel

NOTE: Look at broadcast.go for session enumeration patterns.


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 110/1023)


Deacon CLAUDE.md for patrol execution

Update Deacon role CLAUDE.md for patrol execution.

## Key Additions

### Role Definition

```markdown
## Your Role: DEACON

You are the Deacon - Gas Towns heartbeat process.
You run mol-deacon-patrol continuously.

Your job:
- Check mail for callbacks
- Spawn polecats for ready work
- Monitor rig health (basic)
- Cycle context when full
```

### Patrol Execution

```markdown
## Patrol Execution

You run mol-deacon-patrol on your hook.

On each heartbeat from the daemon:
1. Check your current step: bd hook
2. Execute that step
3. Advance: bd mol advance mol-deacon-patrol
4. If COMPLETE: restart the patrol or cycle context

The daemon keeps you alive. Your job is to run the patrol.
```

### Heartbeat Response

```markdown
## Heartbeat Response

When you see "HEARTBEAT: ..." from the daemon:
- If idle: check your hook, start/resume patrol
- If mid-step: continue working
- If waiting: the heartbeat reminds you to check state

Heartbeats are your clock tick. Use them.
```

### Context Cycling

```markdown
## Context Cycling

When context is high (>80%):
1. Write state to molecule
2. Run: gt handoff -s "Deacon cycling" -m "Context full"
3. Exit cleanly
4. Daemon respawns you
5. You wake, prime, read hook, continue
```

## File

deacon/CLAUDE.md (in town root)


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 351/1023)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 295/1023)


Digest: mol-deacon-patrol

Patrol cycle 8: all healthy


Merge: capable-mjxen9vb

branch: polecat/capable-mjxen9vb
target: main
source_issue: capable-mjxen9vb
rig: gastown
agent_bead: gt-gastown-polecat-capable


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 319/1023)


gt sling should accept raw issues, not just molecules

Currently gt sling only works with molecules. When you try to sling a raw issue:

  gt sling gt-9uy0 gastown/crew/max
  Error: invalid thing: issue not found

Options:
1. Auto-wrap issues in a simple work molecule (mol-issue-work?)
2. Create a minimal 'envelope' molecule on the fly
3. Just pin the issue directly without a molecule wrapper

The friction of needing a molecule for every piece of work discourages using the sling mechanism for ad-hoc tasks.

Related: crew workers often want to pick up an issue without formal molecule choreography.


Merge: dag-mjxpcv5v

branch: polecat/dag-mjxpcv5v
target: main
source_issue: dag-mjxpcv5v
rig: gastown
agent_bead: gt-gastown-polecat-dag


Merge: nux-1767082300311

branch: polecat/nux-1767082300311
target: main
source_issue: nux-1767082300311
rig: gastown


Digest: mol-deacon-patrol


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 965/1023)


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

Patrol 16: All healthy


Digest: mol-deacon-patrol

P5: stable


Remove shell respawn loops from witness and deacon

Currently witness and deacon use shell loops (`while true; do claude; done`) to auto-respawn when Claude exits. This bypasses the proper lifecycle architecture.

## Current Behavior
- witness.go: ensureWitnessSession() wraps Claude in a shell loop
- deacon.go: runDeaconStart() wraps Claude in a shell loop
- When Claude exits, shell automatically restarts it

## Desired Behavior
- Agents should request lifecycle changes via LIFECYCLE mail to deacon
- Daemon processes lifecycle requests and handles restarts
- No shell loops - daemon and deacon's health-scan handle respawns

## Why Change
1. Shell loops bypass state verification (requesting_cycle flag)
2. Shell loops bypass handoff mail protocol
3. Shell loops make lifecycle tracking harder
4. Daemon already has infrastructure for this

## Migration
1. Remove shell loop from witness (daemon/deacon handles restart)
2. Remove shell loop from deacon (daemon handles restart via ensureDeaconRunning)
3. Verify daemon's health check properly restarts dead agents
4. Update templates if needed

## Risk
Low - we have gt witness restart and gt deacon restart as fallbacks


Move disk 3: C → A

Move disk 3 from peg C to peg A. (Move 452/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 407/1023)


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.

## Idle Town Principle

**The Deacon should be silent/invisible when the town is healthy and idle.**

- Skip HEALTH_CHECK nudges when no active work exists
- Sleep 60+ seconds between patrol cycles (longer when idle)
- Let the feed subscription wake agents on actual events
- The daemon (10-minute heartbeat) is the safety net for dead sessions

This prevents flooding idle agents with health checks every few seconds.

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Merge: nux-mjxc8hbs

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


Digest: mol-deacon-patrol

Cycle 6


Beads schema: Add created_by field enforcement

Ensure created_by field is populated on all issue creation. Currently optional and often missing. Should default from BD_ACTOR env var. Affects: merge requests, escalations, digests.


BUG: Daemon doesn't kill zombie tmux sessions before recreating

## Problem

When the daemon detects an agent isn't running (per bead state), it tries to create a new session. But if a zombie tmux session exists (session alive, Claude dead), the create fails:

```
2026/01/02 18:18:20 Witness for gastown not running per agent bead, starting...
2026/01/02 18:18:20 Error creating witness session for gastown: session already exists
```

## Root Cause

`gt witness start` (and similar) fail if tmux session exists, even if it's a zombie. The daemon should:
1. Detect if existing session is responsive
2. Kill zombie if unresponsive
3. Create fresh session

## Current Behavior

```go
// In ensureWitnessRunning or similar:
if err := tmux.NewSession(sessionName, dir); err != nil {
    // Fails with 'session already exists'
    return err
}
```

## Expected Behavior

```go
// Pseudo-code for 'ensure running' semantics:
if sessionExists(name) {
    if !isResponsive(name) {
        killSession(name)  // Kill zombie
    } else {
        return  // Already running and healthy
    }
}
createSession(name)  // Create fresh
```

## Impact

- Dead witness/refinery stay dead indefinitely
- Daemon logs fill with 'session already exists' errors
- Town health degrades with no auto-recovery

## Solution

Add `ensureSessionFresh()` helper that:
1. Checks if session exists
2. If exists, checks if Claude is responsive (look for prompt, or check heartbeat)
3. Kills zombie sessions
4. Creates new session only if needed


Merge: furiosa-mjvtknih

branch: polecat/furiosa-mjvtknih
target: main
source_issue: furiosa-mjvtknih
rig: gastown
agent_bead: gt-gastown-polecat-furiosa


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 732/1023)


HTTP work server: gt worker serve command

## Overview

HTTP server that runs inside Cloud Run containers, accepting work requests.

## Command

```bash
gt worker serve --port 8080
```

## Implementation

```go
type WorkServer struct {
    port    int
    handler *WorkHandler
}

func (s *WorkServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    switch r.URL.Path {
    case "/work":
        s.handleWork(w, r)
    case "/health":
        s.handleHealth(w, r)
    default:
        http.NotFound(w, r)
    }
}

func (s *WorkServer) handleWork(w http.ResponseWriter, r *http.Request) {
    // 1. Parse WorkRequest
    // 2. Clone/pull repo
    // 3. Start Claude on issue
    // 4. Stream WorkEvents as NDJSON
    // 5. Return WorkResult
}
```

## Streaming Response

```go
func (s *WorkServer) streamEvents(w http.ResponseWriter, events <-chan WorkEvent) {
    flusher, _ := w.(http.Flusher)
    encoder := json.NewEncoder(w)
    for event := range events {
        encoder.Encode(event)
        flusher.Flush()
    }
}
```

## Files

- `internal/cloudrun/server.go`
- `cmd/gt/worker_serve.go` - Cobra command

## Dependencies

Depends on: gt-9a2.7 (protocol types)


Add bulk polecat remove command (gt polecat remove --all)

When decommissioning a rig, need to remove multiple polecats one at a time. A --all or --rig flag would allow: gt polecat remove --rig gastown --force


Digest: mol-deacon-patrol

Patrol 16: healthy


Campaign: Large-Scale Work Graph Execution

A Campaign is a Molecule-wrapped Epic graph ready for orchestrated execution.

## Concept

Campaign = Molecule + Epics + Dependency Graph + Execution Strategy

Key properties:
1. **Work graph**: Linked epics with dependency edges (possibly from different authors)
2. **Combinators as glue**: >>, |, wrap define bridging/shaping between epics
3. **Molecule shell**: Provides execution state, persistence across sessions
4. **Witness-aware**: Can be parallelized across polecats on independent branches
5. **Single-rig scoped**: One rig executes it (spans sessions/polecats)

## The "Maximum Speed" Model

Witness becomes a scheduler that:
- Watches campaign progress
- Identifies ready nodes (all dependencies satisfied)
- Spawns/assigns polecats to ready nodes
- Respects parallelism constraints
- Handles failures (retry? skip? escalate?)

## Where Campaign Fits in MEOW

Campaign is the convergence point where work-tracking meets workflow-execution:
- An Epic-of-Epics (work dimension)
- A Molecule (workflow dimension)

## Open Questions

1. Campaign creation UX - manual wire vs declare intent?
2. Partial completion - can you commit progress and resume?
3. Distinct entity type or molecule with type="campaign"?
4. Cross-rig campaigns - can graph span multiple rigs?

## Related

- docs/formula_evolution.md - original discussion
- gt-8tmz - molecule algebra (foundation)


Digest: mol-deacon-patrol

Patrol complete: no work, gastown refinery came online, town healthy


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.

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Merge: gt-ci84

branch: polecat/slit
target: main
source_issue: gt-ci84
rig: gastown


mol-deacon-patrol


Refinery needs manual restart/handoff mechanism

Refinery sessions can get stuck or need restart. Currently requires manual intervention. Need: 1) gt refinery restart command, 2) Refinery self-handoff on context fill, 3) Auto-recovery from stuck states.


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

Patrol 18: All healthy


Digest: mol-deacon-patrol

Patrol 10: Routine. All 3 rigs healthy. 12 polecats. 1 MQ pending.


Add GH deployment artifacts (homebrew, npm)

Add GitHub deployment artifacts to Gas Town similar to Beads setup:
- Homebrew tap/formula for gt CLI
- npm package for JavaScript/TypeScript users
- GitHub Actions workflow for releases

Reference Beads implementation for patterns.


Tmux wrapper: session operations

Wrapper for tmux session operations via subprocess.

## Interface

```go
type Tmux struct{}

func NewTmux() *Tmux

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

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

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

## Session Naming

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

## Implementation

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

## Error Handling

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

## Environment

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


GGT Command Parity: Complete gt command coverage

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

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


Digest: mol-deacon-patrol

Patrol 5: Quick cycle, all quiet


gt-gastown-polecat-testcat2

gt-gastown-polecat-testcat2

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


Digest: mol-deacon-patrol

Patrol 26: furiosa session started, all quiet


Refinery tmux status: show merge queue length

Add refinery-specific status line showing:
- MQ length (pending merges)
- Currently processing item (if any)
- Maybe: success/failure counts

Implement in runRefineryStatusLine() in internal/cmd/statusline.go


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.


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 865/1023)


Digest: mol-deacon-patrol

Patrol cycle 8: thorough check, all healthy


Create handoff beads for Witness and Refinery roles

Each patrol role needs a pinned handoff bead to track attached molecules and patrol state.

## Pattern (from Deacon)
- Title: '<role> Handoff' (e.g., 'witness Handoff', 'refinery Handoff')
- Status: pinned
- Description contains structured state

## Witness Handoff State

```yaml
attached_molecule: mol-witness-patrol
attached_at: 2025-12-24T10:00:00Z

# Nudge escalation tracking
nudges:
  toast:
    count: 2
    last: "2025-12-24T10:30:00Z"
  ace:
    count: 0
    last: null

# Polecats queued for cleanup
pending_cleanup:
  - nux  # received POLECAT_DONE, awaiting verification
```

## Refinery Handoff State

```yaml
attached_molecule: mol-refinery-patrol
attached_at: 2025-12-24T10:00:00Z

# Merge queue tracking
last_processed_branch: polecat/toast
branches_merged_this_cycle: 3
```

## Tasks
1. Create 'witness Handoff' bead in each rig's beads
2. Create 'refinery Handoff' bead in each rig's beads
3. Update Witness/Refinery startup to check handoff bead for attached work
4. Update templates to document handoff bead usage
5. Include nudge state schema for Witness
6. Include merge state schema for Refinery

## Note
These are rig-level beads (in gastown/.beads/, beads/.beads/), not town-level like deacon Handoff (in ~/gt/.beads/).

## See Also
- docs/witness-patrol-design.md - Theory of operation


Digest: mol-deacon-patrol

Patrol complete: all healthy, cleaned 2 orphan processes + 3 stale locks


Digest: mol-deacon-patrol

Patrol cycle 5: All 3 rigs healthy. No incidents.


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


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 974/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 341/1023)


gt crew add: CLAUDE.md customization leaves git dirty

When gt crew add generates a customized CLAUDE.md for crew workers, it differs from the repo version (Crew Worker Context vs Polecat Context, personalized footer). This leaves the git state 'dirty'.

Options:
1. Add CLAUDE.md to .gitignore in crew workspaces
2. Auto-commit the customized CLAUDE.md locally
3. Store crew CLAUDE.md content elsewhere (e.g., .claude/CLAUDE.md)

Current behavior is functional but 'gt crew list' shows 'Git: dirty' for new crew.

Found during: adding crew workers grip, fang, wolf


Digest: mol-deacon-patrol

Patrol cycle 73: All healthy


Merge: gt-ldk8

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


Digest: mol-deacon-patrol

Patrol complete: checked inbox (empty), scanned health (all witnesses/refineries running), no gates, no convoys, no orphans, 1 dog idle, no plugins


Digest: mol-deacon-patrol

Patrol 15 complete


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.

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


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

Patrol 4: All healthy


Digest: mol-deacon-patrol

Patrol 2: All healthy, routine


Digest: mol-deacon-patrol

Cycle 193: Nominal


gt done: Command doesn't exist but documented in polecat CLAUDE.md

The polecat CLAUDE.md documents 'gt done' as the command to signal work is ready for merge queue, but running it gives 'unknown command'. Either implement the command or update the documentation.


Epic: Refinery Engineer Autonomy

Make Refinery Engineer fully autonomous:

## Goal
Refinery can run indefinitely, processing all polecat work through merge queue, cycling sessions as needed, without human intervention.

## Key Components
1. Role prompting (CLAUDE.md, templates)
2. Handoff mechanism (pinned beads)
3. Context detection (gt prime)
4. Communication protocol (Witness, Deacon)
5. Future: Merge orchestration plugins

## Success Criteria
- Refinery starts, reads handoff, knows what to do
- Processes merges sequentially with conflict resolution
- Cycles sessions cleanly via Deacon
- Communicates results to Witness
- No work left behind


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 409/1023)


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 204/1023)


Digest: mol-deacon-patrol

Patrol 20: routine, handoff triggered


Digest: mol-deacon-patrol

Patrol 1: All clear - inbox empty, agents healthy, no orphans


Digest: mol-deacon-patrol

Patrol 6: Quiet


Merge: gt-s7t1h

branch: polecat/dag-mjxm10sv
target: main
source_issue: gt-s7t1h
rig: gastown
agent_bead: gt-mayor


Digest: mol-deacon-patrol

Patrol cycle 19: routine


Digest: mol-deacon-patrol

Patrol 3: all clear, hook fix applied


Move disk 2: C → B

Move disk 2 from peg C to peg B. (Move 750/1023)


End-of-cycle inbox hygiene

Verify inbox hygiene before ending patrol cycle.

**Step 1: Check inbox state**
```bash
gt mail inbox
```

Inbox should be EMPTY or contain only just-arrived unprocessed messages.

**Step 2: Archive any remaining processed messages**

All message types should have been archived during inbox-check processing:
- WITNESS_PING → archived after acknowledging
- HELP/Escalation → archived after handling
- LIFECYCLE → archived after processing

If any were missed:
```bash
# For each stale message found:
gt mail archive <message-id>
```

**Goal**: Inbox should have ≤2 active messages at end of cycle.
Deacon mail should flow through quickly - no accumulation.


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 429/1023)


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 105/1023)


Fix TestHasPolecat test failure in internal/session

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

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

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


bd admin compact --older-than=0 ignores the flag, uses default 30 days

When running bd admin compact --prune --older-than=0, the output says 'No expired tombstones to prune (TTL: 30 days)' - the flag value is ignored.


Show actor on pinned/status change events

Pinned events currently show no actor:

  [10:22:25] → gt-95j13 → pinned · Add tmux hotkey...

Should show who pinned it:

  [10:22:25] → gt-95j13 → pinned · Add tmux hotkey... @gastown/crew/joe

Part of epic gt-u7dxq


Digest: mol-deacon-patrol

Patrol 154: All healthy


Digest: mol-deacon-patrol

Patrol 78: Routine


Digest: mol-deacon-patrol

Patrol 17: quick pass


burn-or-loop

Squash wisp and decide: loop or cycle session.

If context low: spawn new wisp and loop
If context high: handoff and request cycle

Needs: generate-summary


Move disk 4: C → B

Move disk 4 from peg C to peg B. (Move 504/1023)


Digest: mol-deacon-patrol

Patrol 17


Plugin: plan-oracle (work decomposition)

Plugin that helps decompose epics/issues into sub-tasks. Analyzes scope, identifies dependencies, estimates complexity for parallelization, creates beads for sub-tasks with dependency links.


Test swarm epic


Digest: mol-deacon-patrol

Patrol #15: Refineries healthy. Beads 5 pending, gastown 1 pending.


gt refinery start: doesn't actually start a session

## Problem

`gt refinery start gastown` reports success but doesn't start a tmux session.

## Evidence

```
$ gt refinery start gastown
Starting refinery for gastown...
✓ Refinery started for gastown

$ tmux list-sessions | grep refinery
(nothing)

$ gt refinery status gastown
State: ○ stopped
```

## Expected

Should start a tmux session (e.g., gt-gastown-refinery) with Claude processing the merge queue.

## Related

- gt-kcee: Witness commands also need implementation
- The refinery 'start' may just be updating state.json without spawning a session


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 983/1023)


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


Molecule-based Witness Patrol

Wire up mol-witness-patrol as a tracking ledger for the Go-based witness.

## Key Insight

The molecule is NOT an executor - it's a **tracking structure**. The existing
Go code in internal/witness/manager.go continues to run the patrol loop.
The molecule instance provides visibility, audit trail, and polecat tracking.

## Current State

- Witness runs as Go code with direct patrol logic
- mol-witness-patrol and mol-polecat-arm exist as molecule definitions
- gt mol bond creates dynamic children
- No molecule tracking of actual witness operations

## Target State

1. When witness starts → instantiate mol-witness-patrol on its hook
2. When Go code discovers polecat → bond mol-polecat-arm child
3. When polecat completes/dies → close that arm issue
4. gt mol progress shows current patrol state
5. Molecule survives wisp burns via handoff bead

## Benefits

- Visibility: gt mol status gastown/witness shows active arms
- Audit: Each polecat inspection is a trackable issue
- Consistency: Same tracking model as polecats with molecules
- Progress: gt mol progress works for witness too

## Non-Goals

- NOT replacing Go code with Claude session
- NOT running molecule steps as prompts
- NOT requiring Claude for witness operation


Digest: mol-deacon-patrol

Patrol cycle 5: All agents healthy


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'