Add gt rig rename command

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

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

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


Witness MVP: Automated Polecat Lifecycle

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

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

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

## Core Loop

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

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

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

  sleep 60
```

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


Digest: mol-witness-patrol

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


gt mq submit: creates task type instead of merge-request type

## Problem

`gt mq submit` creates an issue with `type: task` but should be `type: merge-request`.

## Evidence

```
$ bd show gt-n508
gt-n508: Merge: gt-70b3
Status: open
Priority: P1
Type: task      <-- WRONG, should be merge-request
...
Description:
type: merge-request   <-- Correct type is in description, not in actual type field
```

## Impact

`gt mq list` shows empty queue because it queries for `type: merge-request`

## Fix

`gt mq submit` should set `--type merge-request` when creating the bead.


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 11: nominal


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

## Variables

| Variable | Required | Description |
|----------|----------|-------------|
| issue | Yes | The source issue ID being worked on |


test message


Digest: mol-deacon-patrol

Patrol cycle 14: routine


implement

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

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

Depends: load-context


Complete gt crew commands (list, attach, remove, refresh, status)

Add remaining crew subcommands to internal/cmd/crew.go:

1. gt crew list - List crew workspaces with status
2. gt crew at/attach - Start tmux session in crew workspace
3. gt crew remove - Remove crew workspace (with safety checks)
4. gt crew refresh - Context cycling with mail-to-self handoff
5. gt crew status - Show detailed workspace status

Build on existing crew add implementation in internal/cmd/crew.go.
Reference closed issues gt-cik.3-7 for original requirements.


Tech Debt: Code Review December 2024

Tech debt identified during code review on 2024-12-21. Contains 11 issues ranging from P2-P4 covering:

- Code duplication (manager creation boilerplate)
- Test coverage gaps (cmd 6.8%, mail 3.6%)
- Magic strings needing constants
- Error handling inconsistencies
- Large files needing splitting
- Unused code removal

Work through these incrementally to improve codebase maintainability.


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.


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.


mol-deacon-patrol


Work on ga-ct2: Add MR workflow to polecat completion. Wh...

Work on ga-ct2: Add MR workflow to polecat completion. When polecat completes work, auto-create MR to integration branch. When done, submit MR (not PR) to integration branch for Refinery.


Digest: mol-deacon-patrol

Patrol 6: All healthy, no messages


Rename Engineer in Box to Shiny

Rename mol-engineer-in-box to mol-shiny (or just 'shiny').

Mad Max reference - the canonical 'right way to engineer'.
Update all references in docs and code.


Digest: mol-deacon-patrol

Patrol #21: No messages, all agents healthy, cleaned 1 stale lock, burned 1 orphan wisp


Digest: mol-deacon-patrol

Patrol 7: All healthy, no messages


GGT Command Parity: Complete gt command coverage

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

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


Integration branch management for swarms

Manage integration branches for swarm merging strategy.

## Branch Naming

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

## Operations

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

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

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

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

## All Workers Same Base

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

This ensures clean merges within the swarm.

## Reference

PGT: ephemeral.py (create_integration_branch, merge_integration_to_main)


Add multi-lang-shiny example and tests

Create example meta-formula and test suite.

## Example

Create .beads/formulas/multi-lang-shiny.meta.yaml:
- Generates shiny-go, shiny-python, shiny-typescript
- Each extends base-shiny with language-specific vars

## Tests

1. Test basic expansion (3 languages -> 3 formulas)
2. Test variable substitution in names and content
3. Test error on duplicate generated names
4. Test empty values list
5. Integration: cook a generated formula


Persist patrol state

Update handoff bead with new states.

Persist state to the witness handoff bead:
- Updated worker statuses from all arms
- Current nudge counts per worker
- Nudge timestamps
- Actions taken this cycle
- Pending items for next cycle

```bash
bd update <handoff-bead-id> --description="<serialized state>"
```

This state survives wisp burns and session cycles.


Execute registered plugins

Execute registered plugins.

Scan ~/gt/plugins/ for plugin directories. Each plugin has a plugin.md with
YAML frontmatter defining its gate (when to run) and instructions (what to do).

See docs/deacon-plugins.md for full documentation.

Gate types:
- cooldown: Time since last run (e.g., 24h)
- cron: Schedule-based (e.g., "0 9 * * *")
- condition: Metric threshold (e.g., wisp count > 50)
- event: Trigger-based (e.g., startup, heartbeat)

For each plugin:
1. Read plugin.md frontmatter to check gate
2. Compare against state.json (last run, etc.)
3. If gate is open, execute the plugin

Plugins marked parallel: true can run concurrently using Task tool subagents.
Sequential plugins run one at a time in directory order.

Skip this step if ~/gt/plugins/ does not exist or is empty.


gt sling: nudge crew/mayor if session is running

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

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

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

NOT applicable to patrol-based agents (witness, refinery, deacon) - they run on cycles and pick up work via hook check, not interactive nudge.

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


Work on ga-xxp: Define mol-polecat-work standard molecule...

Work on ga-xxp: Define mol-polecat-work standard molecule. See bd show ga-xxp for full details.


🤝 HANDOFF: Investigate beads-sync divergence (221 files)

## Context

gt doctor now detects orphaned code on beads-sync branch. Running it shows:

  beads-sync-orphans: 221 file(s) on beads-sync not in main

This is in the gastown repo (checking from crew/max).

## Background

- Earlier today we recovered orphaned mail migration code lost in merge 96c773f
- Recently simplified architecture: all workers use mayor/rig/.beads (redirects)
- This simplification may have caused beads-sync branch to diverge unexpectedly

## Investigation Steps

1. From crew/max run: git diff main..beads-sync --stat
2. Check if beads-sync should even exist anymore (was for multi-clone sync)
3. If obsolete with redirect architecture, consider deleting it
4. If it has legitimate changes, cherry-pick or merge to main

## Key Question

With all workers using mayor/rig/.beads via redirects, is beads-sync still needed?

## Commands

git log main..beads-sync --oneline | head -20
git diff main..beads-sync -- *.go | head -100


CLI: polecat commands (add, list, wake, sleep, decommission)

GGT is missing most polecat management commands that PGT has.

Missing Commands:
- gt polecat add <rig> <name> - Add polecat to rig (creates clone)
- gt polecat list [<rig>] - List polecats with state
- gt polecat info <polecat> - Show detailed info
- gt polecat wake <polecat> - Mark available
- gt polecat sleep <polecat> - Mark unavailable
- gt polecat decommission <polecat> - Remove polecat safely

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

Notes:
- spawn exists but doesn't cover management
- wake/sleep are in polecat manager but not CLI
- decommission should check for uncommitted work


Digest: mol-deacon-patrol

Patrol 14: all clear


Digest: mol-deacon-patrol

Patrol 8: all quiet


Digest: mol-deacon-patrol

Patrol 13: all healthy


Digest: mol-deacon-patrol

P5: stable


Digest: mol-deacon-patrol

Patrol 20: All healthy, 2 crew active


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol #13: Stable


Digest: mol-deacon-patrol

Patrol 9: all clear


Digest: mol-deacon-patrol

Patrol 6: routine


Digest: mol-deacon-patrol

Patrol cycle 14: 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 deacon/ mail identity support

Ensure deacon/ works as a mail identity in town-level beads. Test with bd mail send deacon/ and bd mail inbox --identity deacon/.


Digest: mol-deacon-patrol

Patrol 10: Quick cycle, 50% to handoff


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 7: all clear


Check Witness and Refinery health

Check Witness and Refinery health for each rig.

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

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

**Signals to assess:**

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

**Tracking unresponsive cycles:**

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

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

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

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

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

Reset unresponsive_cycles to 0 when component responds normally.


Digest: mol-deacon-patrol

Patrol 17: all quiet


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

Emergency kill command for swarm operations.

## Commands

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

## Implementation

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

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

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

## Output

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

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

## Safety

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

## Dependencies

Needs: Tmux wrapper, Session management, Polecat management


Digest: mol-deacon-patrol

Patrol cycle 11: routine


Test Polecat Arm

Test child for bonding pattern


Outpost assignment policy: Smart work routing

## Overview

Policy engine for deciding which outpost gets which work.

## Policy Configuration

```yaml
policy:
  # Default order of preference
  default_preference: [local, gce-burst, cloudrun-burst]

  # Rules applied in order
  rules:
    # Background work → Cloud Run (cheap)
    - condition: "priority >= P3"
      prefer: cloudrun-burst

    # Long tasks → VM (persistent)
    - condition: "estimated_duration > 30m"
      prefer: gce-burst

    # Specific epic → specific outpost
    - condition: "epic == gt-abc"
      prefer: local
