Ephemeral polecats: spawn fresh, delete on completion

## Design Decision

Switch from pooled/idle polecats to ephemeral model:
- Spawn creates fresh worktree from main
- Polecat requests shutdown when done (bottom-up)
- Witness verifies handoff, kills session, deletes worktree
- No 'idle' state - polecats exist only while working

## Rationale

1. **Git worktrees are fast** - pooling optimization is obsolete
2. **Pooling creates maintenance burden:**
   - Git stashes accumulate
   - Untracked artifacts pile up
   - Branches drift from main
   - Beads DB gets stale
3. **PGT sync problems** came from persistent branches
4. **Support infrastructure exists** - Witness, Refinery, Mayor handle continuity
5. **Simpler mental model** - polecat exists = work in progress

## Lifecycle

```
Spawn:
  gt spawn --issue <id>
  → Creates fresh worktree: git worktree add polecats/<name> -b polecat/<name>
  → Initializes beads in worktree
  → Starts session, assigns work

Working:
  Polecat does task
  → Pushes to polecat/<name> branch
  → Submits to merge queue when ready

Completion (POLECAT-INITIATED):
  Polecat runs: gt handoff
  → Verifies git state clean
  → Sends mail to Witness: "Ready for shutdown"
  → Marks itself done, waits for termination

Cleanup (WITNESS-OWNED):
  Witness receives shutdown request
  → Verifies PR merged or in queue
  → Verifies no uncommitted changes
  → Kills session: gt session stop <rig>/<polecat>
  → Deletes worktree: git worktree remove polecats/<name>
  → Deletes branch: git branch -d polecat/<name>
  → Optionally: Notifies Mayor of completion
```

## Key Insight: Bottom-Up Shutdown

**Old model (wrong)**: Top-down batch shutdown - "cancel the swarm"
**New model (right)**: Bottom-up individual shutdown - polecat requests, Witness executes

This enables streaming:
- Workers come and go continuously
- No "swarm end" to trigger cleanup
- Each worker manages its own lifecycle
- Witness is the lifecycle authority

## Implementation

1. Add `gt handoff` command for polecats to request shutdown
2. Modify gt spawn to always create fresh worktree
3. Run bd init in new worktree (beads needs initialization)
4. Add shutdown request handler to Witness
5. Witness verifies handoff, then cleans up:
   - Kill session
   - Remove worktree
   - Delete branch
6. Remove 'idle' state from polecat state machine
7. Simplify gt polecat list (only shows active)

## Impact on Other Tasks

- gt-17r (Zombie cleanup): Becomes trivial - orphan worktrees
- gt-4my (Worker health): Simpler - no idle/stuck ambiguity
- gt-f9x.5/f9x.6 (Doctor): Fewer states to validate
- gt-eu9 (Witness handoff): Witness receives polecat shutdown requests


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.


Digest: mol-deacon-patrol

Patrol cycle 62: All healthy, no issues


Digest: mol-deacon-patrol

Patrol cycle 20: all healthy, handoff


Move disk 2: C → B

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


Move disk 1: B → C

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


Move disk 3: C → A

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 2: Quick scan, all healthy, no work


Digest: mol-deacon-patrol

Cycle 5: healthy


gt-refinery-gastown

Refinery - per-rig merge queue processor for gastown.

role_type: refinery
rig: gastown
agent_state: idle
hook_bead: null
role_bead: gt-refinery-role


Formula cycle detection during cooking

Detect and error on circular extends chains during bd cook. E.g., if formula A extends B extends A, cooking should fail with clear error message pointing to the cycle.


Digest: mol-deacon-patrol

Patrol 17: Routine


gt orphans: Find lost polecat work

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

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

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

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

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


Move disk 2: A → C

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


Add gt crew rename command


Digest: mol-deacon-patrol

Patrol 19: OK


Digest: mol-deacon-patrol

Patrol 5


Move disk 1: B → C

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


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol complete: 0 callbacks, no gates, all witnesses/refineries healthy, no orphans


Digest: mol-deacon-patrol

Patrol cycle 64: All healthy


Improve looksLikeFormulaName heuristic in mol_bond

The looksLikeFormulaName() function in mol_bond.go uses simple heuristics that could have edge cases:

Current checks:
- starts with 'mol-'
- contains '.formula'
- contains path separators

Potential improvements:
- Check if operand matches issue ID format (prefix-hash pattern)
- Consider formula search paths when determining if something could be a formula
- Add --formula flag to explicitly mark an operand as a formula name

Low priority since edge cases are rare in practice.


SwarmManager: create, start, update, query operations

SwarmManager operations for creating and managing swarms.

## Interface

```go
type SwarmManager struct {
    rig    *Rig
    beads  *BeadsWrapper  // shells out to bd CLI
}

func NewSwarmManager(rig *Rig) *SwarmManager

// Lifecycle
func (m *SwarmManager) Create(epicID string, workers []string) (*Swarm, error)
func (m *SwarmManager) Start(swarmID string) error
func (m *SwarmManager) UpdateState(swarmID string, state SwarmState) error
func (m *SwarmManager) Cancel(swarmID string, reason string) error

// Queries (delegate to beads)
func (m *SwarmManager) GetSwarm(id string) (*Swarm, error)
func (m *SwarmManager) GetReadyTasks(swarmID string) ([]SwarmTask, error)
func (m *SwarmManager) GetActiveTasks(swarmID string) ([]SwarmTask, error)
func (m *SwarmManager) IsComplete(swarmID string) (bool, error)
```

## Implementation Notes

- `GetReadyTasks` wraps `bd ready --parent <epicID>`
- `IsComplete` checks if all child issues are closed
- State transitions update the epic's description or a tag field
- No separate manifest files - beads IS the source of truth


Session ended: gt-gastown-nux


Digest: mol-deacon-patrol

Patrol 4: Quiet


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 255/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.


towers-of-hanoi

AGENT EXECUTION PROTOCOL - Towers of Hanoi

PURPOSE: This is a durability proof, not computation. Steps are pre-computed.
Your job is to execute them mechanically, proving crash-recovery at scale.

EXECUTION LOOP:
1. Find current state: bd mol current <mol-id>
2. Find the next ready (unblocked) step
3. Close it: bd close <step-id>
4. Repeat until no ready steps remain

ON RESUME (after crash/restart/handoff):
- Same as fresh start. The molecule IS the state.
- Query `bd mol current <mol-id>`, continue from there.
- No memory of previous session needed.

