Move disk 5: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 73: All healthy


Digest: mol-deacon-patrol

Patrol 18: healthy


mol-sync-workspace: Add Refinery-specific inline conflict resolution guidance


Merge: slit-mjtj9dc8

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


Merge: nux-1766959759345

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


Merge: slit-1767084013378

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Polecats should auto-cleanup after MR submission

Currently polecats must manually run 'gt handoff --shutdown' after completing work. This is error-prone and leaves stale polecats around.

## Desired Flow

1. Polecat completes work
2. Polecat runs 'gt mq submit' (or similar)
3. MR is added to integration queue
4. **Polecat automatically cleans up** (no manual handoff needed)

## Implementation Options

### Option A: mq submit triggers cleanup
In 'gt mq submit':
1. Submit MR to queue
2. Automatically run cleanup (same as gt handoff --shutdown)
3. Polecat session terminates

### Option B: Refinery triggers cleanup
When Refinery picks up MR:
1. Refinery processes MR
2. Sends message to Witness: 'CLEANUP: <polecat>'
3. Witness cleans up polecat

### Option C: Molecule-driven
Define cleanup as final phase of polecat-work molecule:
1. code → test → submit-mr → cleanup

## Note
This reinforces the ephemeral model: polecats exist only for the duration of a single task.


Digest: mol-deacon-patrol

Patrol 17: 3 rigs healthy


refinery Handoff

# Merge queue tracking
last_processed_branch: null
branches_merged_this_cycle: 0


Digest: mol-deacon-patrol

Patrol 18 complete


Digest: mol-deacon-patrol

Patrol cycle 20: All agents healthy, handoff threshold reached


Extract interfaces for Git and Tmux to enable testing

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

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 37: All healthy, no incidents


Move disk 3: B → C

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


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 123: All healthy


Digest: mol-deacon-patrol

P17: stable


Digest: mol-deacon-patrol

Patrol cycle 15: all healthy


Digest: mol-deacon-patrol

Patrol 5: Quiet, all healthy


Digest: mol-deacon-patrol

Patrol 19: all quiet


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


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.

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Ephemeral rig support for ad-hoc batch work

Support for temporary worker rigs for ad-hoc batch work.

## Use Case

Ad-hoc batch work where you want temporary workers:
- gt spawn --epic <epic-id> --ephemeral --workers 3
- Creates temp rig with 3 clones
- Workers process epic children
- Work merges through queue
- Clones cleaned up when done

## Interface

```go
type EphemeralRig struct {
    ID               string
    GitURL           string
    BaseCommit       string
    Workers          []string
    IntegrationBranch string
    EpicID           string  // associated epic (for cleanup trigger)
    CreatedAt        time.Time
}

func InitEphemeralRig(gitURL string, numWorkers int) (*EphemeralRig, error)
func (r *EphemeralRig) AddWorker(name string) error
func (r *EphemeralRig) Destroy(force bool) error
```

## Directory Structure

```
<rig>/ephemeral/
└── rig-a3f7/
    ├── config.json
    ├── Alice/     # clone
    ├── Bob/       # clone
    └── Carol/     # clone
```

## Cleanup Trigger

When all issues in the associated epic are closed AND merged, the ephemeral rig can be destroyed.

## Note

No swarm ID needed - the epic ID provides the grouping. Ephemeral rig is just a convenience for temporary clones.

## Reference

PGT: ephemeral.py (for structure, ignore swarm ID coupling)


Digest: mol-deacon-patrol

Patrol cycle 3: all healthy


Digest: mol-deacon-patrol

Patrol cycle 9: All healthy, 4 polecats


Review PR #44: docs: Fix Quick Start to use gt mayor attach

Review and approve/request changes for PR #44. Check docs accuracy. If good, approve with gh pr review --approve.


Move disk 3: B → C

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


Digest: mol-deacon-patrol


mol-deacon-patrol


Move disk 1: B → C

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


Witness sends HEALTH_OK mail to mayor on every deacon ping

## Problem

When Deacon sends HEALTH_CHECK nudges to Witnesses, the Witness Claude sessions
respond by sending 'HEALTH_OK' mail to mayor/. This floods the mayor inbox.

## Current behavior

Deacon: gt nudge gastown/witness 'HEALTH_CHECK'
Witness: gt mail send mayor/ -s 'HEALTH_OK witness' -m 'OK'

This happens every patrol cycle (~30s).

## Expected behavior

Witnesses should NOT send mail responses to routine health checks.

## Fix

Update witness priming to explicitly say 'do not mail on HEALTH_CHECK nudges'.


Batch work landing report generation

Generate reports on batch work completion.

## Trigger

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

## Report Contents

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

## Output Locations

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

## Command

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

## Format

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

## Note

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

## Reference

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


Move disk 2: A → C

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


Witness role template + CLAUDE.md

Create the Witness agent's role context:

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

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

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


Digest: mol-deacon-patrol

Patrol 5: All healthy.


Digest: mol-deacon-patrol

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


Move disk 2: B → A

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


Add gt rig rename command

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

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

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


Digest: mol-deacon-patrol

Patrol 10: all healthy, doctor pass


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 261: Cleaned 510+ stale wisps (57 hq, 450+ gt). All agents healthy (3 witnesses, 3 refineries, 10 polecats active). No incidents.


Digest: mol-deacon-patrol

Patrol cycle 39: All healthy, no incidents


Session ended: gt-gastown-crew-george


Git safety audit module

Port git_audit.py safety checks to Go.

## Purpose

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

## Checks

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

## Beads-Only Classification

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

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

## Interface

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

func (r *GitAuditResult) HasCodeAtRisk() bool

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

## Reference

PGT: swarm/git_audit.py


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Session ended: gt-gastown-slit


Digest: mol-deacon-patrol

Patrol 4: routine checks all clear


Digest: mol-deacon-patrol

Patrol 23: Quick cycle, no changes. All agents healthy.


Tmux session scanner for running agents

Scan tmux for running Gas Town agent sessions.

## Deliverables

1. Function: ScanRunningSessions() -> []AgentAddr
   - Parse tmux list-sessions
   - Filter for Gas Town session naming pattern
   - Return addresses of running agents

2. Function: ScanRigSessions(rig) -> []AgentAddr
   - Filter running sessions by rig prefix

3. Alias resolution:
   - #rig/gastown → running sessions in gastown
   - #town → all running Gas Town sessions
   - #witnesses → running witness sessions

## Location
internal/discovery/tmux.go

## Acceptance
- Scanner finds running sessions
- Correctly parses session names to addresses
- Handles no-sessions case gracefully


Compile-time vs runtime cooking

Distinguish two cooking modes: 1) Compile-time: produces proto with variable placeholders, for modeling/estimation/contractor handoff. 2) Runtime: produces mol with real issue IDs. Compile-time lets you pre-decompose work for untrusted executors or planning purposes.


Digest: mol-deacon-patrol

Patrol 3: All healthy


mol-deacon-patrol


Fanout gate: waits-for children aggregation

Formalize the fanout gate pattern where a step waits for all dynamically-bonded children.

## Current State

Formulas already use this pattern informally:

    step: aggregate
    waits_for: "all-children"

But it is not in the algebra spec or implemented in the cooker.

## Proposed Syntax

    step: aggregate
    needs: [survey-workers]
    waits-for: children-of(survey-workers)

Or simpler:

    step: aggregate
    needs: [survey-workers]
    waits-for: all-children

## Semantics

- Step cannot start until ALL children of the referenced step have completed
- Children are dynamically bonded via for-each (gt-8tmz.8)
- This is the "aggregation" half of the Christmas Ornament pattern
- If no children were bonded, the gate passes immediately

## Use Cases

**Witness Patrol:**
- survey-workers bonds N polecat-arms
- aggregate waits for all arms to complete
- Then proceeds to save-state

**Refinery Patrol:**
- Less common (sequential processing), but useful for parallel test runs

## Relationship to gate

This is a variant of gate where the condition is "all children complete" rather than
an arbitrary expression. Could be implemented as:

    gate:
      condition: "children-of(survey-workers).all(status == complete)"

But dedicated syntax is cleaner for this common pattern.