```

## Implementation

```go
type AssignmentPolicy struct {
    DefaultPreference []string
    Rules             []PolicyRule
}

type PolicyRule struct {
    Condition string   // Simple expression
    Prefer    string   // Outpost name
    Require   string   // Must use this outpost
}

func (p *AssignmentPolicy) SelectOutpost(
    issue Issue,
    outposts map[string]Outpost,
) Outpost {
    // Check rules in order
    for _, rule := range p.Rules {
        if rule.Matches(issue) {
            if op, ok := outposts[rule.Prefer]; ok {
                if op.ActiveWorkers() < op.MaxWorkers() {
                    return op
                }
            }
        }
    }

    // Fall back to default preference
    for _, name := range p.DefaultPreference {
        if op, ok := outposts[name]; ok {
            if op.ActiveWorkers() < op.MaxWorkers() {
                return op
            }
        }
    }

    return nil  // All outposts at capacity
}
```

## Condition Language

Simple expressions, not a full DSL:

```
priority >= P3
priority == P0
estimated_duration > 30m
epic == gt-abc
type == bug
label contains "urgent"
```

## Files

- `internal/outpost/policy.go`
- `internal/outpost/condition.go`

Depends on: gt-9a2.3 (config)


mol-polecat-lease: Semaphore proto for tracking polecat lifecycle

Define a small proto for tracking a single polecat in the Witness patrol wisp:

```markdown
## Molecule: polecat-lease
Semaphore tracking a single polecat's lifecycle.
Vars: {{polecat}}, {{issue}}

## Step: boot
Spawned. Verify it starts working.
gt peek {{polecat}} - if idle, gt nudge.
Timeout: 60s before escalation.

## Step: working
Actively working. Monitor for stuck.
Wait for SHUTDOWN mail.
Needs: boot

## Step: done
Exit received. Ready for cleanup.
Kill session, prune worktree.
Needs: working
```

Used by Witness: bd mol bond mol-polecat-lease wisp-patrol --var polecat=X


Polecat Lifecycle Events: Refinery-Witness Coordination

## Problem

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

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

## Solution: Two-Event Lifecycle

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

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

## Village Sibling Watch

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

## Recovery

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


More branches to process?

More branches to process?

If yes: Return to process-branch with next branch.
If no: Continue to generate-summary.

Track: branches processed, branches skipped (with reasons).

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


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.


mol-deacon-patrol


request-shutdown

Send shutdown request to Witness.
Wait for termination.

The polecat is now ready to be cleaned up.
Do not exit directly - wait for Witness to kill the session.

Depends: generate-summary


Digest: mol-deacon-patrol

Patrol 13: All healthy


Witness patrol wisp with polecat leases

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

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

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

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

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

Requires mol-polecat-lease proto definition.


Digest: mol-deacon-patrol

Patrol 9: All clear


Digest: mol-deacon-patrol

Patrol 3: all quiet


Digest: mol-deacon-patrol

Patrol 2: All healthy


mol-polecat-arm: Add nudge_text variable definition

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

## Current variables section

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

## Missing

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

## Usage in formula

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

## Fix

Add nudge_text to the variables section with a sensible default.


Digest: mol-deacon-patrol

Patrol 3: All healthy, 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.


Digest: mol-deacon-patrol

Patrol 18


Digest: mol-deacon-patrol

Patrol 9: Nominal


Digest: mol-deacon-patrol

P11: stable


gt-witness-gastown

Witness - per-rig polecat monitor for gastown.

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


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

Patrol 19


Test Patrol Parent

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

Original description:
Test parent for Christmas Ornament pattern


Digest: mol-deacon-patrol

Patrol 10: All healthy, no messages


Load context

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

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


implement

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

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

Depends: load-context


Witness daemon: heartbeat loop, spawn ephemeral agent

Background daemon for agent lifecycle and monitoring.

## Core Responsibilities

1. **Heartbeat monitoring**: Check agent health periodically
2. **Session lifecycle**: Restart agents after handoff (Witness Protection)
3. **Polecat monitoring**: Track worker progress, nudging
4. **Escalation**: Report failures to Mayor

## Session Lifecycle (Witness Protection)

The daemon enables autonomous long-running operation by cycling agent sessions:

```go
type SessionLifecycle struct {
    AgentType string  // "witness", "refinery"
    StatePath string  // path to state.json
}

func (d *Daemon) monitorSessionLifecycle(agent SessionLifecycle) {
    // 1. Detect session exit
    // 2. Check state.json for requesting_cycle: true
    // 3. If cycle requested: start new session, clear flag
    // 4. If unexpected exit: escalate to Mayor
}
```

See architecture.md Key Decision #12: Agent Session Lifecycle.

## Interface

```go
type Daemon struct {
    rig      *Rig
    polecats *PolecatManager
    sessions *SessionManager
    config   DaemonConfig
}

type DaemonConfig struct {
    HeartbeatInterval time.Duration  // default: 30s
    NudgeThreshold    int            // nudges before escalation
    MaxWorkers        int            // from rig config
}

func NewDaemon(rig *Rig) *Daemon
func (d *Daemon) Start() error
func (d *Daemon) Stop() error

// Lifecycle
func (d *Daemon) CycleSession(agentType string) error
func (d *Daemon) SpawnWorker(issueID string) error
func (d *Daemon) ShutdownWorker(polecat string) error
```

## Heartbeat Loop

Every HeartbeatInterval:
1. Check Witness session (restart if cycle requested)
2. Check Refinery session (restart if cycle requested)
3. For each active polecat: assess progress, nudge if stuck
4. Query `bd ready` for new work, spawn up to max_workers


Dynamic arm bonding in witness patrol

Witness survey step uses bd mol bond to attach mol-polecat-arm for each active worker. Variables: worker name, rig. Arms become children of the patrol molecule. Requires on_complete/for_each runtime support.


Step recovery: timeout and release

Implement recovery mechanism for stuck molecule steps.

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

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

## Implementation Options

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

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

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

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

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


Refinery needs branch visibility: Convert to worktree or push branches

The refinery cannot see polecat branches because it is a separate clone, not a worktree.

## Problem
- Polecats are worktrees of mayor/rig (correct, per gt-4u5z)
- Refinery is still a separate clone at refinery/rig (not converted)
- Polecat branches are local to mayor/rig, invisible to refinery

## Decision (2025-12-25)
**Use a shared bare repo as the single git source of truth.**

```
gastown/
├── .repo.git/           ← Bare repo (no working tree, invisible base)
├── mayor/rig/           ← Worktree (human workspace)
├── polecats/
│   └── Toast/           ← Worktree on polecat/Toast
├── refinery/rig/        ← Worktree on main (can see all branches!)
└── crew/max/            ← Worktree or separate clone (TBD)
```

**Why bare repo:**
- No working directory to accidentally work in
- Standard git pattern (how servers work)
- All worktrees share branch visibility
- Refinery on main can merge polecat branches directly

## Implementation
1. Create `.repo.git` as bare clone
2. Convert refinery to worktree of .repo.git on main
3. Convert polecats to worktrees of .repo.git
4. Optionally convert mayor/rig (or keep as worktree)
5. Update gt rig init for new rigs
6. Write migration for existing rigs

## Evidence
Tracer bullet 2025-12-23: Refinery could not see polecat/tracer until pushed to origin.


Machine registry: Store and manage machine configs

Registry for managing remote machines in federation.

## Data Model

```go
type Machine struct {
    Name     string `json:"name"`
    Type     string `json:"type"`      // "local", "ssh", "gcp"
    Host     string `json:"host"`      // for ssh: user@host
    KeyPath  string `json:"key_path"`  // SSH key path
    TownPath string `json:"town_path"` // Path to town on remote
}
```

## Interface

```go
type MachineRegistry struct {
    path     string  // config/federation.json
    machines map[string]*Machine
}