DO:
- Close steps as fast as possible (they're trivial mechanical moves)
- Use `gt handoff` when context fills (proactive cycling)
- Trust the pre-computed solution - every move is already correct

DO NOT:
- Try to solve Hanoi yourself - moves are already computed
- Mark steps in_progress - just close them directly
- Ask for permission - this is GUPP territory, just execute
- Stop for human input - run autonomously until complete

MONITORING:
- Progress: Count closed children of the molecule
- For mega-molecules: Use convoy dashboard when available
- Completion: All steps closed = molecule complete

This proves Gas Town can execute arbitrarily long workflows with
nondeterministic idempotence - different sessions, same outcome.


Merge: dementus-1767087772272

branch: polecat/dementus-1767087772272
target: main
source_issue: dementus-1767087772272
rig: gastown


Mail system: JSONL inbox, delivery, tmux injection

Refactor mail system to wrap bd mail commands.

## Status

Current implementation uses JSONL files directly. Now that Beads mail is available (gt-r01 closed), refactor to use bd mail as the backend.

## Implementation

Replace internal/mail/* with thin wrappers around bd CLI:

```go
// Send wraps: bd mail send <to> -s <subject> -m <body>
func (r *Router) Send(msg *Message) error

// List wraps: bd mail inbox --json
func (m *Mailbox) List() ([]*Message, error)

// Get wraps: bd mail read <id> --json
func (m *Mailbox) Get(id string) (*Message, error)

// MarkRead wraps: bd mail ack <id>
func (m *Mailbox) MarkRead(id string) error
```

## Address Translation

GGT addresses → Beads recipients:
- `mayor/` → `mayor`
- `<rig>/refinery` → `<rig>-refinery`
- `<rig>/<polecat>` → `<rig>-<polecat>`

## Tmux Notification

Keep the tmux injection for --notify flag. After bd mail send, optionally inject notification into tmux session.

## Migration

No migration needed - bd mail creates messages as beads issues with type=message. Old JSONL inboxes can be ignored or cleaned up.

## Dependencies

- gt-r01: CLOSED (Beads mail available)
- gt-u1j.4: Tmux wrapper (for notifications)


Move disk 5: C → A

Move disk 5 from peg C to peg A. (Move 368/1023)


Merge: rictus-mjxofiub

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


Merge: furiosa-mjxlt6tk

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


Day 3.0: Document mail protocol contracts

Document the formal mail protocol for Gas Town agent coordination.

Mail Types:

**POLECAT_DONE** (polecat → witness)
```
Subject: POLECAT_DONE: <name>
Body: {"issue": "gt-xyz", "status": "complete|failed", "notes": "..."}
```

**MERGE_READY** (witness → refinery)
```
Subject: MERGE_READY: <branch>
Body: {"worker": "nux", "issue": "gt-xyz", "branch": "polecat/nux/gt-xyz"}
```

**MERGED** (refinery → witness)
```
Subject: MERGED: <branch>
Body: {"issue": "gt-xyz", "sha": "abc123", "worker": "nux"}
```

**LIFECYCLE:Shutdown/Cycle/Restart** (agent → deacon/)
```
Subject: LIFECYCLE:Shutdown
Body: {"action": "shutdown"}
```

**HELP** (polecat → witness → mayor)
```
Subject: HELP: <brief>
Body: {"issue": "gt-xyz", "problem": "...", "context": "..."}
```

Create: docs/mail-protocol.md


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: gt-fpv2p

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


test message


gt-gastown-polecat-ace

gt-gastown-polecat-ace

role_type: polecat
rig: gastown
agent_state: done
hook_bead: null
role_bead: gt-polecat-role
cleanup_status: has_uncommitted
active_mr: gt-kwnj1
notification_level: null


Add live polling and updates

Implement live polling (500ms default) for activity updates. Merge new events into view without flickering. Show connection status indicator. Handle daemon disconnects gracefully.


Digest: mol-deacon-patrol

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


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.


Self-mail should suppress tmux notification

When sending mail to yourself (e.g., mayor sending to mayor/), the tmux notification shouldn't fire.

**Rationale:**
- Self-mail is intended for future-you (next session handoff)
- Present-you just sent it, so you already know about it
- The notification is redundant/confusing in this case

**Fix:**
Suppress tmux notification when sender == recipient address.


Move disk 1: C → A

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 7: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol #10: Stable


Merge: gt-5af.5

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 9: all healthy


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 13: Routine


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol #20: Stable, handoff threshold reached


Merge: cheedo-1767074334708

attached_args: Code review

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


Digest: mol-deacon-patrol

Patrol 3: all healthy


gt rig reset --stale: Clear orphaned in_progress items

Reset in_progress issues when their assigned agent no longer exists.

## Problem
When polecats die without cleanup, their issues remain in_progress forever.
Need a way to bulk-reset these orphaned items.

## Command
```bash
gt rig reset --stale [--dry-run]
```

## Logic
For each in_progress issue in rig:
1. Parse assignee (e.g., "gastown/furiosa")
2. Map to tmux session name (gt-gastown-furiosa)
3. If session does NOT exist:
   - Reset status to "open"
   - Clear assignee
4. Exception: skip crew/* assignees (persistent identities)
   OR check if crew tmux session exists

## Output
```
Resetting stale work in gastown:
  gt-abc: gastown/furiosa (no session) → open
  gt-def: gastown/nux (no session) → open
  Skipped: gt-xyz: gastown/crew/max (persistent)
Reset 2 issues, skipped 1
```

## Related
- gt-2kz: CLI cleanup commands for stale state
- gt-rdmw: orphan-check in deacon patrol
- gt-orphans command (list orphaned molecules)


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

Patrol 12: All healthy


Move disk 1: A → B

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


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

Patrol 4: quiet


Merge: slit-mjw18vx8

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


HOP: Skill vectors on work items

Add skill embeddings to work items for capability-based matching. See ~/ai/stevey-gastown/hop/CONTEXT.md. Post-v0.1 work.


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


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 653/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.


mol-deacon-patrol


Move disk 1: C → A

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


Check convoy completion

Check convoy completion status.

Convoys are coordination beads that track multiple issues across rigs. When all tracked issues close, the convoy auto-closes.

**Step 1: Find open convoys**
```bash
bd list --type=convoy --status=open
```

**Step 2: For each open convoy, check tracked issues**
```bash
bd show <convoy-id>
# Look for 'tracks' or 'dependencies' field listing tracked issues
```

**Step 3: If all tracked issues are closed, close the convoy**
```bash
# Check each tracked issue
for issue in tracked_issues:
    bd show <issue-id>
    # If status is open/in_progress, convoy stays open
    # If all are closed (completed, wontfix, etc.), convoy is complete

# Close convoy when all tracked issues are done
bd close <convoy-id> --reason "All tracked issues completed"
```

**Note**: Convoys support cross-prefix tracking (e.g., hq-* convoy can track gt-*, bd-* issues). Use full IDs when checking.


Digest: mol-deacon-patrol

Patrol 20: all healthy, new polecats spawning


Digest: mol-deacon-patrol

Patrol 12: quiet


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 1: All agents healthy (Mayor, 2 Witnesses, 2 Refineries), no callbacks, no orphans


Digest: mol-deacon-patrol

Patrol 1: All 3 rigs healthy, 12 polecats active, no zombies, no orphans, inbox clear


Use atomic write pattern for state files

attached_args: Atomic write pattern for state files

Prevent data loss from concurrent state file writes using atomic write pattern.

## Files to modify
- internal/witness/manager.go
- internal/refinery/manager.go
- internal/crew/manager.go
- internal/swarm/manager.go

## Problem
State is saved directly to file - if process crashes mid-write, file corrupts.

## Implementation
Replace direct writes with atomic pattern:
```go
func atomicWriteJSON(path string, v interface{}) error {
    data, err := json.MarshalIndent(v, "", "  ")
    if err != nil {
        return err
    }
    tmpFile := path + ".tmp"
    if err := os.WriteFile(tmpFile, data, 0644); err != nil {
        return err
    }
    return os.Rename(tmpFile, path)  // Atomic on POSIX
}
```

## Acceptance criteria
- [ ] atomicWriteJSON helper created (in internal/util or similar)
- [ ] All 4 manager saveState methods use atomic writes
- [ ] .tmp files cleaned up on success
- [ ] go test ./... passes
- [ ] Manual test: state files survive kill -9


working

Actively working. Monitor for stuck.

The polecat is processing its assigned issue ({{issue}}).
Monitor via peek. Watch for:
- Progress on commits
- Status updates in beads
- SHUTDOWN mail when done

Wait for SHUTDOWN signal from the polecat.
Variables: {{polecat}}, {{issue}}


Digest: mol-deacon-patrol

Patrol 20: Routine - handoff threshold reached


Witness emits activity events

Witness emits events to activity stream for patrol activity:

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

This replaces stats tracking in .runtime/witness.json


Move disk 2: A → C

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


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.


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 931/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 1: C → A

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


Swarm learning: Session cleanup missing from swarm workflow

## Problem

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

## What Should Happen

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

## GGT Components

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

## Recommendation

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

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


Digest: mol-deacon-patrol

Patrol 15: quiet


gt swarm dispatch command not working

The "gt swarm dispatch" command shown in help does not work as expected.

**Observed:**
```
$ gt swarm dispatch bd-784c
[prints help text instead of dispatching]
```

**Expected:**
Should dispatch the next ready task from the epic to an available worker.

**Workaround:**
Had to manually use "gt sling <issue> <polecat>" for each task dispatch.

**Impact:**
- Manual task dispatch defeats swarm automation
- Coordinator has to track which tasks are ready and which polecats are free

**Suggestion:**
Implement or fix "gt swarm dispatch" to:
1. Find next unassigned task in epic
2. Find idle polecat in swarm
3. Sling task to polecat automatically

(Moved from bd-kp9y)


Overseer inbox for strategic notifications

New address overseer/ for strategic notifications.

Receives:
- Convoy completions
- Cross-rig dependency resolutions
- Escalations from Deacon
- Daily digests (optional)

Separate from operational mail - this is the executive dashboard.

Related: hq-7h8jx (Convoy System epic in town beads)


Merge: rictus-1766959789036

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


Digest: mol-deacon-patrol

Patrol cycle 3: All healthy. 3 rigs responding.


CLI: spawn command

High-level command to spawn a polecat with work assignment.

## Command

```
gt spawn <rig>/<polecat> --issue <id>
gt spawn <rig> --issue <id>  # auto-select available polecat
gt spawn <rig>/<polecat> -m "Work on X"  # free-form task
```

## What It Does

1. Select or create polecat
2. Ensure polecat is in idle/active state
3. Assign the issue (update beads, set polecat state)
4. Start session (gt session start)
5. Inject initial context

## Options

- `--issue <id>`: Beads issue to assign
- `-m "message"`: Free-form work description
- `--create`: Create polecat if it does not exist
- `--no-start`: Assign work but do not start session

## Auto-Select Logic

If polecat not specified:
1. Look for idle polecats in rig
2. Prefer ones that worked on similar issues before
3. If none available, fail (or create if --create)

## Initial Context

Injects into session:
```
[SPAWN] You have been assigned: <issue-title>
Issue: <id>
Priority: <priority>

<description>

Work on this issue. Signal DONE when complete.
```

## Implementation

Orchestrates PolecatManager + SessionManager + Beads:
```go
func Spawn(rig, polecat, issue string, opts SpawnOptions) error
```


Digest: mol-deacon-patrol

Patrol 9: Nominal


Digest: mol-deacon-patrol

Cycle 292: All healthy, no incidents


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 6: All healthy, no messages


Move disk 1: C → A

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


Move disk 1: A → B

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


Async Coordination Gates

Agents wait for external events without polling.

## Problem
Agents cannot wait for external conditions (CI completion, human approval, timers) without wasteful polling or losing state on handoff.

## Requirements
- Gate issue type in beads (type=gate)
- bd gate create --await timer:5m / gh:run:123 / human:approve / mail:pattern
- Deacon evaluates pending gates each patrol cycle
- Agents park work on gate, resume when condition met
- Gate timeout and notification

## Gate Types
- timer:<duration> - Simple delay (5m, 1h, 24h)
- gh:run:<id> - GitHub Actions run completion
- gh:pr:<id> - PR merged/closed
- human:<prompt> - Human approval required
- mail:<pattern> - Wait for mail matching pattern

## Success Criteria
- Agent can create gate and suspend work
- Deacon wakes agent when gate condition met
- Gates survive session cycling

Consolidates gt-31eg. Parallel work with no dependencies.


Digest: mol-deacon-patrol

Patrol #2: Routine - all 6 agents healthy


Digest: mol-deacon-patrol

Patrol 27: all polecats working, jack session started


Add sovereignty tier to entity model

Add SovereigntyTier to the entity model. This determines what identity information
is revealed and to whom.

**Location**: beads repo, `internal/types/types.go`

**Changes required**:

1. Add SovereigntyTier type and constants:
```go
type SovereigntyTier string

const (
    TierPublic         SovereigntyTier = "public"         // Full legal identity, full visibility
    TierOrganizational SovereigntyTier = "organizational" // Known to org, private outside
    TierPseudonymous   SovereigntyTier = "pseudonymous"   // KYC verified, operates under handle
    TierAnonymous      SovereigntyTier = "anonymous"      // Cryptographic identity only
)
```

2. Add field to EntityRef:
```go
type EntityRef struct {
    // ... existing fields ...
    SovereigntyTier SovereigntyTier `json:"sovereignty_tier,omitempty"`
}
```

3. Add IsValid() method to SovereigntyTier

4. Update ComputeContentHash to include sovereignty tier

**Acceptance criteria**:
1. SovereigntyTier type with 4 values defined
2. EntityRef has optional sovereignty_tier field
3. Empty/missing tier defaults to "public" (backward compatible)
4. Content hash includes sovereignty tier
5. Tests pass


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 10: quiet


Digest: mol-deacon-patrol

Patrol 17: quiet


Crew worker beads-dave in gastown - human-managed persistent workspace.

role_type: crew
rig: gastown
agent_state: idle
hook_bead: null
role_bead: gt-crew-role
cleanup_status: null


Digest: mol-deacon-patrol

Cycle 9: quiet


Digest: mol-deacon-patrol

Patrol 18: Mayor OK, 11 sessions


CLI: gt swarm commands (create, status, list, land)

CLI commands for swarm management.

## Commands

### gt swarm create
Create a new swarm in a rig.

```
gt swarm create <rig> --title "Fix all P1 bugs" \
  --task gt-abc --task gt-def \
  --worker Toast --worker Nux
```

Options:
- --title: Swarm title (required)
- --task: Beads issue IDs to include (repeatable)
- --worker: Polecat names (repeatable, or --workers=3 to auto-assign)
- --start: Start swarm immediately after creation

### gt swarm status <swarm-id>
Show swarm status and progress.

Output:
- Swarm metadata (title, created, workers)
- Task status (pending/in_progress/completed/merged)
- Integration branch status
- Overall progress percentage

### gt swarm list [rig]
List swarms, optionally filtered by rig or status.

```
gt swarm list --status=active
gt swarm list gastown --status=landed
```

### gt swarm land <swarm-id>
Trigger manual landing (normally automatic).

### gt swarm cancel <swarm-id>
Cancel a swarm in progress.

## Output Format

Support --json for machine-readable output.

## Dependencies

Needs: gt-kmn.1 (types), gt-kmn.2 (manager)


Digest: mol-deacon-patrol

Patrol 12: All healthy, no messages


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

Patrol 14


Merge: dementus-1767140140908

branch: polecat/dementus-1767140140908
target: main
source_issue: dementus-1767140140908
rig: gastown


Digest: mol-deacon-patrol

Cycle 8: quiet


Digest: mol-deacon-patrol

Patrol cycle 14: All agents healthy


Digest: mol-deacon-patrol

Patrol 8: Routine


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 2: 1 mail archived, all agents healthy, 1 orphan fixed


Digest: mol-deacon-patrol

Patrol 154 complete


Digest: mol-deacon-patrol

Patrol 17: All clear


Digest: mol-deacon-patrol

Patrol 17: routine


Digest: mol-deacon-patrol

Cycle 293: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol 11: Quick cycle, all quiet


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.


Update templates with molecule navigation workflow

Update all agent templates to use new molecule navigation commands.

## Commands to integrate
- bd mol current: orientation after startup/handoff (bd-sal9)
- bd close --continue: seamless step transitions (bd-ieyy)

## Templates to update

### prompts/roles/polecat.md
- Add bd mol current to 'Finding Your Work' section
- Replace manual 3-command dance with bd close --continue
- Update 'Working Through Steps' section

### prompts/roles/crew.md
- Add molecule navigation to workflow section
- Show bd mol current for session startup

### prompts/roles/refinery.md
- Update patrol step transitions to use --continue

### prompts/roles/witness.md
- Update patrol step transitions to use --continue

### prompts/roles/deacon.md
- Update patrol step transitions to use --continue

## Key message
The Propulsion Principle: close a step, immediately get handed the next.
No friction, no forgetting, no 3-command dance.

## Blocked by (Beads features)
- bd-sal9: bd mol current
- bd-ieyy: bd close --continue

BLOCKED 2025-12-23 00:17: Waiting for beads features (bd mol current, bd close --continue) to be implemented. Notified mayor.


Test4

test4 body


Move disk 2: A → C

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol


Test Patrol Parent

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

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

Original description:
Test parent for Christmas Ornament pattern


Test actor display


Move disk 1: A → B

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


Move disk 2: C → B

Move disk 2 from peg C to peg B. (Move 546/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 5: C → A

Move disk 5 from peg C to peg A. (Move 752/1023)


Include session ID in PropulsionNudge for /resume picker


Digest: mol-deacon-patrol

Patrol 2: inbox clear, all agents healthy


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 20: quiet, handoff threshold reached


File locking for concurrent access

Add file locking for concurrent access safety.

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

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

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

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

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

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

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

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

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

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


implement

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

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

Depends: load-context


Digest: mol-deacon-patrol

Patrol 4: stable


Merge: beads-2nh

branch: fix/spawn-beads-path
target: main
source_issue: beads-2nh
rig: gastown


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 155 complete


Define Engineer as the Refinery agent role

Clarify the distinction:

- **Refinery** = place/module/directory/workspace
  - `<rig>/refinery/` directory structure
  - `gt refinery start/stop/status` commands
  - tmux session name: `refinery` or `<rig>-refinery`

- **Engineer** = role/agent who works in the Refinery
  - CLAUDE.md prompting: "You are an Engineer..."
  - Documentation: "The Engineer processes merge requests..."
  - Mail address: `<rig>/engineer` (or `<rig>/refinery`?)

Updates needed:
- Add Engineer role description to docs
- Update CLAUDE.md templates for refinery agents
- Keep `gt refinery` commands as-is (they manage the place)
- Internal code stays `internal/refinery/` (the module)

Future consideration: Multiple Engineers in one Refinery for parallel merge processing.


Merge: rictus-mjw3nj1a

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


Run the test suite.

Run the test suite.

```bash
go test ./...
```

Track results: pass count, fail count, specific failures.

instantiated_from: mol-refinery-patrol
step: run-tests


Merge: rictus-mjtlq9xg

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


Convoy list UI: numbered shortcuts + expandable tree view

Improve gt convoy list UI:

1. Add numbered shortcuts so users can type 'gt convoy status 1' instead of full ID
2. Consider charmbracelet TUI (bubbletea/gum/lipgloss) for expandable tree view
3. Design decision: simple numbered list vs interactive TUI vs hybrid

Current output shows convoy IDs that are hard to type:
  🚚 hq-cv-7x3ig: Witness nuke fix ●
  🚚 hq-cv-eyxnc: Hanoi Demo Launch Prep ●


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 6: All healthy


Witness Plugin System

Patrol extensions via molecule bonding.

## Core Insight

Plugins ARE molecules. No separate format needed.

## How It Works

```
mol-witness-patrol
    │
    ├── survey-workers
    │
    ├── plugin-run ←── bonds registered plugin molecules
    │       │
    │       ├── mol-mood-check (if registered)
    │       ├── mol-security-scan (if registered)
    │       └── mol-custom-X (user-installed)
    │
    └── aggregate (WaitsFor: all-children)
```

## Plugin Molecule Structure

A plugin is just a molecule proto with specific labels:

```json
{
  "id": "mol-mood-check",
  "title": "Polecat Mood Check",
  "description": "Assess polecat emotional state from output. Vars: {{polecat_name}}, {{captured_output}}",
  "labels": ["template", "plugin", "witness", "tier:haiku"],
  "issue_type": "task"
}
```

Labels encode metadata:
- `plugin` - marks as bondable plugin
- `witness` / `deacon` / `refinery` - which patrol can use it
- `tier:haiku` / `tier:sonnet` - model tier hint

## Registration

Plugins registered in rig config or molecules.jsonl:

```bash
# Install from Mol Mall
bd mol install mol-mood-check

# Or add to ~/.beads/molecules.jsonl manually
```

## Execution

The `plugin-run` step in patrol:

```bash
# For each registered plugin molecule matching this patrol:
bd mol bond mol-mood-check $PATROL_WISP \
  --ref mood-{{polecat_name}} \
  --var polecat_name=$POLECAT \
  --var captured_output="$OUTPUT"
```

## CLI

- `bd mol list --label plugin` - List available plugins
- `bd mol install <id>` - Install from Mol Mall
- `gt patrol plugins <role>` - Show plugins for a patrol role

## Benefits

- No YAML schema to maintain
- No separate plugin loading code
- Plugins are versioned, synced, auditable (they are beads)
- Distribution via Mol Mall (molecules.jsonl registry)
- Same {{var}} substitution as all molecules


Move disk 2: C → B

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


Witness cleanup leaves worktree behind

When witness processes POLECAT_DONE:
- Session is killed ✓
- Work is merged ✓
- Worktree is NOT removed ✗

Dementus example: session 'not running', but /Users/stevey/gt/gastown/polecats/dementus still exists.

Expected: gt polecat nuke equivalent - full cleanup including worktree deletion.


Digest: mol-deacon-patrol

Patrol 7: nominal


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


Add GitHub issue/PR templates

Add .github/ISSUE_TEMPLATE/ with bug and feature templates. Add .github/PULL_REQUEST_TEMPLATE.md. Reference beads repo for examples.


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


Cross-rig worktree support for crew

Enable crew workers to work on other rigs without losing identity.

**Problem**: When gastown/crew/joe needs to fix a beads bug, where do they work?
Current options are all problematic: mayor's rig (coordination, not coding), random
crew clone (conflicts), community repo (file locks), dogs (wrong abstraction).

**Solution**: Crew creates worktrees in target rigs with predictable paths.

Directory structure:
```
~/gt/<target-rig>/crew/<source-rig>-<name>/
~/gt/beads/crew/gastown-joe/     # joe from gastown working on beads
~/gt/gastown/crew/beads-wolf/    # wolf from beads working on gastown
```

Key principles:
- Identity preserved: BD_ACTOR stays gastown/crew/joe
- No conflicts: Each crew has own worktree
- No indirection: Direct work, no delegation to dogs
- Persistent: Worktree survives sessions (matches crew lifecycle)
- Dogs remain for Deacon's infrastructure work only

Commands:
- gt worktree <rig> - Create/enter worktree for rig
- gt worktree list - Show your worktrees
- gt worktree remove <rig> - Clean up worktree


Digest: mol-deacon-patrol

Patrol cycle 16


Move disk 3: B → C

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


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


Timed Beads: Scheduled recurring work

## Summary

Timed beads wake up periodically and get injected into the ready queue by the daemon.

## Schema Extension

```yaml
id: gt-weekly-sync
type: task  # or sentinel
schedule: "0 9 * * 1"  # cron: Monday 9am
# OR
interval: 24h          # every 24 hours
tier: haiku            # cheap model for routine checks
next_run: 2025-12-20T09:00:00Z
```

## Daemon Integration

Daemon heartbeat loop:
1. Check timed beads where `next_run <= now`
2. For each due bead:
   - Inject into ready queue (set status to open if needed)
   - Update `next_run` based on schedule/interval
3. Witnesses pick up work via `bd ready`

## Use Cases

- Weekly team sync reminders
- Daily health checks
- Periodic cleanup tasks
- Scheduled reports

## Interaction with Pinned Beads

A pinned bead can be timed - it wakes up periodically but never closes.
This is how you model "background services" in Gas Town.


Inline step expansion (Step.Expand field)

Step.Expand and Step.ExpandVars fields exist in schema but are not implemented.

## Current State

Steps can declare inline expansion:

    steps:
      - id: design
        expand: rule-of-five
        expand_vars:
          iterations: 3

This is more convenient than compose.expand for single-step expansions.

## Difference from compose.expand

- compose.expand: Centralized, applies after all steps parsed
- Step.Expand: Inline, step declares its own expansion

## Implementation

1. During cooking, detect steps with Expand field
2. Load referenced expansion formula
3. Replace step with expanded template (like compose.expand)
4. Pass ExpandVars as variable overrides
5. Handle recursion depth (reuse DefaultMaxExpansionDepth)

## Files

- internal/formula/types.go: Step.Expand, Step.ExpandVars (already defined)
- internal/formula/expand.go: Add inline expansion handling
- internal/formula/expand_test.go: Add test cases

## Depends On

- gt-8tmz.34 (var overrides) should be done first


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 559/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.


Merge: capable-1767074974673

branch: polecat/capable-1767074974673
target: main
source_issue: capable-1767074974673
rig: gastown


Evaluate pending async gates

Evaluate pending async gates.

Gates are async coordination primitives that block until conditions are met.
The Deacon is responsible for monitoring gates and closing them when ready.

**Timer gates** (await_type: timer):
Check if elapsed time since creation exceeds the timeout duration.

```bash
# List all open gates
bd gate list --json

# For each timer gate, check if elapsed:
# - CreatedAt + Timeout < Now → gate is ready to close
# - Close with: bd gate close <id> --reason "Timer elapsed"
```

**GitHub gates** (await_type: gh:run, gh:pr) - handled in separate step.

**Human/Mail gates** - require external input, skip here.

After closing a gate, the Waiters field contains mail addresses to notify.
Send a brief notification to each waiter that the gate has cleared.


Digest: mol-deacon-patrol

Patrol 10


Digest: mol-deacon-patrol

Patrol 12: All clear


Design mol-ready-work patrol for crew workers

## Summary

Design and implement a protomolecule (mol-ready-work) that enables crew workers to autonomously work through backlogs when the overseer is away. This replaces the normal "await instructions" patrol step with productive backlog processing.

## Context

Crew workers like dave/joe are persistent, user-managed agents. Currently their patrol loop has an "await instructions" step that idles. We want an alternative: sling mol-ready-work at them and they crank through backlogs until:
- The overseer interrupts with new instructions
- Context fills up (request handoff)
- Backlogs are empty

## Backlogs (Priority Order)

1. **Open PRs** - Review/merge pending pull requests
2. **Untriaged GH issues** - New issues needing triage
3. **Open beads work** - bd ready items (unblocked issues)
4. **Triaged GH issues** - Bugs/features to implement

## Key Features

### ROI-Based Selection
Instead of strict priority, agent applies ROI heuristic:
- Size estimate (fits in remaining context?)
- Achievability (has all needed info?)
- Impact (priority + type weight)
- Pick highest-value achievable item

### Context Management
- Check token usage after each work item
- Request handoff before running out
- Leave clear handoff notes (mail to self)
- Next session picks up the patrol

### Patrol Loop Structure
```
orient → scan-backlogs → select-work → execute-work → check-context → (loop or handoff)
```

## Design Questions

1. How does gt sling work? Does it exist?
2. How does this interact with the normal crew patrol?
3. Should the molecule go in Gas Town catalog or per-rig?
4. How does bonding work for discovered work during execution?
5. Should this be a wisp (ephemeral) or mol (persistent)?

## Acceptance Criteria

- [ ] mol-ready-work protomolecule defined in catalog
- [ ] gt sling command implemented (or existing mechanism documented)
- [ ] Context-checking step works with agent token awareness
- [ ] Handoff mechanism integrates with gt mail
- [ ] Documentation for crew workers on using the patrol


Digest: mol-deacon-patrol

Patrol cycle 13: routine


Digest: mol-deacon-patrol

Patrol 86: All healthy


MR: gt-svi.1 (polecat/Furiosa)

branch: polecat/Furiosa
target: main
source_issue: gt-svi.1


Mayor handoff mail template

Add MAYOR_HANDOFF mail template to templates.py.

## Template Function

def mayor_handoff(
    active_swarms: List[SwarmStatus],
    rig_status: Dict[str, RigStatus],
    pending_escalations: List[Escalation],
    in_flight_decisions: List[Decision],
    recent_actions: List[str],
    delegated_work: List[DelegatedItem],
    user_requests: List[str],
    next_steps: List[str],
    warnings: Optional[str] = None,
    session_duration: Optional[str] = None,
) -> Message:
    metadata = {
        'template': 'MAYOR_HANDOFF',
        'timestamp': datetime.utcnow().isoformat(),
        'session_duration': session_duration,
        'active_swarm_count': len(active_swarms),
        'pending_escalation_count': len(pending_escalations),
    }
    # ... format sections ...
    return Message.create(
        sender='mayor/',
        recipient='mayor/',
        subject='Session Handoff',
        body=body,
        priority='high',
    )

## Metadata Fields

- template: MAYOR_HANDOFF
- timestamp: ISO format
- session_duration: Human readable
- active_swarm_count: Number of active swarms
- pending_escalation_count: Number of escalations

## Mail Priority

Use priority='high' to ensure handoff is seen on startup.


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 20: All 6 agents healthy, 4 polecats active, refinery queues processing


Digest: mol-deacon-patrol

Patrol 18: quick pass


Polecat cleanup should refuse to lose uncommitted work

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

## Current Problem

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

## Desired Behavior

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

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

## Implementation

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

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

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

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

    return nil
}
```

## Affected Commands

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


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

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


Move disk 1: C → A

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


Move disk 1: C → A

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


Move disk 4: A → C

Move disk 4 from peg A to peg C. (Move 392/1023)


Move disk 1: B → C

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


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 60 seconds minimum** before next patrol cycle
- If town is idle (no in_progress work), sleep longer (2-5 minutes)
- Return to inbox-check step

**Why longer sleep?**
- Idle agents should not be disturbed
- Health checks every few seconds flood inboxes and waste context
- The daemon (10-minute heartbeat) is the safety net for dead sessions
- Active work triggers feed events, which wake agents naturally

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.


Refactor formula transformation pipeline to shared helper

The formula transformation pipeline (control flow, advice, expansions, aspects) is duplicated between cook.go and mol_bond.go. Should be extracted to a shared function in the formula package.

Current duplication in:
- cmd/bd/cook.go:96-136
- cmd/bd/mol_bond.go:598-633

Suggested approach:
- Add formula.Transform(resolved *Formula, parser *Parser) (*Formula, error)
- Handles all transformation steps in order
- Both cook.go and mol_bond.go call this single function


Town root .beads has schema mismatch with bd

The .beads directory at town root (/Users/stevey/gt/.beads) has an incompatible schema:

```
Error: failed to open database: failed to initialize schema: sqlite3: SQL logic error: no such column: thread_id
```

Meanwhile, gastown/.beads (symlinked to mayor/rig/.beads) works fine.

## Impact

- gt mail inbox fails at town root
- gt handoff sends mail to broken db
- Daemon can't check its inbox

## Options

1. Delete town root .beads/beads.db and let it recreate
2. Symlink town root .beads to gastown/.beads
3. Run schema migration on existing db

## Root Cause

Likely a beads version upgrade that added thread_id column, but the town root db was created before that.


Move disk 1: C → A

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


Move disk 3: B → C

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


Polecats should not push branches to remote

## Current Behavior

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

## Desired Behavior

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

## Benefits

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

## Trade-offs

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

## Implementation

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


Move disk 4: A → C

Move disk 4 from peg A to peg C. (Move 104/1023)


Digest: mol-deacon-patrol

Patrol 11: all healthy


Digest: mol-deacon-patrol

Patrol #18: Quick cycle, all quiet.


Digest: mol-deacon-patrol

Patrol 6


Polecat sessions terminate unexpectedly during work

During swarm bd-784c, polecat sessions (Toast, Nux) terminated mid-task without completing their work.

**Observed:**
- Polecats were actively working (edits in progress, tests running)
- Sessions suddenly showed 'not running' in gt polecat status
- tmux sessions existed but were empty/reset
- Work was partially complete (some commits made, issue still open)

**Impact:**
- Lost work progress
- Required manual intervention to restart
- Unclear if work was saved/committed

**Suggestion:**
- Add session health monitoring
- Auto-restart on unexpected termination
- Log session exit reasons


Digest: mol-deacon-patrol

Patrol cycle 25: All healthy, no incidents


Move disk 1: C → A

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


Move disk 1: C → A

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


gt spawn beads sync warning is misleading for redirect-based polecats

## Problem

When spawning a polecat, gt spawn shows a warning:
```
Warning: beads sync: exit status 1
```

This is misleading because polecats using the redirect architecture (`.beads/redirect`) share the canonical database at `mayor/rig/.beads/beads.db`. The 'stale beads' indicated by the warning is just git branch divergence (main vs beads-sync), not actual data staleness.

## Expected Behavior

gt spawn should either:
1. Skip the beads sync check for polecats using redirects (they share the canonical DB)
2. Or provide a clearer message like 'beads redirect active, using shared database'

## Reproduction

```bash
gt spawn --issue gt-xxx --rig gastown --create
# Shows 'Warning: beads sync: exit status 1' even though beads are current
```

## Root Cause

spawn.go calls beads sync and treats any non-zero exit as a warning. But with redirects, the polecat doesn't need its own beads - it uses the canonical source via the redirect chain:
```
polecat/.beads/redirect -> ../../.beads -> gastown/.beads/redirect -> mayor/rig/.beads
```

## Fix Options

1. Check for .beads/redirect before calling sync
2. Have bd sync return 0 when redirect is present
3. Suppress the warning in spawn when redirect exists


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy


attached_args: Remove os.Exit calls from Cobra RunE handlers

Replace os.Exit() calls with proper error returns in Cobra commands.

## Files to modify
- internal/cmd/mail.go (lines 546, 554, 561, 808-812)
- Any other files with os.Exit in RunE

## Problem
Some RunE handlers call os.Exit() directly:
```go
RunE: func(cmd *cobra.Command, args []string) error {
    ...
    os.Exit(1)  // BAD: bypasses Cobra error handling
}
```

## Fix
Return errors instead:
```go
RunE: func(cmd *cobra.Command, args []string) error {
    ...
    return fmt.Errorf("not in workspace")
}
```

## Acceptance criteria
- [ ] No os.Exit calls inside RunE functions
- [ ] Errors returned with proper context
- [ ] grep -n 'os.Exit' internal/cmd/*.go shows no RunE matches
- [ ] go build ./... passes
- [ ] Commands still exit with correct codes


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 105: All agents healthy, no incidents


Move disk 1: B → C

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


Molecule CLI: bd molecule commands

Add molecule commands to bd:

## Commands

```bash
bd molecule list              # List molecules (type: molecule)
bd molecule show <id>         # Show molecule with parsed steps
bd molecule parse <id>        # Validate and show parsed structure
bd molecule instantiate <mol-id> --parent=<issue-id>  # Create steps
bd molecule instances <mol-id>  # Show all instantiations
```

## gt spawn integration

```bash
gt spawn --issue <id> --molecule <mol-id>
```

This should:
1. Call `bd molecule instantiate` (creates child beads atomically)
2. Spawn polecat on first ready step
3. Polecat grinds through via `bd ready`

## Output Examples

```
$ bd molecule show mol-abc

mol-abc: Engineer in a Box
Type: molecule

Steps (5):
  design      → (ready first)
  implement   → Needs: design
  review      → Needs: implement
  test        → Needs: implement
  submit      → Needs: review, test

Instances: 3
```

```
$ bd molecule instances mol-abc

Parent          Status    Created
gt-xyz          done      2025-12-15
gt-abc          active    2025-12-17 (3/5 complete)
gt-def          pending   2025-12-18
```


Wire GT_ACCOUNT env var into spawn/attach

When spawning Claude Code (gt spawn, gt crew attach), check GT_ACCOUNT env var. If set, look up account in config and set CLAUDE_CONFIG_DIR accordingly.


Move disk 1: B → C

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


Witness cleanup should know worktree parent repo

Witness had to discover that polecat worktrees are created from mayor/rig, not the rig root.

## Problem
When cleaning up polecat/tracer:
- Witness ran git worktree remove from gastown/ - failed
- Had to discover worktree was from mayor/rig
- Then removed correctly

## Improvement
Witness should know the worktree parent repo path (mayor/rig) and clean up from there directly.

## Evidence
Tracer bullet 2025-12-23: Witness took extra steps to figure out cleanup path.


Merge: morsov-mjxpeg1a

branch: polecat/morsov-mjxpeg1a
target: main
source_issue: morsov-mjxpeg1a
rig: gastown
agent_bead: gt-gastown-polecat-morsov


Polecat template: fix hard-to-parse sentence about persistence

This sentence is hard to parse: 'When in doubt, prefer bd—persistence you don't need beats lost context'. Rewrite for clarity, e.g., 'When in doubt, use bd for tracking - unnecessary persistence is better than lost context.'


Move disk 1: A → B

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


test pin issue


Move disk 1: A → B

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


Move disk 2: A → C

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


Witness pre-kill verification protocol

Add pre-kill verification protocol to Witness CLAUDE.md template.

## Protocol for Witness Prompting

```markdown
## Pre-Kill Verification Protocol

Before killing any worker session, verify workspace is clean.

### Verification Steps

When a worker signals done:

1. **Capture worker state**:
```bash
town capture <polecat> "git status && git stash list && bd sync --status"
```

2. **Assess the output** (use your judgment):
- Is working tree clean?
- Is stash list empty?
- Is beads synced?

3. **Decision**:
- **CLEAN**: Proceed to kill session
- **DIRTY**: Send nudge with specific issues

### Nudge Templates

**Uncommitted Changes**:
```
town inject <polecat> "WITNESS CHECK: Uncommitted changes found. Please commit or discard: <files>. Signal done when clean."
```

**Beads Not Synced**:
```
town inject <polecat> "WITNESS CHECK: Beads not synced. Run 'bd sync' then commit. Signal done when complete."
```

### Kill Sequence

Only after verification passes:
```bash
town kill <polecat>
town sleep <polecat>
```

### Escalation

If worker fails verification 3+ times:
```bash
town mail send mayor/ -s "Escalation: <polecat> stuck" -m "Cannot complete cleanup after 3 attempts. Issues: <list>."
```
```

## Implementation

Add to WITNESS_CLAUDE.md template.


Merge: warboy-mjwjbptd

branch: polecat/warboy-mjwjbptd
target: main
source_issue: warboy-mjwjbptd
rig: gastown
agent_bead: gt-gastown-polecat-warboy


Digest: mol-deacon-patrol

Patrol 1: All agents healthy. Clone divergence (zoey/jack) noted for witnesses.


gt refinery attach: Attach to refinery session

Add 'gt refinery attach [rig]' command to attach to refinery tmux session.

Mirrors 'gt mayor attach' pattern. If rig not specified, use current rig context.


gt sling to town roles should use Town beads

## Problem

When Mayor starts from ~/gt (town root), `gt mol status` couldn't find beads pinned in rig beads.

## Solution

Added cross-rig scanning for town-level roles (mayor, deacon):
1. First check local beads directory
2. If nothing found AND target is a town-level role, scan all registered rigs
3. Return first pinned bead found

This makes `gt mol status` work correctly regardless of where Mayor is when checking hook status.

## Tested

1. `gt sling gt-552hb mayor` from gastown/mayor/rig/ - pins in rig beads ✓
2. `gt mol status` from ~/gt - finds the pinned bead via cross-rig scan ✓


Digest: mol-deacon-patrol

Patrol 17: Quiet


Digest: mol-deacon-patrol

Cycle 18


Digest: mol-deacon-patrol

P4: stable


MR field parsing: extract structured fields from description

Parse merge-request beads to extract structured fields:
- branch: source branch name
- target: target branch (main or integration/xxx)
- source_issue: the work item being merged
- worker: who did the work
- rig: which rig
- merge_commit: (set on close)
- close_reason: (set on close)

Fields stored in description as YAML block or key: value lines.
Provide helper functions: ParseMRFields(issue) and SetMRFields(issue, fields).

Reference: docs/merge-queue-design.md#merge-request-schema


Merge: slit-1767080431456

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


Refactor all startup paths to use StartupNudge

## Files to Refactor

| File | Function | Current Approach |
|------|----------|------------------|
| start.go:788 | runStartCrew | SendKeys(claude) then SendKeys(gt prime) |
| start.go:747 | runStartCrew restart | Same |
| start.go:929 | another path | SendKeys without prime |
| crew_lifecycle.go:354 | restart | SendKeys(gt prime) after start |
| crew_lifecycle.go:525 | another path | Same |
| crew_at.go:154 | --detached | Claude arg "gt prime" ✓ |
| handoff.go:331 | handoff | Claude arg "gt prime" ✓ |
| deacon.go:294 | deacon start | Relies on hooks |
| witness.go:336 | witness start | Relies on hooks |
| polecat_spawn.go | spawn | Various |

## Pattern
Replace scattered logic with:
```go
cfg := StartupNudgeConfig{
    Recipient: address,
    Sender:    sender,
    Topic:     "cold-start",  // or "handoff", mol-id, etc.
}
if err := session.StartupNudge(t, sessionName, cfg); err \!= nil {
    // handle
}
```

## Dependencies
- gt-bgfqy: Create StartupNudge function
- gt-dc2fs: Add runtime configuration


Digest: mol-deacon-patrol

Patrol cycle 6: All agents healthy


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 1: All healthy, no messages, no orphans


BUG: gt convoy create with count argument doesn't set convoy description

Root cause: 'gt convoy create' usage is 'create <name> [issues...]' but we invoked 'gt convoy create 1 beads' expecting polecat count semantics.

The '1' became the convoy name, 'beads' was treated as an issue ID (failed to track).

Options:
1. Add --count flag for polecat spawning semantics
2. When issues are added later via 'convoy add', update convoy title if current title is just a number
3. If first arg looks like an issue ID (has prefix), auto-generate name from issue title

For now, users must use: 'gt convoy create "Descriptive name" issue-id' not 'gt convoy create <count> <rig>'


Digest: mol-deacon-patrol

Cycle 194: Nominal


Digest: mol-deacon-patrol

Patrol 71: Routine


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

Patrol 5: All healthy


Move disk 2: A → C

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


Move disk 2: B → A

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


Deacon patrol banners: visual feedback on atom transitions

Print large ASCII banners when transitioning between patrol atoms.

## Problem

When the deacon progresses through patrol atoms (steps), there is no visual feedback.
The operator cannot easily see what the deacon is doing without reading the full output.

## Desired Behavior

Print banners on step start and completion:

  INBOX-CHECK - Checking for lifecycle requests, escalations, timers
  INBOX-CHECK COMPLETE - Processed 3 messages, 0 lifecycle requests

## Benefits

1. Scanability: Operator can glance at tmux and see what is happening
2. Progress tracking: Easy to see where in the patrol loop we are
3. Debugging: Clear demarcation between steps for troubleshooting

## Implementation Options

1. In deacon CLAUDE.md: Instruct agent to print banners
2. gt patrol step start/end: Commands that print banners
3. bd mol step hooks: Automatically on step transitions

## Related

- gt-id36: Deacon Kernel
- gt-rana: Patrol System


Port Gas Town to Go

Complete rewrite of Gas Town in Go for improved performance and single-binary distribution.

## Goals
- Single installable binary (gt)
- All Python functionality ported
- Federation support built-in
- Improved performance

## Phases
1. Core infrastructure (config, workspace, git wrapper)
2. Rig & polecat management
3. Session & tmux operations
4. Mail system
5. CLI commands
6. TUI (optional)


Merge: nux-mjui76op

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


Move disk 3: A → B

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


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 746/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.


Digest: mol-deacon-patrol

Patrol 8


Digest: mol-deacon-patrol

Patrol complete: inbox empty, polecats healthy (furiosa/nux idle), witness/refinery running, no orphans


Refinery background daemon mode

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

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

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


Digest: mol-deacon-patrol

Patrol 97: All healthy


Mol Mall: Formula Package Registry

A package registry for sharing and discovering formulas, schematics, and protocols.

## Concept

Like npm/Maven/Go modules but for workflow definitions.

```
mol-mall.io/
├── @gastown/           # Official Gas Town formulas
│   ├── shiny
│   ├── polecat-work
│   └── release
├── @acme-corp/         # Enterprise org (private)
│   └── compliance-review
├── @linus/             # Individual publisher
│   └── kernel-review
└── community/          # Unscoped public formulas
    └── towers-of-hanoi
```

## Resolution Hierarchy

```
1. Project:  ./.beads/formulas/          # Project-specific
2. Rig:      ~/gt/<rig>/.formulas/       # Rig-wide
3. Town:     ~/gt/.formulas/             # Town-wide (mayor stdlib)
4. User:     ~/.gastown/formulas/        # Personal collection
5. Mall:     mol-mall.io/                # Published packages
```

## Package Manifest

```toml
[package]
name = "shiny"
version = "1.2.0"
description = "Engineer in a Box"
authors = ["Gas Town <gastown@example.com>"]
license = "MIT"

[dependencies]
"@gastown/review-patterns" = "^2.0"
```

## Distribution Scenarios

1. **Celebrity Formulas**: Expert-curated workflows (e.g., Linus kernel review)
2. **Enterprise Compliance**: Private company formulas
3. **Standard Library**: @gastown/* blessed defaults
4. **Community Ecosystem**: Varying quality, needs ratings/verification

## Open Questions

1. Versioning semantics - SemVer? Breaking change rules?
2. Security model - sandboxing? signing? permissions?
3. Private registries - self-hosted? authentication?
4. Lock files - formulas.lock format?

## Related

- docs/formula_evolution.md - package ecosystem parallel section
- gt-8ws7o - Schematic (can be published)
- gt-y3jb9 - Protocol (can be published)


Merge: gt-7923

branch: polecat/rictus
target: main
source_issue: gt-7923
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.

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


Polecats should not bd sync on startup

Polecats all share the same beads database at the rig level. The refinery and mayor/witness manage syncing beads.

## Current Behavior
Polecat startup runs bd sync, causing:
- Contention when multiple polecats spawn simultaneously
- Unnecessary sync operations
- Potential race conditions

## Desired Behavior
- Polecats should NOT run bd sync on startup
- They read from the shared beads database
- Only refinery/witness/mayor sync beads

## Implementation
Remove bd sync from polecat spawn/startup sequence.


Phase verbs: pour and wisp commands

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

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


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 757/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.


Worker prompting: Beads write access

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

## Beads Access Section for Prompting

```markdown
## Beads Access

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

### Quick Reference

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

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

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

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

### When to Create Issues

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

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

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

### Beads Sync Protocol

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

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

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

## Implementation

Add to AGENTS.md.template polecat section.


mol-witness-patrol

Per-rig worker monitor patrol loop using the Christmas Ornament pattern.

The Witness is the Pit Boss for your rig. You watch polecats, nudge them toward
completion, verify clean git state before kills, and escalate stuck workers.

**You do NOT do implementation work.** Your job is oversight, not coding.

This molecule uses dynamic bonding to spawn mol-polecat-arm for each worker,
enabling parallel inspection with a fanout gate for aggregation.

## The Christmas Ornament Shape

```
                     ★ mol-witness-patrol (trunk)
                    /|\
          ┌────────┘ │ └────────┐
       PREFLIGHT  DISCOVERY  CLEANUP
          │          │           │
      inbox-check  survey    aggregate (WaitsFor: all-children)
      check-refnry   │       save-state
      load-state     │       generate-summary
                     ↓       context-check
             ┌───────┼───────┐  burn-or-loop
             ●       ●       ●   mol-polecat-arm (dynamic)
            ace     nux    toast
```


Code review swarm: recent merges


Beads schema: Add overseer field for team scenarios

For future team support: overseer field identifies human owner when multiple humans share a workspace. For now, email in git commits serves this purpose. Low priority until teams needed.


Move disk 1: A → B

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


Implement pinned beads for handoff state

Add pinned bead support to beads:
- Pinned beads never close, only update
- Use for persistent state like Refinery handoffs
- bd create --pinned flag
- bd list --pinned to find them
- Update description to change state


Digest: mol-deacon-patrol

Patrol 11: All healthy


Merge: slit-1767073379145

attached_args: Code review this merge request

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

CODE REVIEW (valkyrie): REQUEST CHANGES

Critical bugs found in internal/swarm/manager.go:
1. JSON field changed from 'dependents' to 'dependencies' but bd outputs 'dependents'
2. 'hooked' status removed from in_progress handling
3. Assignee field removed from task loading

These changes will break swarm coordination. Polecat_spawn.go fix is correct.

Recommendation: Revert swarm/manager.go changes, keep polecat_spawn.go fix.


Spawn inject: Enter not submitted after multiline paste

When gt spawn injects a multiline context (85+ lines), Claude Code shows
'[Pasted text #1 +85 lines]' but the prompt is not submitted.

The tmux SendKeys function does include 'Enter' but it appears to not work
for long pasted text:

```go
func (t *Tmux) SendKeys(session, keys string) error {
    _, err := t.run("send-keys", "-t", session, keys, "Enter")
    return err
}
```

Possible fixes:
1. Use tmux paste-buffer instead of send-keys for long text
2. Send Enter separately after the text
3. Use bracketed paste mode correctly

Reproduction:
```bash
gt spawn gastown/Nux --issue gt-u1j.13 --create
# Session shows pasted text but waits at prompt
```


mol-christmas-launch: 3-day execution plan

---

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

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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol #11: Quick cycle, all quiet.


Move disk 1: B → C

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


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


Digest: mol-deacon-patrol

Patrol 1: all healthy, 17 sessions, 3 rigs online


Digest: mol-deacon-patrol

Patrol cycle 10: routine, healthy - midpoint


Handle callbacks from agents

Handle callbacks from agents.

Check the Mayor's inbox for messages from:
- Witnesses reporting polecat status
- Refineries reporting merge results
- Polecats requesting help or escalation
- External triggers (webhooks, timers)

```bash
gt mail inbox
# For each message:
gt mail read <id>
# Handle based on message type
```

**WITNESS_PING**:
Witnesses periodically ping to verify Deacon is alive. Simply acknowledge
and archive - the fact that you're processing mail proves you're running.
Your agent bead last_activity is updated automatically during patrol.
```bash
gt mail archive <message-id>
```

**HELP / Escalation**:
Assess and handle or forward to Mayor.
Archive after handling:
```bash
gt mail archive <message-id>
```

**LIFECYCLE messages**:
Polecats reporting completion, refineries reporting merge results.
Archive after processing:
```bash
gt mail archive <message-id>
```

**DOG_DONE messages**:
Dogs report completion after infrastructure tasks (orphan-scan, session-gc, etc.).
Subject format: `DOG_DONE <hostname>`
Body contains: task name, counts, status.
```bash
# Parse the report, log metrics if needed
gt mail read <id>
# Archive after noting completion
gt mail archive <message-id>
```
Dogs return to idle automatically. The report is informational - no action needed
unless the dog reports errors that require escalation.

Callbacks may spawn new polecats, update issue state, or trigger other actions.

**Hygiene principle**: Archive messages after they're fully processed.
Keep inbox near-empty - only unprocessed items should remain.


Move disk 2: C → B

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


Move disk 3: C → A

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


Witness: Escalate dormant polecats with unpushed work (don't auto-nuke)

Witness escalation for dormant polecats should distinguish between safe-to-nuke and needs-recovery.

## Problem
Witness detected 4 dormant polecats with unpushed commits (hq-ww5ev) but by the time Mayor processed the mail, the polecats were nuked during cleanup, losing work.

## Fix
1. Witness dormancy check should read cleanup_status from agent bead
2. If has_unpushed or has_uncommitted: mark as NEEDS_RECOVERY, escalate
3. If clean: safe to nuke
4. NEVER auto-nuke polecats with unpushed work

## Escalation Format
Subject: RECOVERY_NEEDED <polecat>
Body includes: unpushed commit SHAs, branch name, issue ID


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 1: A → B

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


Move disk 1: B → C

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


Polecat CLAUDE.md: configure auto-approve for bd and gt commands

Polecats get stuck waiting for bash command approval when running
bd and gt commands. Need to configure Claude Code to auto-approve these.

Options:
1. Add allowedTools to polecat CLAUDE.md
2. Configure .claude/settings.json in polecat directory
3. Use --dangerously-skip-permissions flag (not recommended)

Should auto-approve:
- bd (beads commands)
- gt (gastown commands)
- go build/test
- git status/add/commit/push

Should still require approval:
- rm -rf
- Arbitrary commands outside project

Related to polecat prompting (gt-e1y, gt-sd6).


Digest: mol-deacon-patrol

Patrol cycle 16: All healthy.


Patrol formulas: Inconsistent variable placeholder syntax

The patrol formulas use inconsistent syntax for variable placeholders:

## Inconsistency

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

## Expected

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

## Fix

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


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


Move disk 1: A → B

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


Move disk 3: B → C

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


Move disk 1: C → A

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


Test: Alpha to Beta

Sibling communication test


Move disk 3: A → B

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


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 14: Mayor OK, 11 sessions


bd mol install: Install formula from GitHub

Fetch and install a formula from a GitHub repository.

Usage: bd mol install github.com/org/repo[@version]

Should:
- Clone/fetch the formula.json from the repo
- Validate the formula structure
- Store in local catalog
- Track installation in .beads/installed.json


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol cycle 59: All healthy


CLI: rig commands (list, show, add)

Rig management CLI commands.

## Commands

### gt rig list
List all registered rigs.
```
gt rig list [--json]
```
Output:
- Rig name
- Git URL
- Polecat count
- Witness/Refinery status

### gt rig show
Show details for a specific rig.
```
gt rig show <name> [--json]
```
Output:
- Full rig info
- Polecats with status
- Recent activity
- Beads summary (open issues)

### gt rig add
Add a new rig to the town.
```
gt rig add <name> <git-url>
gt rig add <name> --local <path>
```
Steps:
- Clone repo to town root (or link local)
- Register in rigs.json
- Create agent directories
- Configure git exclude

### gt rig remove
Remove a rig from the town.
```
gt rig remove <name> [--force]
```
- Warns if active polecats
- --force required if uncommitted changes

## Implementation

```go
var rigCmd = &cobra.Command{Use: "rig"}
rigCmd.AddCommand(rigListCmd, rigShowCmd, rigAddCmd, rigRemoveCmd)
```


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 7: Routine


Polecats should spawn with auto-accept mode enabled

During swarm bd-784c, polecats (Toast, Nux) were spawned without --dangerously-skip-permissions or equivalent auto-accept mode.

**Problem:**
Every edit, bash command, and tool use required manual confirmation via tmux send-keys. This defeats the purpose of autonomous polecat operation.

**Expected:**
Polecats in a swarm should run with permissions bypassed so they can work autonomously.

**Suggestion:**
- gt sling should pass --dangerously-skip-permissions by default for polecats
- Or polecats should have a .claude/settings.local.json pre-configured for auto-accept