## Dependencies

- Depends on gt-8tmz.8 (for-each creates the children)
- Depends on gt-8tmz.4 (gate infrastructure)


Digest: mol-deacon-patrol

Patrol 3: All witnesses/refineries healthy, no work


mol-refinery-patrol

Merge queue processor patrol loop.

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

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

## Merge Flow

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

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

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


Swarm learning: Witness needs automated context cycling

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


Digest: mol-deacon-patrol

Patrol cycle 7: routine, healthy


Move disk 1: C → A

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


Move disk 2: A → C

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


Move disk 2: A → C

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


Move disk 1: B → C

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


Track merge requests as beads (type=merge-request)

Currently MRs are tracked in .gastown/refinery.json. For HOP audit trail and entity CV tracking, merge requests should be Beads entries with type=merge-request. This enables:
- Full audit trail of what was merged, when, by whom
- Entity chain contributions (who validated what)
- Cross-rig visibility of merge activity

The refinery would create an MR bead when work enters the queue, update status as it progresses (open → in_progress → merged/rejected).

Part of Beads-as-data-plane vision from HOP.


LocalConnection: Local file/exec/tmux operations

LocalConnection implementation for local machine operations.

## Implementation

```go
type LocalConnection struct {
    tmux *Tmux
}

func NewLocalConnection() *LocalConnection

func (c *LocalConnection) Name() string { return "local" }
func (c *LocalConnection) IsLocal() bool { return true }
```

## File Operations

Direct passthrough to os package:
```go
func (c *LocalConnection) ReadFile(path string) ([]byte, error) {
    return os.ReadFile(path)
}
// etc.
```

## Command Execution

Uses exec.Command:
```go
func (c *LocalConnection) Exec(cmd string, args ...string) ([]byte, error) {
    return exec.Command(cmd, args...).Output()
}
```

## Tmux

Delegates to Tmux wrapper:
```go
func (c *LocalConnection) TmuxNewSession(name, dir string) error {
    return c.tmux.NewSession(name, dir)
}
```

## Notes

Straightforward implementation - this is the "baseline" connection that SSHConnection will mirror remotely.


Rig management commands for town startup/shutdown


Self-test

Testing gt mail works


Daemon/Boot/Deacon Watchdog Chain: Fix session lifecycle management

## Summary

The watchdog chain (Daemon → Boot → Deacon → Witness/Refinery) has multiple bugs preventing auto-recovery of dead agents:

1. Boot spawns in wrong session
2. Daemon can't kill zombie sessions
3. Binary/process age mismatch goes undetected
4. Status display doesn't reconcile bead vs tmux state
5. Start commands don't have 'ensure' semantics

## Impact

When witness/refinery die, they stay dead until manual intervention. The entire purpose of the Deacon (health monitoring) is defeated.

## Root Cause

Session lifecycle management lacks 'ensure running' semantics. The code assumes:
- If session doesn't exist → create it
- If session exists → it's healthy

Reality:
- Sessions can be zombies (tmux alive, Claude dead)
- Bead state and tmux state can diverge
- Daemon process can run old code

## Child Issues

- gt-sgzsb: Boot session confusion (P1)
- gt-j1i0r: Zombie session blocking (P1)
- gt-d48f2: Binary age detection (P2)
- gt-doih4: Status bead/tmux mismatch (P2)
- gt-ekc5u: Start 'ensure' semantics (P2)
- gt-1847v: Boot/Deacon documentation (P2)

## Success Criteria

1. Dead witness/refinery auto-restart within 5 minutes
2. `gt status` accurately reflects session health
3. Daemon warns if running old code
4. Boot/Deacon lifecycle is clear and documented


gt install command: Create workspace structure

Create Gas Town workspace structure.

## Command

```
gt install [path]
```

If path omitted, uses current directory.

## Created Structure

```
<path>/
├── config/
│   ├── town.json      # {"type": "town", "version": 1, ...}
│   └── rigs.json      # {"version": 1, "rigs": {}}
│
└── mayor/
    ├── CLAUDE.md      # Mayor role prompting (from template)
    ├── mail/
    │   └── inbox.jsonl  # Empty inbox
    └── state.json     # Initial mayor state
```

## Implementation

```go
func Install(path string, opts InstallOptions) error

type InstallOptions struct {
    TownName string  // defaults to directory name
    Force    bool    // overwrite existing
}
```

## Steps

1. Validate path (exists, writable)
2. Check not already a town (unless --force)
3. Create config/ directory
4. Write town.json with name and timestamp
5. Write empty rigs.json
6. Create mayor/ directory structure
7. Write CLAUDE.md from template
8. Create empty inbox.jsonl
9. Write initial state.json

## Error Cases

- Path does not exist: Create it (like mkdir -p)
- Already a town: Error unless --force
- Permission denied: Clear error message
- Inside existing town: Warn (nested towns not recommended)

## Templates

Mayor CLAUDE.md comes from embedded template (see gt-u1j.20).


gt spawn should create fresh polecat worktree, never reuse

Currently gt spawn tries to reuse existing polecats, which causes:

1. Stale beads database
2. Stale code (behind main/integration)
3. Old inbox messages
4. Git history pollution

## Current Behavior

gt spawn:
1. Looks for idle polecat in pool
2. If found, reuses existing worktree
3. Assigns new issue

## Desired Behavior

gt spawn:
1. Always create FRESH polecat from current main/integration
2. Fresh worktree with clean beads
3. No reuse of old worktrees

## Name Pool Still Useful

Keep name pool for:
- Allocating themed names (mad-max, etc.)
- Tracking which names are in use

But worktrees should be created fresh each time.

## Implementation

In spawn.go, before starting work:
1. If worktree exists: remove it first
2. Create fresh worktree from integration branch
3. Sync beads from rig to polecat
4. Then proceed with work assignment

This ensures polecats always start with latest code and beads.


Digest: mol-deacon-patrol

Patrol cycle 3: all systems nominal


Update Refinery to use Beads merge queue

Replace branch discovery with Beads queue in the Refinery module:

Current (internal/refinery/manager.go):
- Scans for polecat/* branches
- Creates MR objects on-the-fly

New:
- Pull from Beads: bd ready --type=merge-request
- Process each MR
- Close with merge commit: bd close <id> --reason="Merged at <sha>"
- Handle failures: bd update <id> --status=blocked --reason="..."

The Engineer (agent) becomes Beads-native.
The Refinery (module) provides the infrastructure.


Digest: mol-deacon-patrol

Patrol 10: healthy


Deacon primes pending workers instead of spawn nudge

## Problem

When gt spawn starts a polecat, it tries to send a nudge message immediately:
1. Starts tmux session with Claude Code
2. Waits 3 seconds (hardcoded)
3. Sends nudge via NudgeSession

But Claude Code takes 10-20+ seconds to be ready. The message arrives before
the prompt is ready, so it appears as part of the prompt string instead of
being executed.

## Solution

Move priming responsibility to the Deacon patrol cycle:

1. gt spawn: Mark polecat as pending_prime=true in state, return immediately
2. Deacon patrol: New step prime-pending-workers that:
   - Scans all rigs for workers with pending_prime=true
   - Uses WaitForClaudeReady() to poll for "> " prompt (already exists in tmux.go)
   - Once ready, sends gt prime + assignment nudge
   - Clears pending_prime flag

## Implementation

### spawn.go changes
- Remove the 3-second sleep (line 368)
- Remove the NudgeSession call (lines 375-383)
- Instead: Update polecat state with pending_prime=true

### Polecat state addition
status: assigned, pending_prime: true, issue: gt-xxx

### Deacon patrol addition
Add step between inbox-check and plugin-run:
prime-pending-workers: Check all rigs for workers marked pending_prime.
For each pending worker: WaitForClaudeReady(60s), then gt prime + nudge

### Benefits
- No race condition - we poll until actually ready
- Deacon already does health checks - priming is natural fit
- Works for polecats, witnesses, refineries, crew (unified approach)
- Timeout handling built in

## Depends on
- Existing WaitForClaudeReady() in tmux.go (lines 384-403)


Digest: mol-deacon-patrol

Patrol cycle 41: All agents healthy, no pending spawns, no orphans, inbox clean


Merge: dementus-mjxaqvb9

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


Digest: mol-deacon-patrol

Patrol 7: All healthy


Digest: mol-deacon-patrol

Patrol 1: inbox clear, witness/refinery healthy, no orphans, no plugins


Digest: mol-deacon-patrol

Patrol cycle 18: all healthy


Digest: mol-deacon-patrol

Patrol 3: All agents healthy.


Move disk 1: B → C

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


Add human escalation configuration

Add overseer contact config to mayor/town.json. Deacon uses this for escalation when it cannot resolve issues. Support email and/or other notification methods.


Digest: mol-deacon-patrol

Patrol cycle 8: All agents healthy


Digest: mol-deacon-patrol

Patrol cycle 5: All agents healthy


Witness: aggregate completion and notify Mayor

## Problem
No signal when swarm completes. Mayor must manually check.

## ZFC-Compliant Solution
Add step to `mol-witness-patrol.formula.toml`:

```toml
[[step]]
id = "check-swarm-completion"
title = "Report swarm completion to Mayor"
description = """
1. Check state.json for active swarm tracking:
   - swarm_id, start_time, assigned_beads[], completed_beads[]
2. For each completed merge (from cleanup step):
   - Add bead to completed_beads
3. If all assigned_beads are in completed_beads:
   - Calculate duration
   - Send summary to Mayor:
     gt mail send mayor/ -s "SWARM_COMPLETE: <swarm_id>" -m "All N polecats merged in Xm"
   - Clear swarm tracking from state.json
"""
depends_on = ["cleanup-merged-polecats"]
```

## Swarm Initialization
When Mayor slings a batch, they should:
```bash
# Mayor creates swarm tracking
gt mail send <rig>/witness -s "SWARM_START" -m '{"swarm_id": "batch-123", "beads": ["bd-a", "bd-b", "bd-c"]}'
```

Witness parses SWARM_START and initializes tracking in state.json.

## Why This Works
- Mayor initiates batch with SWARM_START mail
- Witness tracks progress in its own state
- Witness signals completion via mail
- All coordination is agent-to-agent via mail

## Files
- formulas/mol-witness-patrol.formula.toml


Merge: gt-cp2s

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


Witness session cycling and handoff

Add session cycling and handoff protocol to Witness CLAUDE.md template.

## Session Cycling Protocol

```markdown
## Session Cycling

Your context will fill over long swarms. Proactively cycle when:
- Running for many hours
- Losing track of which workers you've checked
- Responses getting slower
- About to start complex operation

### Handoff Protocol

1. **Capture current state**:
```bash
town list .           # Worker states
town all beads        # Pending verifications
town inbox            # Unprocessed messages
```

2. **Compose handoff note**:
```
[HANDOFF_TYPE]: witness_cycle
[TIMESTAMP]: <now>
[RIG]: <rig>

## Active Workers
<list workers and status>

## Pending Verifications
<workers signaled done but not verified>

## Recent Actions
<last 3-5 actions>

## Warnings/Notes
<anything next session should know>

## Next Steps
<what should happen next>
```

3. **Send handoff**:
```bash
town mail send <rig>/witness -s "Session Handoff" -m "<note>"
```

4. **Exit cleanly**: End session, daemon spawns fresh one.

### On Fresh Session Start

1. Check for handoff: `town inbox | grep "Session Handoff"`
2. If found, read it and resume from handoff state
3. If not found, do full status check
```

## Implementation

Add to WITNESS_CLAUDE.md template.


Polecat CLAUDE.md update for hook execution

Update polecat role CLAUDE.md to include hook execution instructions.

## Key Additions

### Startup Protocol

```markdown
## Startup Protocol

When you wake up:

1. **Check your hook first**
   Run: gt prime
   This shows your assigned work.

2. **If hook has molecule**
   You are running a workflow. Execute the current step.
   When done: bd mol advance <mol-id>

3. **If hook has slung bead**
   Work on that specific issue.
   Claim it: bd update <id> --status=in_progress

4. **If hook empty**
   Wait for assignment via mail or spawn.
```

### Work Completion

```markdown
## Completing Work

When you finish your assigned issue:

1. Commit changes: git add && git commit -m "description (issue-id)"
2. Push branch: git push -u origin <branch>
3. Create MR bead: bd create "Merge: <issue-id>" --type=merge-request
4. Close issue: bd close <issue-id> --reason "Fixed in commit abc123"
5. Sync: bd sync
6. Signal done: gt mail send witness/ -s "LIFECYCLE: Done" -m "Completed <issue-id>"
```

### Exit States

```markdown
## Exit States

When finishing, signal your state:

- COMPLETED: Work done successfully
- BLOCKED: Cannot proceed, need help
- ESCALATE: Problem beyond your scope
- HANDOFF: Passing to successor
```

## File

templates/polecat/CLAUDE.md


Built-in molecules: engineer-in-box, quick-fix, research

Create built-in molecules as Beads issues:

## engineer-in-box

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

Full workflow from design to merge.

## Step: design
Think carefully about architecture. Consider:
- Existing patterns in the codebase
- Trade-offs between approaches
- Testability and maintainability

Write a brief design summary before proceeding.

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

## Step: review
Self-review the changes. Look for:
- Bugs and edge cases
- Style issues
- Missing error handling
Needs: implement

## Step: test
Write and run tests. Cover happy path and edge cases.
Fix any failures before proceeding.
Needs: implement

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

## quick-fix

```markdown
id: mol-quick-fix
type: molecule
title: Quick Fix

Fast path for small changes.

## Step: implement
Make the fix. Keep it focused.

## Step: test
Run relevant tests. Fix any regressions.
Needs: implement

## Step: submit
Submit for merge.
Needs: test
```

## research

```markdown
id: mol-research
type: molecule
title: Research

Investigation workflow.

## Step: investigate
Explore the question. Search code, read docs,
understand context. Take notes.

## Step: document
Write up findings. Include:
- What you learned
- Recommendations
- Open questions
Needs: investigate
```

## Storage

Built-in molecules live in `<town>/.beads/` as regular issues.
Created during `gt install` or `bd init`.


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)


Crew worker grip in gastown - human-managed persistent workspace.

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


Add timeouts to convoy panel subprocess calls

convoy.go spawns bd and sqlite3 without timeouts. If these hang, the TUI freezes. Add 5-second context timeouts.


Move disk 1: B → C

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


Move disk 1: B → C

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


Merge: furiosa-1767138824776

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


Digest: mol-deacon-patrol

Patrol cycle 15: All 6 agents healthy


Digest: mol-deacon-patrol

Patrol 4: nominal


Digest: mol-deacon-patrol

Patrol 1: All agents healthy (2W 2R). 1 orphan (gt-mol-aux assigned to dead polecat). No incidents.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Day 2.7a: gt install creates Deacon and Mayor agent beads

Update gt install to create agent beads:

1. After initializing town beads, create:
   - gt-deacon agent bead (role_type: deacon, rig: null, agent_state: idle)
   - gt-mayor agent bead (role_type: mayor, rig: null, agent_state: idle)

2. Use bd create --type=agent or internal beads API

Files:
- internal/cmd/install.go

Moved to gt rig add instead of gt install due to routing constraints. Agent beads need to be in rig beads (not town beads) for daemon to find them via prefix routing. First rig added gets gt-deacon and gt-mayor.


Digest: mol-deacon-patrol

Patrol 3: All healthy, routine


Digest: mol-deacon-patrol

Patrol 11: Mayor OK, 11 sessions


mol-deacon-patrol


Merge: nux-mjw3mn8o

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


Digest: mol-deacon-patrol

Patrol 11: 3 rigs healthy


Merge: nux-mjw3mn8o


Outpost configuration: YAML config and OutpostManager

## Overview

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

## Config File

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

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

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

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

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

## OutpostManager

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

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

## Files

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Merge: dementus-mjw46vz4

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


Add nudge channels for real-time fan-out messaging

Add channel support to gt nudge for real-time fan-out.

## Semantics
- Ephemeral, real-time (tmux send-keys)
- Fan-out to all channel members
- Parallel to list:name but for nudge instead of mail

## Use Case
"Everyone send yourself gt handoff now" - real-time coordination.

## Syntax
gt nudge channel:workers "gt handoff"
gt nudge channel:witnesses "Swarm incoming"

## Implementation
1. Add nudge_channels to MessagingConfig schema
2. Extend gt nudge to recognize channel:name syntax
3. Expand channel to member list, nudge each

## Config Addition to messaging.json
```json
"nudge_channels": {
  "workers": ["gastown/polecats/*", "gastown/crew/*"],
  "witnesses": ["*/witness"],
  "all": ["@town", "@rig/*"]
}
```

## Relation to gt broadcast
gt broadcast is a one-off "everyone" nudge.
Nudge channels are named, configured subsets.

Could potentially deprecate gt broadcast in favor of:
gt nudge channel:all "message"


Extend auto-continue to polecats (not just crew)

gt prime currently only outputs AUTO-CONTINUE MODE for crew workers.
Polecats with attached work should also auto-continue.

## Current behavior
outputCrewAttachmentStatus() in prime.go:
- Only runs for RoleCrew
- Outputs '→ AUTO-CONTINUE MODE' when attached work detected

## Desired behavior
- Rename to outputAttachmentStatus() or similar
- Run for RoleCrew AND RolePolecat
- Same directive: if attachment exists, work immediately

## The Propulsion Principle
'If you find something on your hook, YOU RUN IT.'

This applies to ALL workers, not just crew.

## Implementation
1. Extend role check in outputCrewAttachmentStatus()
2. Adjust assignee detection for polecats vs crew
3. Test with both worker types


Move disk 2: B → A

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


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 4: All healthy


Digest: mol-deacon-patrol

Patrol 156 complete


gt mail archive/purge: Archive management

Add `gt mail archive` and `gt mail purge` commands.

### gt mail archive
```
gt mail archive [--older-than DAYS] [--all-read] [--dry-run]
```
- Move messages from inbox.jsonl to archive.jsonl
- Default: archive read messages older than 7 days

### gt mail purge
```
gt mail purge [--older-than DAYS] [--dry-run] [--force]
```
- Permanently delete from archive.jsonl
- Confirm unless --force

**Implementation:**
- Add to internal/cmd/mail.go
- Add Archive(), Purge() to internal/mail/mailbox.go
- Create archive.jsonl in same directory as inbox.jsonl


Digest: mol-deacon-patrol

Patrol: 4 msgs (2 blocked on bd mol current, 2 handoffs). 11 polecats, 18 sessions. Swarm in progress.


Merge: gt-h6eq.1

branch: polecat/nux
target: main
source_issue: gt-h6eq.1
rig: gastown


gt convoy create: Fix notify slot warning

When creating convoy with --notify, get warning:
```
⚠ Warning: couldn't set notify slot: exit status 1
```

But notification target still shows in status. Investigate slot setter.


Move disk 2: C → B

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


Test Task 2: Add comment to version.go


Digest: mol-deacon-patrol

Patrol 20: All healthy, handoff threshold reached


Digest: mol-deacon-patrol

Patrol 92: All healthy


Merge: morsov-mjwcd60m

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


Merge: gt-99a

branch: polecat/Slit
target: main
source_issue: gt-99a
rig: gastown


Digest: mol-deacon-patrol

Patrol 9: all clear


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 1: A → B

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


Merge: slit-1767079899677

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


Polecat template: move session close checklist into molecule steps

Template has prose checklists for 'Before Signaling Done' and 'SESSION CLOSE PROTOCOL'. These should be encoded as tail steps in the polecat molecule, not repeated as prose in CLAUDE.md. Reduces duplication and ensures the steps are actually followed.


Move disk 2: C → B

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 7: All clear


Move disk 3: B → C

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


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 10: All healthy.


Map expansion should match nested child steps


Recreate beads rigs with fresh clones

## Problem

Beads rigs have schema mismatches (missing thread_id column, etc.) from development iteration.

## Tasks

1. Shut down any active polecats
2. Delete existing beads rigs: mayor/rig, refinery/rig, witness/rig, crew/*
3. Re-clone from beads repo
4. Run bd init in each new clone

## Rigs to recreate

- /Users/stevey/gt/beads/mayor/rig
- /Users/stevey/gt/beads/refinery/rig
- /Users/stevey/gt/beads/crew/* (if any)

## Source

Clone from beads repo (need to confirm remote URL)


Move disk 3: B → C

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


Digest: mol-deacon-patrol

Cycle 19


Move disk 4: A → C

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


Verify initial state

All 3 disks stacked on peg A. Largest on bottom.


gt crew add: role_bead field references non-existent bead

## Problem

When `gt crew add` creates an agent bead (e.g., `gt-crew-gastown-grip`), it sets:
```
role_bead: gt-crew-gastown-grip-role
```

This is WRONG. It creates per-instance role bead references that don't exist.

## Correct Pattern

Role beads are SHARED templates defining what a role IS. Agent beads reference them:

| Role Type | Role Bead (shared) | Agent Bead (per-instance) |
|-----------|-------------------|---------------------------|
| Mayor | gt-mayor-role | gt-mayor |
| Deacon | gt-deacon-role | gt-deacon |
| Witness | gt-witness-role | gt-witness-<rig> |
| Refinery | gt-refinery-role | gt-refinery-<rig> |
| Crew | gt-crew-role | gt-crew-<rig>-<name> |
| Polecat | gt-polecat-role | gt-polecat-<rig>-<name> |

## Current State

Working correctly:
- gt-mayor → gt-mayor-role ✅
- gt-witness-gastown → gt-witness-role ✅
- gt-refinery-gastown → gt-refinery-role ✅

Broken:
- gt-deacon → gt-deacon-role (bead doesn't exist)
- gt-crew-* → gt-crew-<rig>-<name>-role (wrong pattern, beads don't exist)
- gt-polecat-* → (not set at all)

## Code Locations

1. `internal/cmd/crew_add.go:91` - sets `RoleBead: crewID + "-role"`
   Should be: `RoleBead: "gt-crew-role"`

2. `internal/polecat/manager.go:220,426` - doesn't set RoleBead
   Should set: `RoleBead: "gt-polecat-role"`

## Fix Required

1. Create missing role beads: gt-crew-role, gt-polecat-role, gt-deacon-role
2. Fix crew_add.go to use shared gt-crew-role
3. Fix polecat/manager.go to use shared gt-polecat-role
4. Update existing crew agent beads to point to gt-crew-role


mol-deacon-patrol


Move disk 6: A → C

Move disk 6 from peg A to peg C. (Move 992/1023)


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 9: All healthy


Swarm doesn't track dynamically added workers

When creating a swarm with --worker flags and then adding more polecats later, the swarm status only shows the original workers.

Steps to reproduce:
1. gt swarm create gastown --epic gt-i26df --worker slit --worker rictus --start
2. Add more polecats: gt polecat add gastown capable
3. gt sling gt-xxx gastown/capable
4. gt swarm status gt-i26df -> only shows slit, rictus

Expected: Swarm tracks all workers that are working on swarm tasks.
Actual: Only original workers shown.


Digest: mol-deacon-patrol

Patrol cycle 16: all healthy


Digest: mol-deacon-patrol

Patrol 20: all healthy


bd sync fails when .beads/redirect points to different repo


Digest: mol-deacon-patrol

Patrol 148: All healthy


Digest: mol-deacon-patrol

Cycle 15


attached_args: Standardize warning output to use style.Warning

Unify warning message formatting across codebase.

## Files to modify
- internal/cmd/start.go
- internal/cmd/polecat.go
- internal/cmd/mail.go
- Any other files with inconsistent warning output

## Current inconsistency
```go
fmt.Printf("%s Warning: ...", style.Dim.Render("⚠"))
fmt.Printf("Warning: %s", ...)
fmt.Fprintf(os.Stderr, "warning: ...")
```

## Standard pattern
Create helper if needed:
```go
// In internal/style/style.go
func PrintWarning(format string, args ...interface{}) {
    msg := fmt.Sprintf(format, args...)
    fmt.Printf("%s %s\n", Warning.Render("⚠ Warning:"), msg)
}
```

## Acceptance criteria
- [ ] PrintWarning helper in style package
- [ ] All warning outputs use consistent format
- [ ] Warnings go to stdout (not stderr) for consistency
- [ ] grep -rn 'Warning:' internal/cmd/ shows consistent format
- [ ] go build ./... passes


Design Convoy formula

## Design Convoy Formula

Structured design exploration for features/architecture.

### Input
- Problem statement or feature request

### Legs (parallel polecats)
| Leg | Focus | Output |
|-----|-------|--------|
| api | Interface design, ergonomics | api-design.md |
| data | Data model, storage, migrations | data-model.md |
| ux | User experience, CLI ergonomics | ux-analysis.md |
| scale | Performance at scale, bottlenecks | scalability.md |
| security | Threat model, attack surface | security.md |
| integration | How it fits existing system | integration.md |

### Synthesis
- Read all dimension analyses
- Identify conflicts and tradeoffs
- Propose unified design with options
- Flag decisions needing human input

### Command
```bash
gt formula run design --problem="Add notification levels to mayor"
# Creates design convoy
# Spawns dimension polecats
# Lands with design-doc.md
```


Digest: mol-deacon-patrol

Patrol 11: All agents healthy, cleaned 18 stale wisps


gt mol status: role detection fails from polecat directory

When running 'gt mol status' from a polecat's worktree directory (e.g., ~/gt/gastown/polecats/furiosa), the role detection incorrectly returns 'mayor' instead of 'gastown/furiosa'.

## Root Cause
The detectRole() function in prime.go calculates relPath from townRoot (~gt) to cwd (~/gt/gastown/polecats/furiosa), giving 'gastown/polecats/furiosa'. It then checks parts[0] == 'mayor' but 'gastown' != 'mayor', so it falls through to rig detection where it treats 'gastown' as a rig name.

However, the code then looks for parts[1] == 'polecats' but the actual check is parts[1] == 'polecats' which should work...

## Actual Issue
Need to debug further - the hook file IS created correctly by spawn, but gt mol status can't find it because it's looking for the wrong agent identity.

## Expected
Running from ~/gt/gastown/polecats/furiosa should detect:
- Role: polecat
- Rig: gastown
- Polecat: furiosa
- Agent identity: gastown/furiosa

## Actual
- Role: mayor
- Agent identity: mayor

This prevents polecats from seeing their slung work via gt mol status.


Digest: mol-deacon-patrol

Patrol 15


Session cycling UX: smooth transitions via TUI wrapper

## Problem

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

## GGT Advantages (already have)

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

## Gap: Transition Mechanics

Ideas to explore when actively using CLI:

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

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

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

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

## Deferred

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


Move disk 1: B → C

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


Move disk 3: B → C

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


Document merge queue architecture

Update docs/architecture.md with:

- Merge Queue section explaining Beads-native approach
- Engineer role (renamed from Refinery)
- Session restart protocol
- gt mq command reference
- Federation considerations for queue

Also update any references to .gastown/ → config/.


Move disk 1: C → A

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


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

Patrol 11: 8 sessions OK


Epic: Refinery Engineer Autonomy

Make Refinery Engineer fully autonomous:

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

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

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


Refinery startup: bond mol-refinery-patrol on start

Wire up Refinery to automatically bond its patrol molecule on startup.

## Current state
- mol-refinery-patrol exists in builtin_molecules.go
- prompts/roles/refinery.md describes the protocol
- Refinery doesn't auto-bond on startup

## Desired behavior
On Refinery session start:
1. gt prime detects RoleRefinery
2. Check for existing in-progress patrol: bd list --status=in_progress --assignee=refinery
3. If found: resume from current step
4. If not found: bd mol bond mol-refinery-patrol --wisp
5. Output patrol context to agent

## Implementation options
A) Add to gt prime (outputRefineryPatrolContext)
B) Add startup hook in refinery CLAUDE.md
C) Both (prime detects, template reinforces)

## Testing
- Start refinery session
- Verify patrol bonds automatically
- Kill mid-patrol, restart, verify resumes

## Depends on
- gt-3x0z.10 (existing issue for Refinery patrol)


Merge: slit-mjvtz18y

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


Add isAnnounceAddress() and parseAnnounceName() helpers to router.go

Add announce address detection to internal/mail/router.go.

PATTERN TO FOLLOW:
Look at isListAddress() and parseListName() at lines 53-60 as the template.

IMPLEMENTATION:
1. Add isAnnounceAddress(address string) bool - returns true if address starts with 'announce:'
2. Add parseAnnounceName(address string) string - extracts announce name after 'announce:'
3. Add var ErrUnknownAnnounce = errors.New("unknown announce channel")

FILE: internal/mail/router.go
TESTS: Add tests in internal/mail/router_test.go

Small, focused task - just address detection, not delivery.


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 18: Quiet


Digest: mol-deacon-patrol

Patrol cycle 12: all healthy


Move disk 2: B → A

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


gt mq submit: create MR from current branch

Implement 'gt mq submit' command that creates a merge-request bead.

Auto-detection logic:
1. Branch: current git branch
2. Issue: parse from branch name (polecat/Nux/gt-xyz → gt-xyz)
3. Target: main (or integration branch if --epic specified)
4. Worker: parse from branch name
5. Rig: current rig

Options:
- --branch BRANCH: explicit source branch
- --issue ISSUE: explicit source issue
- --epic EPIC: target integration/EPIC instead of main
- --priority P: override priority (default: inherit from source issue)

Creates merge-request bead and prints MR ID.

Reference: docs/merge-queue-design.md#creating-merge-requests


Implement

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


Move disk 1: A → B

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


Implement gt mq CLI commands

Add gt mq subcommands as sugar over bd:

- gt mq submit: Create MR for current branch
- gt mq list: Show open merge requests
- gt mq next: Show next MR ready to process
- gt mq process: Engineer processes the queue
- gt mq reorder <id> --after <x>: Change ordering via deps
- gt mq status <id>: Show MR details

All commands should work with the Beads data plane.


Digest: mol-deacon-patrol

Patrol 13: nominal


MessagingConfig: Add missing test cases

Missing test coverage:
1. Version > CurrentMessagingVersion rejection
2. Malformed JSON handling


Molecule converge: iterate until AI says done

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

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

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

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

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

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


Move disk 1: B → C

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Add gt deacon start/stop/status commands

Add CLI commands: gt deacon start (spawn gt-deacon session), gt deacon stop (kill session), gt deacon status (show health state). Similar to gt mayor commands.


Digest: mol-deacon-patrol

Patrol: slit handoff (landing protocol), polecats cleaned (0 now), 4 witness/refineries up


Move disk 1: C → A

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


Daemon: configurable heartbeat interval

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

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


Move disk 4: C → B

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


Digest: mol-deacon-patrol

Patrol cycle 80: All healthy


Digest: mol-deacon-patrol

Patrol 16: nominal


Digest: mol-deacon-patrol

Patrol 10: routine, all healthy


Digest: mol-deacon-patrol

Patrol cycle 17: All healthy.


Witness patrol: Add sibling-check for Refinery

Witness should check on Refinery health as part of patrol (village sibling watch).

## Implementation

1. Add `sibling-check` step to mol-witness-patrol
2. Use `gt peek <rig>/refinery 20` to check Refinery output
3. Check Refinery queue status: `gt mq list <rig>`
4. Look for:
   - Refinery session alive
   - Queue processing (if items present)
   - No stuck MRs (same MR in_progress for too long)
5. If Refinery seems stuck:
   - Send nudge or status request
   - Consider escalation to Deacon

## Acceptance
- Witness checks Refinery each patrol cycle
- Can detect stuck Refinery
- Provides backup oversight for merge queue


Digest: mol-deacon-patrol

Patrol 12


Digest: mol-deacon-patrol

Patrol 9: All healthy


Digest: mol-deacon-patrol

Patrol cycle 4: routine, healthy


gt prime: Refinery context detection and output

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


Digest: mol-deacon-patrol

Patrol 257 complete: no incidents


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 3: B → C

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


Move disk 1: B → C

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


Deprecate hook files, use pinned beads for propulsion

## Problem

Hook files were "deprecated" via comments but NOT eradicated. The code is all still there and actively used.

## Current State (NOT Done)

**Live hook file exists:**
- `/Users/stevey/gt/deacon/.beads/hook-deacon.json`

**Code still calling hook functions:**
- `resume.go:151` - WriteSlungWork
- `park.go:114` - ReadHook
- `spawn.go:407` - WriteSlungWork
- `molecule_step.go:293` - WriteSlungWork
- `molecule_step.go:368` - BurnHook

**Hook infrastructure still exists:**
- `internal/wisp/io.go` - All hook I/O functions
- `internal/wisp/types.go` - SlungWork, Wisp types, constants
- `.beads/.gitignore` - hook-*.json pattern

**14 docs still reference hooks:**
architecture.md, beads-data-plane.md, molecular-chemistry.md, molecules.md,
pinned-beads-design.md, polecat-lifecycle.md, polecat-wisp-architecture.md,
propulsion-principle.md, session-lifecycle.md, sling-design.md, vision.md,
wisp-architecture.md, witness-patrol-design.md, ~/gt/CLAUDE.md

## Goal: Total Eradication

1. Remove ALL hook file code from callers
2. Delete hook functions from internal/wisp/
3. Delete hook types and constants
4. Remove gitignore patterns
5. Delete any live hook files, convert to pinned beads
6. Update all documentation
7. Verify propulsion cycle works with pinned beads only


Digest: mol-deacon-patrol

Patrol 16: All healthy


Move disk 1: A → C

Move disk 1 from peg A to peg C.


Digest: mol-deacon-patrol

Patrol 84: All healthy, quiet


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


Move disk 2: A → C

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


Refinery: Add lifecycle-notify step to patrol

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

## Implementation

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

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

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


Polecat template: remove redundant 'Finding Work' section

The 'Finding Work' section (bd ready, bd list, bd show) is general-purpose guidance that may not apply to polecats who are spawned with specific work. Either remove for polecats or clarify this is for discovering additional work during execution.


Digest: mol-deacon-patrol

Cycle 17


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, no messages, no orphans


Digest: mol-deacon-patrol

Patrol cycle 17: All 6 agents healthy


Day 3.2: Witness reads agent beads for polecat state

Witness patrol reads polecat state from agent beads:
- bd list --type=agent --role_type=polecat
- For each, check state field
- If state=running, check progress
- If state=stuck, handle stuck protocol

No more PID/tmux inference.

Parent: gt-hwka3


Verify commit on main before nuke (not just MERGED signal)

Witness nukes on MERGED signal without verifying merge actually succeeded.

## Problem
MERGED signal means refinery ATTEMPTED merge. But:
- Merge could have failed after signal sent
- Merge could be to wrong branch
- MERGED could be for stale MR (already merged via different path)

## Fix
Before nuke, witness should verify:
```bash
# Get the commit SHA from the polecat branch
commit_sha=$(git rev-parse polecat/$name)