func NewMachineRegistry(configPath string) *MachineRegistry
func (r *MachineRegistry) Get(name string) (*Machine, error)
func (r *MachineRegistry) Add(m *Machine) error
func (r *MachineRegistry) Remove(name string) error
func (r *MachineRegistry) List() []*Machine
func (r *MachineRegistry) Connection(name string) (Connection, error)
```

## Storage

federation.json in config/:
```json
{
  "version": 1,
  "machines": {
    "local": {"type": "local"},
    "gcp-vm-1": {
      "type": "ssh",
      "host": "user@10.0.0.1",
      "key_path": "~/.ssh/gcp_key",
      "town_path": "/home/user/ai"
    }
  }
}
```

## Connection Factory

```go
func (r *MachineRegistry) Connection(name string) (Connection, error) {
    m := r.machines[name]
    switch m.Type {
    case "local":
        return NewLocalConnection(), nil
    case "ssh":
        return NewSSHConnection(m.Host, m.KeyPath), nil
    }
}
```


mol-deacon-patrol


Phase 5.2: Ephemeral error handling and recovery

Handle edge cases in ephemeral molecule lifecycle.

## Scenarios

### Agent dies mid-molecule
- Ephemeral state persists
- Witness detects stall (no heartbeat)
- Options:
  a. Nudge agent to resume
  b. Reassign to new agent
  c. Escalate to Mayor

### Squash fails
- Retry with exponential backoff
- If persistent failure, escalate
- Don't lose the ephemeral state until squash succeeds

### Orphaned molecules
- Molecule started, never completed
- gt doctor detects (>24h old with no activity)
- Options:
  a. Manual review
  b. Auto-abandon with 'abandoned' digest
  c. Reassign

### Ephemeral repo corruption
- Re-init from scratch
- Active molecules are lost
- Main beads is source of truth for assigned work

## Implementation

Add error handling to:
- bd mol bond (handle init failures)
- bd squash (retry logic)
- gt doctor (recovery suggestions)


Digest: mol-deacon-patrol

Patrol 9: healthy


CloudRun cost tracking: Usage monitoring and limits

## Overview

Track Cloud Run usage costs and enforce spending limits.

## Cost Model

Cloud Run pricing (approximate):
- CPU: ~$0.000024/vCPU-second
- Memory: ~$0.0000025/GiB-second
- Requests: ~$0.40/million

For 5-minute worker (2 vCPU, 4GB):
- CPU: 300 × 2 × $0.000024 = $0.0144
- Memory: 300 × 4 × $0.0000025 = $0.003
- **Total: ~$0.017 per session**

## Implementation

```go
type CostTracker struct {
    cpuRate    float64  // per vCPU-second
    memRate    float64  // per GiB-second
    sessions   []SessionCost
    mu         sync.RWMutex
}

type SessionCost struct {
    WorkerID  string
    StartTime time.Time
    EndTime   time.Time
    CPUs      float64
    MemoryGiB float64
}

func (t *CostTracker) RecordSession(workerID string, start, end time.Time, cpus, mem float64) {
    t.mu.Lock()
    defer t.mu.Unlock()
    t.sessions = append(t.sessions, SessionCost{...})
}

func (t *CostTracker) CurrentCost() float64 {
    t.mu.RLock()
    defer t.mu.RUnlock()
    var total float64
    for _, s := range t.sessions {
        duration := s.EndTime.Sub(s.StartTime).Seconds()
        total += duration * s.CPUs * t.cpuRate
        total += duration * s.MemoryGiB * t.memRate
    }
    return total
}
```

## Cost Cap Enforcement

```go
func (o *CloudRunOutpost) Spawn(...) (Worker, error) {
    if o.costCap > 0 && o.costTracker.CurrentCost() >= o.costCap {
        return nil, ErrCostCapExceeded
    }
    // ... spawn worker
}
```

## Config

```yaml
outposts:
  - name: cloudrun-burst
    type: cloudrun
    cost_cap_hourly: 5.00   # Stop spawning if hourly cost exceeds $5
    cost_cap_daily: 50.00   # Daily limit
```

## CLI

```bash
gt outpost status cloudrun-burst
# Shows: Cost (today): $0.42 / $50.00 cap
```

## Files

- `internal/cloudrun/cost.go`

## Dependencies

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


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.


Day 2.5: Test daemon pokes based on agent state

Integration test:
1. Create agent bead with state=idle
2. Sling work → hook_bead set
3. Verify daemon pokes
4. Update state=running
5. Verify daemon doesn't double-poke
6. Update state=stopped
7. Verify daemon re-pokes on new work

Parent: gt-d0jqp


Test issue for spawn molecule


Town-level beads: Real DB for coordination mail

Implement Option A from mail redesign: Town gets real beads DB for coordination.

## Background

Mail is now Beads. But currently:
- Town .beads/redirect points to rig beads
- mayor/mail/ has legacy JSONL files
- Cross-rig coordination has no clear home

## Design

Town beads = coordination, cross-rig mail, mayor inbox, handoffs
Rig beads = project issues, work items

Matches HOP hierarchy: platform > project > worker

## Structure

~/gt/
  .beads/           # REAL beads DB (prefix: gm-)
  mayor/
    town.json
    state.json      # NO mail/ directory
  gastown/
    .beads/         # Rig beads (prefix: ga-)

## Tasks

1. Delete ~/gt/.beads/redirect
2. Run bd init --prefix gm at ~/gt/ (town beads)
3. Delete ~/gt/mayor/mail/ directory
4. Update gt mail to use beads not JSONL
5. Add mail fields (thread_id, reply_to, msg_type)
6. Update gt prime for two-tier model
7. Update docs/architecture.md

## Addressing

- mayor/ -> town beads
- rig/agent -> rig beads
- Cross-rig -> town beads


Digest: mol-deacon-patrol

Patrol 19: All clear


Session cycling: Auto-spawn successor when context full

Enable automatic session succession for crew workers.

When a crew worker's context fills up (>80%), they should:
1. Write handoff mail to themselves
2. Signal session end
3. System auto-spawns successor session
4. Successor reads handoff, finds attached work, auto-continues

This completes the autonomous overnight work pattern from gt-9g82.

Depends on:
- Detecting context fullness (Claude Code API?)
- Session spawning mechanism (tmux/daemon)
- Handoff protocol already implemented


Digest: mol-deacon-patrol

Patrol 11: All healthy, no messages


Digest: mol-deacon-patrol

Patrol #5: Routine - 6 sessions healthy


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol


Polecat management: add, remove, list, state

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

## Data Model

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

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

## Interface

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

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

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

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

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

## Add Flow

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

## Remove Flow

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

## State Persistence

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


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.


mol-polecat-lease

Semaphore tracking a single polecat's lifecycle.
Vars: {{polecat}}, {{issue}}

Used by Witness to track polecat lifecycle during patrol. The Witness bonds
this proto for each active polecat, creating a lease that tracks the polecat
from spawn through work to cleanup.

## Step: boot
Spawned. Verify it starts working.

Check if the polecat is alive and working:
```bash
gt peek {{polecat}}
```

If idle for too long, nudge:
```bash
gt nudge {{polecat}} "Please start working on your assigned issue."
```

Timeout: 60s before escalation to Mayor.

## Step: 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.
Needs: boot

## Step: done
Exit received. Ready for cleanup.

The polecat has completed its work and sent SHUTDOWN.
Perform cleanup:
```bash
gt session kill {{polecat}}
gt worktree prune {{polecat}}
```

Update beads state and close the lease.
Needs: working


Digest: mol-deacon-patrol

Quick patrol: no messages, all healthy


Digest: mol-deacon-patrol

Patrol 7: all clear


bd doctor: detect clone divergence emergencies

Add doctor check to detect:
1. Crew/Mayor on feature branches (should always be on main)
2. Significant divergence between clones that should be in sync
3. Distinguish from normal beads-sync vs main divergence (expected)

Context: bd sync --status shows all divergence as equal, but some is emergency (clones drifted) vs normal (sync branch mechanics).


Convert MR queue to wisp storage

MR queue should use wisp storage (.beads-wisp/) instead of durable beads.

## Design (Simplified)

With refinery as worktree, polecats and refinery share the same machine. No cross-machine MR coordination needed. Wisps are the natural fit.

### Storage
- Location: `.beads-wisp/mq/<mr-id>.json`
- Format: Same MRFields structure (branch, target, source_issue, worker, rig)
- Lifecycle: Create on submit, delete after merge

### Code Changes

1. **MR Creation** (done.go, mq_submit.go)
   - Write to `.beads-wisp/mq/` instead of `bd create --type=merge-request`
   - Generate ID: `mr-<timestamp>-<random>` or similar

2. **Refinery Query** (refinery/manager.go, engineer.go)
   - Read from `.beads-wisp/mq/` directory
   - List files, parse JSON, process in order

3. **Cleanup**
   - Delete MR file after successful merge
   - On failure, leave file (refinery retries)

### What Stays in Beads
- Source issues (the work being merged) - still tracked in beads
- Merge commits reference source issue ID
- `bd close <issue>` still happens on merge

### Benefits
- No sync overhead for transient MR state
- Simpler model (file per MR, delete when done)
- Consistent with wisp philosophy (ephemeral operational state)

### Not Needed
- Digest squashing (MRs are deleted, not accumulated)
- Cross-machine visibility (single-machine architecture)


Digest: mol-deacon-patrol

Patrol #19


Digest: mol-deacon-patrol

Patrol 14: Green


Digest: mol-deacon-patrol

Patrol 9: All green


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.


mol-deacon-patrol


Deacon session cycling: first step of rounds

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

## Why First

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

## Implementation

At wake, before doing anything else:

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

## Decision Criteria

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

## State to Preserve in Handoff

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

## Relation to Daemon

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

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


Swarm learning: Beads database locality gap

## PGT Bug (GGT Design Already Correct)

Mayor created issues in `~/ai/mayor/rigs/beads/.beads/` but polecats use `~/ai/beads/.beads/`. Different databases = polecats can't see Mayor's beads.

**GGT Fix**: architecture.md already specifies:
- All agents use BEADS_DIR pointing to rig-level `.beads/`
- Lines 116-143: Beads Configuration for Multi-Agent
- Lines 573-586: Rig-Level Beads via BEADS_DIR

This is a PGT implementation gap, not a design issue. GGT spawn must set BEADS_DIR correctly.


gt sling: Make target path parsing more forgiving

Current parsing rejects valid-looking paths like 'gastown/nux' or 'gastown/polecats/nux'.

Should accept:
- gastown/nux (polecat)
- gastown/Nux (polecat, case-insensitive)
- gastown/polecats/nux (explicit)
- gastown/crew/max (crew)
- gastown (auto-spawn)

The help says 'gastown/Toast' works but it doesn't. Parser is too strict.


Guardrail: Verify commits exist before closing polecat issues

## Updated Approach (ZFC)

The original proposal was for mechanical guardrails in bd close. This contradicts the ZFC principle: all decisions go to models, not code.

## Correct Solution

The verification should happen in **mol-polecat-arm** execute step, not bd close:

In the pre-kill-verify action:
```bash
# Current steps
git status                    # Must be clean
git log origin/main..HEAD     # Check for unpushed
bd show <assigned-issue>      # Verify closed/deferred