# Verify it's reachable from main
git merge-base --is-ancestor $commit_sha main
```

Only nuke if verification passes.

## Alternative
Refinery sends commit SHA in MERGED payload, witness verifies that specific SHA.


Merge: gt-3x1.3

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


Digest: mol-deacon-patrol

Patrol cycle 14: All healthy.


Digest: mol-deacon-patrol

Patrol 133: All healthy


Delete molecules_*.go files

Remove legacy Go-defined molecules:
- internal/beads/builtin_molecules.go
- internal/beads/molecules_patrol.go
- internal/beads/molecules_session.go
- internal/beads/molecules_work.go

Update install.go to cook formulas instead of seeding Go structs.
Update catalog.go if needed.


gt sling: nudge crew/mayor if session is running

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

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

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

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

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol @ 2025-12-24 20:23

Patrol complete: inbox clear, all agents healthy, no orphans


Move disk 1: C → A

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


gt mq list: doesn't show submitted MRs

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

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

## Expected
gt mq list should show submitted MRs

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


Digest: mol-deacon-patrol

Patrol cycle 18: 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.

## Second-Order Monitoring

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

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


Move disk 1: A → B

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


Remove dead code: splitLines first loop, unused methods.

## Dead code locations

### 1. internal/cmd/polecat.go (lines 1093-1106)
splitLines function has unreachable first loop:
```go
func splitLines(s string) []string {
    var lines []string
    for _, line := range filepath.SplitList(s) {  // DEAD: wrong function
        ...
    }
    lines = nil  // Discards above
    for _, line := range strings.Split(s, "\n") {  // This is what runs
        lines = append(lines, line)
    }
    return lines
}
```
**Fix:** Remove first loop and reset.

### 2. internal/townlog/logger.go (lines 277-279)
```go
func (e Event) JSON() ([]byte, error) {
    return json.Marshal(e)
}
```
**Fix:** Remove unused method.

### 3. internal/lock/lock.go (line 27)
```go
ErrStaleLock = errors.New("stale lock detected")
```
**Fix:** Remove unused error variable.

### 4. internal/witness/types.go (line 19)
```go
StatePaused State = "paused"
```
**Fix:** Remove unused state constant.

### 5. internal/refinery/manager.go (lines 527-538)
```go
func (m *Manager) getTestCommand() string { ... }
```
**Fix:** Remove unused method.

## Acceptance criteria
- [ ] polecat.go: Dead loop removed from splitLines
- [ ] townlog/logger.go: Event.JSON() method removed
- [ ] lock/lock.go: ErrStaleLock removed
- [ ] witness/types.go: StatePaused removed
- [ ] refinery/manager.go: getTestCommand removed
- [ ] go build ./... passes
- [ ] go test ./... passes


Digest: mol-deacon-patrol

Patrol cycle 20: all healthy, handing off


Digest: mol-deacon-patrol

Cycle 298: All healthy, refinery processing


Move disk 2: C → B

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


Move disk 1: B → C

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


mol-deacon-patrol


Move disk 3: A → B

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


Digest: mol-deacon-patrol

Patrol 9: nominal


gt sling/handoff fails: slashes in agent identity create invalid hook paths


Digest: mol-deacon-patrol

Patrol 2: All healthy - no changes from cycle 1


Merge: keeper-mjwcc4ik

branch: polecat/keeper-mjwcc4ik
target: main
source_issue: keeper-mjwcc4ik
rig: gastown
agent_bead: gt-gastown-polecat-keeper


Set GIT_AUTHOR_NAME per agent session

Set GIT_AUTHOR_NAME to actor string (e.g., gastown/crew/joe) in agent session environment. GIT_AUTHOR_EMAIL stays as workspace owner. Enables git log --author queries for agent work.


Merge: bix-mjufugoo

branch: polecat/bix-mjufugoo
target: main
source_issue: bix-mjufugoo
rig: gastown


Digest: mol-deacon-patrol

Patrol 17: all healthy


Digest: mol-deacon-patrol

Patrol 18: all clear


Delete hook types from internal/wisp

Delete from internal/wisp/types.go:
- WispType type
- TypeSlungWork constant
- HookPrefix, HookSuffix constants
- Wisp struct
- SlungWork struct
- NewSlungWork function
- HookFilename function
- AgentFromHookFilename function

The entire file may become empty or minimal.


Polecat prompting: gt mq submit on completion

Update Polecat CLAUDE.md prompting to:

1. On task completion, run: gt mq submit --issue <id>
2. This creates a merge-request bead in the queue
3. Engineer will process it

The Polecat self-reports completion to the merge queue.


Digest: mol-deacon-patrol

Patrol 18: All healthy


Merge: rictus-mjw3nj1a

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


Merge: gt-i4kq

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


Move disk 1: B → C

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


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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


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


gt rig reset: clear stale mail on reset/land

## Problem

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

## Current State

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

## Proposed Behavior

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

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

## Implementation

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


Clean up stale issue references in comments

Several code comments reference completed or tombstoned issues as if they're future work:

## Stale "will do" comments (issue is closed/done):

1. **daemon/daemon.go:313** - Says "gt-2hzl4 will add timeout fallback" but gt-2hzl4 is closed and the fallback is implemented at lifecycle.go:725. Update to past tense or remove.

2. **daemon/lifecycle.go:174** - Says "to be removed per gt-psuw7" but gt-psuw7 is closed. Either remove the legacy tmux detection code or update the comment.

## Tombstoned epic references (epic superseded):

3. **keepalive/keepalive_test.go:64** - "See gt-gaxo epic for rationale" - gt-gaxo is tombstone.

4. **cmd/doctor.go:100** - "See gt-gaxo epic for ZFC cleanup rationale" - gt-gaxo is tombstone.

## Action:
- Update stale comments to reflect current state
- Remove or update tombstone references
- For the lifecycle.go tmux detection: decide if code should stay or go


Digest: mol-deacon-patrol

Patrol 13: quiet


Digest: mol-deacon-patrol

Patrol 2: archived stale Mayor handoffs, all agents healthy


Test molecule

Test


Merge: gt-unrd

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


Digest: mol-deacon-patrol

Patrol 3: All healthy. 3 rigs, 6 agents. No incidents.


MEOW Stack Evolution: Higher-Order Workflow Abstractions

Molecular Expression of Work (MEOW) - the full taxonomy of workflow abstractions.

## Current Hierarchy

```
WORK TRACKING              WORKFLOW EXECUTION
─────────────              ──────────────────