# ADD: Verify productive work
git log --oneline --grep='<issue-id>' | head -1
# If no commits AND issue being closed as 'done' → flag for review
```

The agent (Witness) makes the decision. The mol gives it the verification step.

## Why Not Code Guardrails

Polecats have legitimate reasons to close issues without commits:
- Already done (someone else fixed it)
- Deferred (out of scope)
- Escalated (needs human decision)
- Duplicate (merged with another issue)

A code guardrail would block all these. The mol step lets the agent verify AND make the judgment call.

## Implementation

Update mol-polecat-arm execute step to include commit verification for 'done' closures.


Worker cleanup: Beads sync on shutdown

Add beads sync verification to worker cleanup checklist and Witness verification.

## Update to Decommission Checklist (gt-sd6)

Add to pre-done verification:
- bd sync --status must show 'Up to date'
- git status .beads/ must show no changes

## Beads Edge Cases

Uncommitted beads changes:
  bd sync
  git add .beads/
  git commit -m 'beads: final sync'

Beads sync conflict (rare):
  git fetch origin main
  git checkout main -- .beads/
  bd sync --force
  git add .beads/
  git commit -m 'beads: resolve sync conflict'

## Update to Witness Verification (gt-f8v)

When capturing worker state:
  town capture <polecat> "bd sync --status && git status .beads/"

Check for:
- bd sync --status shows 'Up to date'
- git status .beads/ shows no changes

If beads not synced, nudge:
  WITNESS CHECK: Beads not synced. Run 'bd sync' then commit .beads/. Signal done when complete.


Add gate checking to Deacon patrol loop

Integrate gate checking into Deacon's patrol cycle.

## Patrol Integration
```go
func (d *Deacon) checkGates(ctx context.Context) {
    gates, _ := d.store.ListOpenGates(ctx)

    for _, gate := range gates {
        // Check timeout
        if time.Since(gate.CreatedAt) > gate.Timeout {
            d.notifyWaiters(gate, "timeout")
            d.closeGate(gate, "timed out")
            continue
        }

        // Check condition
        if d.checkCondition(gate.AwaitType, gate.AwaitID) {
            d.notifyWaiters(gate, "cleared")
            d.closeGate(gate, "condition met")
        }
    }
}
```

## Moved from beads
Originally bd-is6m. Deacon is in gastown, not beads.


Pinned beads architecture implementation

Implement the pinned beads architecture from docs/pinned-beads-design.md

Phases:
1. Doctor checks for hook validation
2. Dashboard visibility (gt hooks, gt dashboard)
3. Protocol enforcement (self-pin, audit trail)
4. Documentation updates


CloudRun protocol types: WorkRequest, WorkEvent, WorkResult

## Overview

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

## Request Type

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

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

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

## Response Types (streaming NDJSON)

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

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

## Files

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

## Notes

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


Digest: mol-deacon-patrol

Patrol 4: all healthy


Formula versioning and migration strategy

Define how formula versions are managed:
- What does the version field mean? Semver? Integer?
- When a formula changes, what happens to existing protos?
- Do protos track their source formula version?
- Migration path: old proto + new formula = ?
- Backwards compatibility guarantees (if any)

Deferred: post-launch polish


Digest: mol-deacon-patrol

Patrol 17: OK


Rename engineer-in-box to shiny across all docs

Systematic rename of mol-engineer-in-box to shiny throughout docs: molecular-chemistry.md, molecules.md, architecture.md, etc. The shiny name is now canonical per the Breaking Bad × Mad Max naming.


Add neighbor-check steps to all patrol molecules

Part of the 'Gas Town is a Village' antifragility design.

Every patrol molecule should include optional neighbor-checking:
- Deacon checks Witness and Refinery health
- Witness checks Refinery health
- Refinery checks Witness health
- Polecats can peek other polecats

Use gt peek to check health states.
If stuck neighbor found, can nudge or escalate.

This creates distributed monitoring - no single point of failure.


Day 4.4: Witness calls nuke after MERGED signal

When refinery sends MERGED:
1. Witness receives MERGED mail
2. Witness calls gt polecat nuke
3. Full sandbox cleanup
4. Agent bead removed

Parent: gt-4a2qt


Digest: mol-deacon-patrol

Patrol 2: all healthy, no incidents


mol-witness-patrol molecule definition

Create mol-witness-patrol in builtin_molecules.go.

## Steps (10 total)
1. inbox-check - Process witness mail (lifecycle, help requests)
2. load-state - Read handoff bead, get nudge counts
3. survey-workers - gt polecat list, categorize by status
4. inspect-workers - tmux capture-pane for each 'working' polecat
5. decide-actions - Apply nudge matrix, queue actions
6. execute-actions - Nudge, kill, or escalate as decided
7. save-state - Update handoff bead with new states
8. generate-summary - Summarize cycle for digest
9. context-check - Check own context usage
10. burn-or-loop - Squash wisp, then loop or cycle session

## Key Behaviors
- Uses wisp storage (.beads-wisp/)
- Reads/writes witness handoff bead for state persistence
- Progressive nudging (3 levels before escalate)
- Pre-kill verification before killing polecats

## Reference
- See prompts/roles/witness.md for protocol details
- See mol-refinery-patrol for similar structure
- Parent epic: gt-aqd8


implement

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

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

Depends: load-context


Direct formula-to-wisp instantiation (skip proto)

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

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

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

Implementation: streaming cook that emits directly to wisp storage.

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 19: All healthy


gt spawn should use bd mol run for molecule attachment

Simplify Gas Town to use bd mol run for work tracking.

## Key Insight
Two distinct mechanisms, not duplicative:

| Mechanism | Purpose | Query |
|-----------|---------|-------|
| **Pinned molecule** (bd mol run) | What am I working on? | `bd list --pinned --assignee=me` |
| **Handoff mail** | Context notes for restart | `gt mail read` (self-addressed) |

The handoff is just **mail to yourself** - optional context notes.
The molecule is **the actual work** - required state.

## Current State (Overengineered)
Gas Town has custom attachment system:
- Permanent "Foo Handoff" pinned beads per identity
- AttachMolecule(pinnedBeadID, moleculeID)
- Attachment fields parsed from description
- Separate from beads pinning

## New Model (Simplified)
Use bd mol run directly:

```bash
# Spawn polecat with molecule
bd mol run mol-polecat-work --var issue=gt-xyz
# This: spawns, assigns to caller, pins root, sets in_progress
```

Query current work:
```bash
bd list --pinned --assignee=gastown/furiosa --status=in_progress
```

Handoff context (when needed):
```bash
gt mail send gastown/furiosa -s "Context notes" -m "Was on step 4..."
```

## Changes Required

### Remove from Gas Town
- AttachMolecule() / DetachMolecule()
- AttachmentFields struct and parsing
- GetAttachment() / SetAttachmentFields()
- Permanent pinned handoff beads per identity
- Daemon attachment detection (checkDeaconAttachment)

### Update gt spawn
```go
// Old: custom molecule instantiation + attachment
// New: just call bd mol run
cmd := exec.Command("bd", "mol", "run", protoID, "--var", "issue="+issueID)
```

### Update gt prime / agent context
```go
// Old: find handoff bead, parse attachment
// New: query for pinned molecule
cmd := exec.Command("bd", "list", "--pinned", "--assignee="+identity, "--status=in_progress", "--json")
```

### Update documentation
- Remove handoff bead attachment docs
- Clarify: handoff = mail, molecule = work
- Update CLAUDE.md templates

## Benefits
1. One system for work tracking (beads)
2. Simpler Gas Town code
3. bd mol squash works naturally
4. Handoff is just mail (already works)

## Related
- gt-3x0z: Wisp Molecule Integration
- gt-rana: Patrol System
- gt-lek6: gt rig reset --stale
- gt-ay1r: gt molecule current


gt swarm is implemented but undocumented

internal/swarm/ package is fully implemented with:
- gt swarm create
- gt swarm status
- gt swarm list
- gt swarm land
- gt swarm cancel
- gt swarm start

But no documentation exists for it:
- Not in README
- Not in architecture.md (uses different terminology)
- Not in any role prompts

Either:
1. Document gt swarm as the canonical mechanism
2. Or deprecate it in favor of gt sling

Related to gt-6n13 (competing molecule mechanisms)


Doctor check: Worker health and stuck detection

Detect and report stuck workers via gt doctor.

## Checks

### WorkerHealthCheck
- List all active workers (polecats with state=working)
- Check last activity timestamp for each
- Flag as potentially stuck if no progress for configurable threshold (default: 30 min)
- Check if Witness is running for the rig
- Verify Witness last heartbeat time

### Stuck Detection Criteria
- Polecat state=working but session not running
- Polecat state=working but output unchanged for threshold
- Witness not responding to health checks
- Multiple polecats in same rig all stuck

## Output

```
[WARN] Workers in rig 'wyvern' may be stuck:
  - Toast: working for 45m, no recent output
  - Capable: working for 52m, session not found
  - Witness: last heartbeat 20m ago

  Suggestions:
  - gt witness status wyvern
  - gt capture wyvern/Toast 50
  - gt stop --rig wyvern (kill all)
```

## Auto-Fix

Cannot auto-fix stuck workers (risk of data loss), but can:
- Restart Witness daemon if crashed
- Send warning mail to Mayor


Digest: mol-deacon-patrol

Patrol 11: healthy


Digest: mol-deacon-patrol

Patrol cycle 16: nominal


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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 12: All healthy


Daemon sends heartbeat to Mayor instead of Deacon


Digest: mol-deacon-patrol

Patrol cycle 16: routine


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


Digest: mol-deacon-patrol

Patrol 19: Quiet


Advice operators: before, after, around

Implement Lisp-style advice operators for molecules:
- before(target, step) - insert step before target
- after(target, step) - insert step after target
- around(target, wrapper) - wrap target with before/after

Support glob patterns for targeting (*.implement, shiny.*, etc).


Check mail for MR submissions, escalations, messages.

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

Handle shutdown requests, escalations, and status queries.

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


Digest: mol-deacon-patrol

Patrol 8: routine, all healthy


Refinery tmux status: show merge queue length

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

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


Digest: mol-deacon-patrol

Patrol #9


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-f14c
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Digest: mol-deacon-patrol

Patrol 14: All healthy, read Mayor handoff (info)


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 21: all healthy, no lifecycle requests, 4 in-progress issues noted, handoff triggered at threshold


Add gt crew rename command


Create Refinery role template

Add Refinery template to internal/templates/roles/:
- refinery.md.tmpl with full role context
- Variables: rig name, working directory, handoff bead ID
- Update SeedRoleTemplates to include it
- gt prime uses this template for Refinery context


Digest: mol-deacon-patrol

Patrol 17


Phase 2: Awareness and real-time channels (announce:, #channel)

## Scope

Extensions for awareness broadcasting and ephemeral real-time communication.

### Deliverables

1. **announce:name** - Shared single-copy bulletin board
   - Informational, not work-creating
   - Recipients check when convenient, missing is OK
   - Use case: 'Bob is refactoring logging, be aware'
2. **#channel resolution** - Dynamic tmux scan for running agents
   - #rig/gastown → tmux sessions matching gastown/*
   - #town → all Gas Town sessions
3. **gt channel publish** - Ephemeral nudge broadcast to channel

### Key semantics
- announce: shared copy (1 message, N readers) vs list: (N copies, N obligations)
- #channel ephemeral - no storage, real-time only
- Channels resolve against running sessions, not filesystem


implement

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

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

Depends: load-context


Clean dead sessions

Clean dead sessions and orphaned state.

Run `gt doctor --fix` to handle all cleanup:

```bash
# Preview what needs cleaning
gt doctor -v

# Fix everything
gt doctor --fix
```

This handles:
- **orphan-sessions**: Kill orphaned tmux sessions (gt-* not matching valid patterns)
- **orphan-processes**: Kill orphaned Claude processes (no tmux parent)
- **wisp-gc**: Garbage collect abandoned wisps (>1h old)

All cleanup is handled by doctor checks - no need to run separate commands.


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.


Merge: gt-3x1.5

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


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

## Problem

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

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

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

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

## The Right Architecture

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

## Scope

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

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

3. Update gt witness commands to use Claude session model

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

## Related

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


mol-deacon-patrol


Auto-handoff: self-cycling with guaranteed work pickup

## Summary

A mechanism for agents to self-cycle: send handoff mail, request Deacon to kill the process, and automatically restart to pick up the work.

## Use Case

User says: `auto-handoff: gt-bug3`

The agent:
1. Sends handoff mail documenting current state
2. Requests Deacon to terminate the session
3. Deacon restarts the agent in background
4. New session picks up the handoff and continues working

When the user returns to terminal, the old session is gone but work continues in background. User can reattach.

## Key Requirements

- **Guaranteed pickup**: Something in the hook and/or handoff must ensure the new session picks up the work (not just a passive "check inbox")
- **Background execution**: Work continues without user presence
- **Reattachability**: User can reconnect to see progress

## Design Questions

1. Can molecules help coordinate this? (e.g., molecule binds the handoff + auto-restart)
2. What hook handles the pickup guarantee?
3. How does Deacon know to restart vs just kill?
4. How does user reattach to a background agent?

## Related

- Molecules system
- Deacon lifecycle management
- Handoff hooks


Phase 2.1: gt spawn --molecule bonds in ephemeral

Make gt spawn molecule-aware with ephemeral bonding.

## New Flag

```bash
gt spawn --issue gt-xxx --molecule mol-polecat-work
```

## Behavior

1. Create polecat with fresh worktree (existing)
2. Bond molecule in ephemeral: `bd mol bond mol-polecat-work --ephemeral`
3. Link molecule root to source issue
4. Include molecule context in work assignment mail
5. Start session

## Work Assignment Mail

```
Subject: Work Assignment: Fix lifecycle bug [MOLECULE]

You are working on gt-rixa as part of molecule mol-polecat-work.

Molecule instance: eph-abc123
Current step: read-assignment (1/8)

Follow the molecule workflow. When complete, generate summary and squash.
```


Test Polecat Arm

Test child for bonding pattern


Digest: mol-deacon-patrol

Patrol 10: All clear


Remove shell respawn loops from witness and deacon

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 9: routine


gt mq integration create: create integration branch for epic

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 15: all clear


implement

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

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

Depends: load-context


mol-town-shutdown: Full Gas Town reset molecule

## Summary
Molecule for clean town shutdown/restart. Sling it to Mayor when ready to reboot.

## Steps
1. Clear all inboxes (witness, refinery, crew - all rigs)
2. Unhook all agents (remove stale molecule attachments)
3. Kill any active polecats
4. Stop daemon
5. Rotate/archive logs
6. bd sync + git push
7. Send Mayor handoff (what's next)
8. Restart daemon fresh

## Invocation
```
gt hook mol-town-shutdown   # attach it
# Mayor runs it on next session
```

## Related
- Patrol cleanup (continuous) vs shutdown (nuclear)
- See gt-xxx for patrol hygiene


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.


Error handling improvements: retry logic and recovery hints

Improve error handling across GGT codebase.

## Issues Found

### 1. Silent Failures in Refinery
manager.go ProcessMR():
- git pull errors ignored
- Continues processing even on partial failures

### 2. Missing Beads CLI
Many operations silently continue if `bd` not found:
```go
// Current
tasks, err := m.loadTasksFromBeads(epicID)
if err != nil {
    // Non-fatal - swarm can start without tasks
}

// Better
if err != nil {
    return nil, fmt.Errorf("beads required: %w", err)
}
```

### 3. No Retry Logic
Network/lock errors should retry:
```go
func withRetry(attempts int, delay time.Duration, fn func() error) error {
    for i := 0; i < attempts; i++ {
        if err := fn(); err == nil {
            return nil
        }
        time.Sleep(delay)
    }
    return fmt.Errorf("failed after %d attempts", attempts)
}
```

### 4. Recovery Hints
Error messages should include fix suggestions:
```go
// Current
return fmt.Errorf("polecat not found")

// Better
return fmt.Errorf("polecat '%s' not found. Use 'gt polecat list' to see available polecats", name)
```

## Domain Error Types
```go
type SessionError struct {
    Op      string
    Polecat string
    Err     error
}