Bead (issue)               Step (action)
    │                          │
    ▼                          ▼
Epic (bead group)          Molecule (runtime)
    │                          │
    ▼                          │
    └───────► CAMPAIGN ◄───────┘
                  │
                  ▼
             Schematic (domain template)
                  │
                  ▼
             Protocol (interface/type)
                  │
                  ▼
             Catalyst (meta-generator)
                  │
                  ▼
             Mol Mall (distribution)
```

## Key Concepts

1. **Campaign** (gt-camx5): Molecule-wrapped Epic graph for orchestrated execution
2. **Schematic** (gt-8ws7o): Domain-level formula composition
3. **Protocol** (gt-y3jb9): Type system for formulas
4. **SDK** (gt-ihzqr): Developer tooling (Forge, Lab, Validator)
5. **Mol Mall** (gt-vm85o): Package registry for distribution

## Design Principles

- Chemistry metaphor: atoms → molecules → compounds → materials
- Two orthogonal dimensions: work tracking × workflow execution
- Campaign is the convergence point
- Everything compiles down to executable molecules

## Origin

Discussion: 2024-12-26, Mayor session
Related: docs/formula_evolution.md
Foundation: gt-8tmz (Molecule Algebra)


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

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

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

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


Digest: mol-deacon-patrol

Patrol 18: healthy


Digest: mol-deacon-patrol

Patrol 10: All healthy, halfway mark


mol-deacon-patrol


SQL injection in convoy.go:581

User input interpolated directly into SQL via fmt.Sprintf(). convoyID from args[0] used in: fmt.Sprintf(`SELECT depends_on_id, type FROM dependencies WHERE issue_id = '%s'`, convoyID). Fix: Use parameterized queries.


Session ended: gt-gastown-crew-george


Digest: mol-deacon-patrol

Cycle 12


Move disk 2: B → A

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


Merge: gt-ay1r

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


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 16: routine


Move disk 3: B → C

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


Deacon plugin scheduler: cron-like execution

Implement scheduled plugin execution in the Deacon's plugins step.

## Concept

Plugins are just directories with config. Deacon checks which are due
and executes them during the plugins step of rounds.

## Plugin Registration

Plugins are registered in:
1. Pinned kernel bead (preferred)
2. `{townRoot}/plugins/` directory scan (fallback)

Each plugin has:
```json
{
  "name": "beads-hygiene",
  "schedule": "0 2 * * *",
  "last_run": "2025-12-20T02:00:00Z",
  "enabled": true,
  "attention_budget": "low",
  "max_duration_minutes": 30
}
```

## Schedule Format

Standard cron format: `minute hour day month weekday`
- `0 2 * * *` - 2 AM daily
- `0 4 * * 0` - 4 AM Sundays
- `*/15 * * * *` - Every 15 minutes

## Execution

During plugins step:
1. Load plugin schedules from kernel bead + directory
2. For each plugin:
   a. Parse schedule, check if due (last_run + schedule)
   b. If due, execute:
      - Read `plugins/{name}/CLAUDE.md` for context
      - Run plugin logic (inline or spawn subagent)
      - Record outcome and update last_run
3. Continue to next step

## Plugin Execution Modes

- **inline**: Deacon runs the plugin logic directly (simple, fast)
- **subagent**: Spawn a polecat-like agent for the plugin (complex, parallel)
- **mail**: Send mail to another agent to do the work (delegation)

## State Tracking

`{townRoot}/deacon/plugin-state.json`:
```json
{
  "plugins": {
    "beads-hygiene": {
      "last_run": "2025-12-20T02:00:00Z",
      "last_outcome": "success",
      "run_count": 42,
      "failure_count": 2
    }
  }
}
```

## Relation to gt-axz

This implements the execution side of the plugin architecture (gt-axz).
gt-axz defines the format; this task implements the scheduler.


Move disk 2: B → A

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


Move disk 1: A → B

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


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


Move disk 2: B → A

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


Move disk 1: B → C

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


Agent beads hook_bead field never populated

## Problem

The witness patrol formula expects polecat agent beads to have:

  hook_bead: <current-work-id>

This field is used by the witness to see what the polecat is working on.

But looking at the code, hook_bead is never set:

1. Polecat agent bead created (polecat/manager.go:167-170) - no hook_bead
2. reportAgentState called (prime.go:1067) - passes nil for hookBead
3. UpdateAgentState preserves existing hook_bead if nil (beads.go:633-635)

Since hook_bead starts empty and is never updated, the witness cannot use
agent beads to see what polecats are working on.

## Found in commit

f3a6ef6 (feat: Witness reads polecat state from agent beads)

## Related to

- gt-0lop3 (Agent state lifecycle incomplete for polecats)

## Suggested fix

When a polecat is assigned work (via gt sling or similar), update the agent
bead's hook_bead field:

  bd.UpdateAgentState(agentID, 'running', &hookBeadID)


Update role prompts with hook protocol

Update role prompt templates to include hook-first protocol.

Templates to update:
- polecat.md.tmpl
- deacon.md.tmpl
- witness.md.tmpl
- refinery.md.tmpl
- crew.md.tmpl

Each should include:
1. Check hook first (gt mol status)
2. If empty, check mail for attached work
3. Self-pin protocol if needed


Move disk 1: A → B

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


Add gt role command group with env-based role detection

# gt role Command Group

Make role detection less fragile by using env var injection instead of cwd detection.

## Env Vars
- `GT_ROLE` - authoritative role name (mayor, witness, refinery, polecat, crew)
- `GT_ROLE_HOME` - canonical home directory for the role

## Detection Precedence
1. `$GT_ROLE` env var (authoritative)
2. Fall back to cwd-based detection (legacy/manual)
3. Warn if they disagree

## Subcommands
- `gt role` / `gt role show` - show current role
- `gt role home [ROLE]` - show home dir for role
- `gt role detect` - force cwd-based detection (debugging)
- `gt role list` - list all known roles
- `gt role env` - print export statements

## Integration Points
- gt prime - show role, warn on mismatch
- gt mol status - use gt role instead of own detection
- gt handoff - preserve GT_ROLE, reset to home
- All spawners - inject GT_ROLE and GT_ROLE_HOME

## Background
Mayor wandered to refinery dir, handoff preserved it, role detection broke.
Env var injection makes role stable across cd operations.


Move disk 1: C → A

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


CLI: mayor commands (start, attach, stop, status)

Mayor management CLI commands.

## Commands

### gt mayor start
```
gt mayor start [--continue] [--agent AGENT]
```
- --continue: Resume from previous session (check for handoff mail)
- --agent: claude (default) or other agent type

### gt mayor attach
```
gt mayor attach
```
Attach to running Mayor session.

### gt mayor stop
```
gt mayor stop [--grace-period N]
```
Stop Mayor session with optional grace period.

### gt mayor status
```
gt mayor status [--json]
```
Show Mayor running status.

## Session Management
Session name: `gt-mayor`
Working directory: `<town>/mayor/rig/` or `<town>/mayor/`

## Implementation
Similar to session commands but for special Mayor context.

```go
func getMayorPath(townRoot string) string {
    return filepath.Join(townRoot, "mayor")
}

func getMayorSessionName() string {
    return "gt-mayor"
}
```

## New File
internal/cmd/mayor.go

## PGT Reference
gastown-py/src/gastown/cli/mayor_cmd.py

## Acceptance Criteria
- [ ] gt mayor start launches Mayor session
- [ ] gt mayor attach works
- [ ] gt mayor stop with grace period
- [ ] gt mayor status shows running state


Digest: mol-deacon-patrol

Patrol #6: All quiet, 1 dog idle.


Move disk 2: A → C

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


Phase 3: Polecat Work Cycle

# Phase 3: Polecat Work Cycle

The complete lifecycle of a single polecat working a single issue.

## The Cycle

```
spawn → wake → prime → read hook → work → submit → complete → cleanup
```

## Step by Step

### 1. Spawn (Deacon/Mayor initiates)

```bash
gt spawn --issue gt-xxx --rig gastown
```

Creates fresh worktree, assigns issue, creates polecat session.

### 2. Wake (Claude starts)

Polecat Claude session starts. SessionStart hook fires.

### 3. Prime (Context loads)

```bash
gt prime  # Runs automatically via hook
```

Loads CLAUDE.md, injects beads context, checks hook.

### 4. Read Hook

gt prime finds the assigned issue on the hook:

```
## Your Hook: gt-xxx