func (e *SessionError) Error() string {
    return fmt.Sprintf("session %s for %s: %v", e.Op, e.Polecat, e.Err)
}
```

## Files to Review
- internal/refinery/manager.go
- internal/swarm/manager.go
- internal/session/manager.go
- All cmd/*.go files

## Acceptance Criteria
- [ ] No silent error swallowing
- [ ] Retry logic for transient failures
- [ ] Helpful error messages with hints
- [ ] Consistent error types per domain


Digest: mol-deacon-patrol

Patrol #15: 3/4 through


Digest: mol-deacon-patrol

Patrol 9: All healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Digest: mol-deacon-patrol

Patrol 6: Core healthy. Noted Mayor escalation (rig mismatch) - not Deacon work.


Digest: mol-deacon-patrol

Patrol complete: all agents healthy, no lifecycle requests, 9 in-progress items noted


Merge: gt-t9u7

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


Digest: mol-deacon-patrol

Patrol 16: All healthy


load-context

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

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


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

## Variables

| Variable | Required | Description |
|----------|----------|-------------|
| issue | Yes | The source issue ID being worked on |


Digest: mol-witness-patrol

Patrol cycle 1: 3 polecats inspected (nux, slit, furiosa), all working. 4 initial nudges sent. Refinery nudged with 2 MRs. No escalations.


gt rig add: Auto-configure HQ routes.jsonl for new rigs

## Summary

When `gt rig add <rig-name>` adds a new rig to the town, it should automatically
add a routing entry to `~/gt/.beads/routes.jsonl` so that beads with that rig's
prefix can be looked up from the town root.

## Current Behavior

After running `gt rig add myproject`:
- Rig is cloned and set up
- No routing entry is added to HQ beads

## Desired Behavior

After running `gt rig add myproject`:
- Rig is cloned and set up
- Detect the rig's beads prefix (from config.yaml or existing issues)
- Add entry to `~/gt/.beads/routes.jsonl`:
  `{"prefix": "mp-", "path": "myproject/mayor/rig"}`

## Implementation Notes

1. After rig setup, check for `<rig>/mayor/rig/.beads/config.yaml`
2. Read `issue-prefix` if set, or sample an issue ID from the database
3. Append to `~/gt/.beads/routes.jsonl` if the prefix isn't already routed
4. Create routes.jsonl if it doesn't exist

## Edge Cases

- Rig has no beads yet (no prefix known) - skip routing setup, let doctor fix later
- Prefix already exists in routes.jsonl - warn and skip (or update path?)
- routes.jsonl doesn't exist - create it


Witness session startup (gt witness start)

Implement gt witness start <rig>

Should:
1. Verify rig exists and has witness/ directory
2. Check for existing witness session (don't double-start)
3. Create tmux session: gt-<rig>-witness
4. Start Claude Code with --dangerously-skip-permissions
5. Send gt prime to load context
6. Send startup prompt

Similar pattern to refinery startup in internal/refinery/manager.go


Design molecule parameterization

Enable protos to accept parameters for customization.

## Use Cases

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

## Proposed Syntax

### In Proto

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

### In Sling

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

### In Bonded Molecule

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

## Implementation

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

## Edge Cases

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


Digest: mol-deacon-patrol

Patrol 12: All green


Merge: gt-7923

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


Day 4.5: Test multi-step molecule lifecycle

Integration test:
1. Create 3-step molecule
2. Sling to polecat
3. Watch step 1 complete → recycle
4. Watch step 2 complete → recycle
5. Watch step 3 complete → MERGE_READY
6. Watch merge → nuke
7. Verify clean state

Parent: gt-4a2qt


gt handoff: Deadlock in waitForRetirement


Digest: mol-deacon-patrol

Patrol 8: All clear


gt molecule current: Show what agent should be working on

Query what an agent identity is supposed to be working on via breadcrumb trail.

## Command
```bash
gt molecule current <identity>
gt molecule current gastown/furiosa
gt molecule current deacon
```

## Logic
1. Find handoff bead for identity (pinned bead titled "<role> Handoff")
2. Parse attachment field → molecule ID
3. If no attachment → "naked" (no active molecule)
4. If attached → load molecule, find current step:
   - bd ready --parent=<mol-id> → next unblocked step
   - Or first in_progress step

## Output
```
Identity: gastown/furiosa
Handoff:  gt-8v2 (Furiosa Handoff)
Molecule: gt-mol-abc (mol-polecat-work)
Progress: 3/8 steps complete
Current:  gt-mol-abc.4 - verify-tests
```

Or if naked:
```
Identity: gastown/angharad
Handoff:  gt-9x1 (Angharad Handoff)
Molecule: (none attached)
Status:   naked - awaiting work assignment
```

## Use Cases
- Mayor checking what polecats are doing
- Witness verifying polecat progress
- Debug: "why isnt this polecat working?"
- Deacon patrol: track all agent states


Digest: mol-deacon-patrol

Patrol 12: All healthy


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

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

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


Digest: mol-deacon-patrol


Execute registered plugins

Execute registered plugins.

Scan ~/gt/plugins/ for plugin directories. Each plugin has a plugin.md with YAML frontmatter defining its gate (when to run) and instructions (what to do).

See docs/deacon-plugins.md for full documentation.

Gate types:
- cooldown: Time since last run (e.g., 24h)
- cron: Schedule-based (e.g., "0 9 * * *")
- condition: Metric threshold (e.g., wisp count > 50)
- event: Trigger-based (e.g., startup, heartbeat)

For each plugin:
1. Read plugin.md frontmatter to check gate
2. Compare against state.json (last run, etc.)
3. If gate is open, execute the plugin

Plugins marked parallel: true can run concurrently using Task tool subagents. Sequential plugins run one at a time in directory order.

Skip this step if ~/gt/plugins/ does not exist or is empty.


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.


Update config location: .gastown/ → config/

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

Hidden directories are poorly discovered by AI agents.


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


Digest: mol-deacon-patrol

Patrol 5: All healthy


No-tmux mode: naked Claude Code operation without daemon/tmux

## Problem

Tmux is crashing workers. The daemon relies on tmux for:
- Session management (creating/killing panes)
- Nudging agents via SendKeys
- Crash detection via pane-died hooks

When tmux is unstable, the entire Gas Town operation fails.

## Goal

Enable Gas Town to operate without tmux or the daemon, relying solely on:
- Naked Claude Code sessions (terminal or IDE)
- Deacon self-handoff and patrol robustness
- Pinned beads for propulsion (already implemented)
- **Beads as universal data plane** - args, context, everything flows through beads

## Key Insight: Beads Replace SendKeys

Currently --args is injected via tmux SendKeys. In no-tmux mode:
- Store args in the pinned bead description (attached_args field)
- gt prime reads and displays args from pinned bead
- Wisps are infinite ephemeral sticky notes - use them for transient context
- No prompt injection needed - agent discovers everything via bd show

## Degraded Behavior (No-Tmux Mode)

**What still works:**
- Propulsion via pinned beads (agents pick up work on startup)
- Self-handoff (agents can cycle themselves)
- Patrol loops (Deacon, Witness, Refinery keep running)
- Mail system (beads-based, no tmux needed)
- Args passed via bead description

**What is degraded:**
- **No interrupts**: Cannot nudge busy agents mid-task
- **Polling only**: Agents must actively check inbox (no push notifications)
- **Await steps block**: "Wait for human" steps require manual agent restart
- **No crash detection**: pane-died hooks unavailable
- **Manual startup**: Human must start each agent in separate terminal

**Workflow implications:**
- Patrol agents work fine (they poll as part of their loop)
- Task workers need restart to pick up new work
- Cannot redirect a busy worker to urgent task
- Human must monitor and restart crashed agents

## Requirements

1. **gt sling --args stores in bead**: Write args to pinned bead description
2. **gt prime displays args**: Read attached_args from pinned bead
3. **gt spawn --naked**: Assign work without creating tmux session
4. **Documentation**: Explain no-tmux mode and degraded behavior
5. **Deacon self-sustaining**: Must cycle reliably without daemon

## Acceptance Criteria

- Can assign work with args without tmux
- Agent discovers args via gt prime / bd show on startup
- Deacon patrol runs indefinitely via self-handoff
- Workers started manually pick up pinned work
- Documentation explains what works vs degraded in no-tmux mode


mol-deacon-patrol


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.


Test Patrol for Bonding

Parent issue for mol bond CLI test


Digest: mol-deacon-patrol

Patrol cycle 10: nominal


Update gt doctor to check new config locations

Doctor should validate new structure:
- Check mayor/config.json exists and is valid
- Check settings/ exists for each rig
- Warn if old .gastown/ files still exist
- Offer --fix to migrate old locations to new


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.

## The Christmas Ornament Shape

This molecule uses dynamic bonding to create inspection arms per-polecat:

```
                    ★ mol-witness-patrol (trunk)
                   /|\
            ┌─────┘ │ └─────┐
         PREFLIGHT DISCOVERY CLEANUP
            │       │        │
        ┌───┴───┐ ┌─┴─┐  ┌───┴───┐
        │inbox  │ │sur│  │aggreg │
        │refnry │ │vey│  │save   │
        │load   │ └─┬─┘  │summary│
        └───────┘   │    │contxt │
                    │    │loop   │
          ┌─────────┼─────────┐ └───────┘
          │         │         │
          ●         ●         ●     mol-polecat-arm (dynamic)
         ace       nux      toast
          │         │         │
       ┌──┴──┐   ┌──┴──┐   ┌──┴──┐
       │cap  │   │cap  │   │cap  │
       │ass  │   │ass  │   │ass  │
       │dec  │   │dec  │   │dec  │
       │exec │   │exec │   │exec │
       └──┬──┘   └──┬──┘   └──┬──┘
          │         │         │
          └─────────┴─────────┘
                    │
                 ⬣ base (cleanup)