You have been assigned this issue. Begin work now.

Title: Fix authentication bug
Priority: P1
Description: ...

Claim it with: bd update gt-xxx --status=in_progress
```

### 5. Work

Polecat:
- Claims issue: `bd update gt-xxx --status=in_progress`
- Reads relevant code
- Makes changes
- Commits with issue ID

### 6. Submit

Polecat:
- Pushes branch
- Creates MR bead: `bd create "Merge: gt-xxx" --type=merge-request`
- Signals completion

### 7. Complete

Polecat:
- Closes the issue: `bd close gt-xxx --reason "Fixed in commit abc123"`
- Syncs beads: `bd sync`

### 8. Cleanup

Polecat:
- Sends completion mail to Witness
- Session terminates (or awaits next assignment)

## The mol-polecat-work Molecule

This is already defined. The polecat should be bonded to it on spawn.

Key steps:
1. orient - Read context, understand codebase
2. claim - Update issue status
3. work - Implement the fix
4. test - Run tests, verify
5. submit - Push, create MR
6. handoff - Signal done, sync

## Implementation

### gt spawn enhancements

- Automatically pin mol-polecat-work to new polecat
- Pass issue ID as variable
- Ensure hook is set before Claude starts

### Polecat CLAUDE.md

Must include:
- Hook reading instructions
- Molecule execution pattern
- Exit state vocabulary (COMPLETED, BLOCKED, ESCALATE)

## Acceptance Criteria

- gt spawn creates polecat with issue on hook
- Polecat wakes and begins work automatically
- Polecat completes issue and submits MR
- Issue is closed with commit reference


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.


Move disk 3: A → B

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Code review: await-signal command (gt-vdprb.1)

Review the await-signal molecule step implementation in internal/cmd/molecule_await_signal.go


Digest: mol-deacon-patrol

Patrol 1: 3 rigs healthy, no incidents


Meta-formulas: formula generators

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


Execute registered plugins

Execute registered plugins.

Scan ~/gt/plugins/ for plugin directories. Each plugin has a plugin.md with TOML 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.


End-of-cycle inbox hygiene

Verify inbox hygiene before ending patrol cycle.

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

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

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

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

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

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


Move disk 4: B → A

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


Witness: Handle LIFECYCLE work-merged mail

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

## Implementation

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 1: B → C

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


Move disk 3: B → C

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


mol-deacon-patrol


Merge: gt-h1n5

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


gt mol step done: Auto-continue molecule on step completion

## Summary

Implement `gt mol step done <step-id>` command that enables polecats to close a molecule step and automatically continue to the next step without waiting for witness orchestration.

## Problem

Currently, when a polecat completes a molecule step:
1. Polecat sends POLECAT_DONE to witness
2. Witness (in patrol cycle) eventually reads mail
3. Witness spawns next step
4. **Minutes of latency possible**

Polecats also forget to close beads steps (using internal TodoWrite instead), breaking the activity feed.

## Solution

`gt mol step done <step-id>` handles everything:

1. Close the beads step (`bd close <step-id>`)
2. Extract molecule ID from step (bd-mol-xga.1 → bd-mol-xga)
3. Find next ready step (dependency-aware)
4. If next step exists:
   - Update hook file to point to next step
   - Write handoff context
   - tmux respawn-pane (fresh claude session)
5. If molecule complete:
   - Clear hook
   - Send POLECAT_DONE to witness
   - Exit session

## Key Insight

Step-to-step transitions are **mechanical**, not **cognitive**. No AI needed in the critical path. Pure Go automation.

## Related Commands

- `gt mol next <mol-id>` - Show next ready step(s)
- `gt mol progress <mol-id>` - Already exists

## Polecat Protocol Update

```markdown
When your hook contains a molecule step:
1. Read the step: `bd show <step-id>`
2. Execute the work described
3. When complete: `gt mol step done <step-id>`