```

## Phases

### PREFLIGHT (fixed steps)
1. inbox-check - Process lifecycle requests, help messages
2. check-refinery - Ensure MQ is alive and processing
3. load-state - Read persistent state (nudge counts, etc.)

### DISCOVERY (spawns dynamic arms)
4. survey-workers - List polecats, bond mol-polecat-arm per polecat
5. run-plugins - Bond mol-plugin-runner for each witness plugin

### CLEANUP (gate + fixed steps)
6. aggregate - GATE: WaitsFor all arms + plugins to complete
7. save-state - Persist nudge counts, action log
8. generate-summary - Create digest content
9. context-check - Check if context is high
10. burn-or-loop - Squash/burn wisp, then loop or exit

## Dynamic Arms

Each polecat gets mol-polecat-arm bonded as a wisp child:
- capture - Capture tmux output
- assess - Categorize state (working/idle/error/done)
- load-history - Get nudge counts for this polecat
- decide - Apply nudge matrix
- execute - Take action (nudge/kill/escalate/none)

Arms run in PARALLEL. The aggregate step waits for all to complete.

## Activity Feed

This design enables real-time visibility:

```
[14:32:08] + patrol-x7k.arm-ace bonded (5 steps)
[14:32:09] → patrol-x7k.arm-ace.capture in_progress
[14:32:10] ✓ patrol-x7k.arm-ace.capture completed
[14:32:14] ✓ patrol-x7k.arm-ace.decide completed (action: nudge-1)
[14:32:17] ✓ patrol-x7k.arm-ace COMPLETE
```

## Storage

- Wisp storage: .beads-wisp/ (ephemeral, gitignored)
- Persistent state: witness handoff bead (nudge counts, etc.)
- Digests: Squashed summaries in permanent beads

## Dependencies

- bd-xo1o: Dynamic Molecule Bonding epic (in beads rig)
  - bd mol bond with variable substitution
  - WaitsFor directive for fanout gates
  - Activity feed query

Labels: [template, christmas-ornament]


Digest: mol-deacon-patrol

Patrol 14: Quick cycle, all quiet


gt mail send should tmux-notify recipient

## Problem

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

## Expected Behavior

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

## Current Behavior

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

## Impact

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

## Implementation Notes

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

## Reference

Check PGT implementation for how it handles this.


Check own context limit

Check own context limit.

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

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

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

This enables the Deacon to burn and respawn cleanly.


gt sling --force: return displaced work to ready pool

When slinging with --force to an agent with occupied hook, the displaced molecule should be returned to the ready pool rather than silently orphaned.

Current behavior:
- --force overwrites the hook attachment
- Previous work becomes orphaned (still assigned but not pinned)

Desired behavior:
1. Unpin the displaced molecule (clear assignee, set pinned=false)
2. Print warning in tool output: 'Warning: displaced gt-xxx back to ready pool'
3. Proceed with new sling

This ensures:
- No silent data loss
- Agent sees the warning and can act on it
- Human caller sees what happened
- Displaced work is discoverable via 'bd ready'

Implementation location: checkHookCollision() or the sling handlers themselves (after the --force check passes)


Digest: mol-deacon-patrol

Patrol cycle 8: thorough check, all healthy


Digest: mol-deacon-patrol

Patrol 18: routine


sling pin test 2


Validate expanded step IDs are unique


Batch Work System: Integration branch, merge queue, landing

## Overview

This epic tracks batch work coordination in GGT. Key insight: **work is a stream, not discrete swarms**.

There are no "swarm IDs" - the epic IS the grouping, the merge queue IS the coordination. "Swarming an epic" is colloquial for spawning multiple workers on its children.

## Architecture

- **Epics** group related work
- **Issues** are individual tasks
- **Dependencies** encode ordering (multi-wave emerges automatically)
- **Merge queue** coordinates completed work
- **Workers** process issues independently

See Key Decision #11 in docs/architecture.md: "Work is a Stream (No Swarm IDs)"

## What This Epic Covers

1. Integration branch management for batch merges
2. Refinery semantic merge processing
3. Witness landing protocol (cleanup)
4. Report generation (epic-based, not swarm-ID-based)
5. Git safety auditing
6. Work reconciliation

## What Was Removed

- Swarm IDs (sw-1, sw-2, etc.)
- Per-swarm directories (.gastown/swarms/<id>/)
- Swarm manifest/state/events files
- swarm-started/swarm-landed beads

These were redundant - beads already provides hierarchy, status, dependencies, and history.

## References

- Architecture: docs/architecture.md (Key Decision #11, Multi-Wave Work Processing)
- PGT: swarm/manager.py, swarm/landing.py (behavioral reference, but ignore swarm ID patterns)


Remove unused style helper functions

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


Create patrol formula YAML files

Create formula YAML files for:
- mol-deacon-patrol.formula.yaml
- mol-witness-patrol.formula.yaml
- mol-refinery-patrol.formula.yaml

Use the step definitions currently in molecules_patrol.go as reference.
Store in .beads/formulas/


Add audit trail for hook detach operations

Log detachment events for debugging and monitoring.

When work is detached from hook:
- Log timestamp, agent, molecule ID, reason
- If abnormal (not completion), notify Witness
- Consider adding to wisp digest for patrol cycles


Digest: mol-deacon-patrol

Patrol complete: 5 mayor msgs (informational), all agents healthy, triggered 3 polecats, closed 1 orphan (gt-mol-aux test artifact)


Resource Beads: Leases, locks, and quotas

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


Document how to configure a Gas Town Harness

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


Merge: gt-a95

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


Digest: mol-deacon-patrol

Patrol 6: all clear, agents healthy


Digest: mol-deacon-patrol

Quick patrol: no messages, all healthy


Request shutdown

Send shutdown request to Witness.
Wait for termination.

The polecat is now ready to be cleaned up.
Do not exit directly - wait for Witness to kill the session.


Create PolecatArmMolecule() for per-polecat inspection

Add PolecatArmMolecule() to builtin_molecules.go.

Steps:
- capture: Capture tmux output
- assess: Categorize state
- load-history: Get nudge counts
- decide: Apply nudge matrix
- execute: Take action

Uses variable substitution:
- {{polecat_name}}
- {{rig}}

This proto is bonded dynamically by survey-workers step.


Work assignment messages should auto-close on completion

When a polecat completes work on an issue, the work assignment message (msg-type:task) stays open. Found 7 stale work assignments in gastown after swarm completed.

Proposal: When bd close is called on an issue, auto-close any work assignment messages that reference that issue in their body.

Alternative: Work assignment messages could use a different lifecycle - perhaps they should be acked (closed) when the polecat starts working, not when they finish.


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.


Design Deacon molecule health-check step

**Context:** After removing Go heuristics, Deacon molecule needs the logic.

**New molecule step: health-scan**

Claude executes:
1. Check Witness heartbeat: gt witness status <rig>
2. Check Refinery heartbeat: gt refinery status <rig>
3. For each, assess: responsive? stuck? needs restart?
4. If unresponsive for N cycles, send escalation mail

**Key difference from Go approach:**
- Claude makes the judgment call, not hardcoded thresholds
- Claude can read context (what was the agent working on?)
- Claude can ask questions or check additional signals
- Thresholds come from molecule config, not Go constants

**Deliverables:**
- Update mol-deacon-patrol health-scan step
- Add configurable thresholds as molecule variables
- Test with simulated stuck agents


Day 2.2: Remove PID/tmux state inference

Remove ZFC violations where Go infers state from signals:
- No more PID file checks
- No more tmux session parsing
- No more branch pattern analysis

Daemon becomes pure transport layer.

Reference: ~/gt/docs/zfc-violations-audit.md

Parent: gt-d0jqp


survey-workers

List polecats and categorize by status.

```bash
gt polecat list <rig>
```

Needs: load-state


Merge: gt-caih

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


Merge: gt-0ei3

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


Digest: mol-deacon-patrol

Patrol 18: healthy


Digest: mol-deacon-patrol

Patrol 10: All green - halfway mark


gt channel publish command

New CLI command for ephemeral broadcast to channels.

## Deliverables

1. New command: gt channel publish <channel> <message>
   - Example: gt channel publish #witnesses "Swarm incoming"
2. Resolve channel to running sessions
3. Nudge each session with message
4. Report delivery status

## Usage
```bash
gt channel publish #town "Handoff in 5 minutes"
gt channel publish #rig/gastown "Merge queue paused"
```

## Dependencies
- #channel resolution (gt-???)

## Acceptance
- Command works with #channel syntax
- Message delivered to running sessions
- Clear output showing delivery status


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.


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 12: OK


Digest: mol-deacon-patrol

Patrol 14: All clear


MR ID generation: prefix-mr-hash convention

Generate merge-request IDs following the convention: <prefix>-mr-<hash>

Example: gt-mr-abc123 for a gastown merge request.

This distinguishes MRs from regular issues while keeping them in the same namespace.
The hash should be derived from branch name + timestamp for uniqueness.

Implement: GenerateMRID(prefix, branch string) string

Reference: docs/merge-queue-design.md#id-convention


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 4: all clear