That is it. Do NOT manually close steps. Do NOT work multiple steps.
```

## Benefits

- **Instant step transitions** (~5-10s vs minutes)
- **Activity feed works** (steps closed as completed)
- **Witness freed up** (safety net only, not critical path)
- **Fresh context per step** (better attention, no accumulated confusion)


Witness should nuke polecats after completion, not leave idle

## Problem
Polecats are supposed to be ephemeral - fully despawned (nuked) after completing work. Currently the witness:
1. Receives POLECAT_DONE signal
2. Marks polecat as 'idle'
3. Stops there

This leaves zombie polecats with tmux sessions and git worktrees lingering indefinitely.

## Evidence
14 beads polecats sitting 'idle' with stopped sessions after completing work in the Boot+Polish swarm.

## Expected Behavior
After polecat completes (MR submitted or other exit):
1. Witness verifies work is pushed/merged
2. Witness nukes the polecat (session, worktree, branch, agent bead)
3. Polecat no longer exists

Polecats are disposable single-task workers, not persistent like crew.

## Impact
- Accumulating tmux sessions
- Accumulating git worktrees
- Accumulating disk usage
- Confusion about available workers


Beads epic templates for batch work patterns

Optional: Define templates for common batch work patterns.

## Concept

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

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

## Usage

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

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

## Decision Point

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

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

## Note

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


Polecat Role Definition

You are a Polecat - an autonomous worker assigned to a specific issue.

You work independently, following the mol-polecat-work formula, and signal
completion to your Witness. You are transient - spawned for work, cleaned up
after completion.

session_pattern: gt-{rig}-{name}
work_dir_pattern: {town}/{rig}/polecats/{name}
needs_pre_sync: true
start_command: export GT_ROLE=polecat GT_RIG={rig} GT_POLECAT={name} BD_ACTOR={rig}/polecats/{name} && claude --dangerously-skip-permissions

default_molecule: mol-polecat-work
capabilities:
  - execute_assigned_work
  - git_operations
  - branch_management
  - completion_signaling

## Core Responsibilities

1. Execute your pinned molecule's steps
2. Maintain clean git state
3. Signal completion via gt done
4. Wait for Witness to handle lifecycle

## You Do NOT

- Push directly to main (Refinery merges)
- Kill your own session (Witness does cleanup)
- Skip verification steps
- Work on anything other than your assigned issue

## Propulsion Principle

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

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

## Completion Protocol

When done:
1. Tests pass: go test ./...
2. COMMIT changes: git add and git commit
3. Push branch: git push -u origin HEAD
4. Close issue: bd close <issue>
5. Sync beads: bd sync
6. Run gt done
7. WAIT: Witness will kill your session

## Communication

Mail your Witness when stuck:
gt mail send <rig>/witness -s "HELP: <problem>" -m "..."


Merge: rictus-1767084016819

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