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.


Rig management: discover, load, create rigs

Rig discovery, loading, and creation.

## Interface

```go
type Rig struct {
    Name      string
    Path      string
    GitURL    string
    Config    RigConfig
    Polecats  []string
    HasWitness bool
    HasRefinery bool
}

type RigManager struct {
    townRoot string
    config   *Config
    git      *Git
}

func NewRigManager(townRoot string, config *Config, git *Git) *RigManager

// Discovery
func (rm *RigManager) DiscoverRigs() ([]*Rig, error)
func (rm *RigManager) GetRig(name string) (*Rig, error)
func (rm *RigManager) RigExists(name string) bool

// Creation
func (rm *RigManager) AddRig(name, gitURL string) (*Rig, error)
func (rm *RigManager) RemoveRig(name string) error

// Rig state
func (rm *RigManager) LoadRigConfig(rig *Rig) error
func (rm *RigManager) SaveRigConfig(rig *Rig) error
```

## Discovery Logic

1. Read rigs.json from config/
2. For each registered rig, verify directory exists
3. Load rig-level config if present
4. Scan for polecats/ subdirectory
5. Check for witness/, refinery/ directories

## Rig Creation

1. Clone repo to town root
2. Add entry to rigs.json
3. Create agent directories (polecats/, witness/, refinery/, mayor/)
4. Update .git/info/exclude to ignore agent dirs
5. Initialize rig config

## Rig Structure

Per docs/architecture.md:
```
<rig>/
├── polecats/
├── refinery/rig/
├── witness/rig/
└── mayor/rig/
```


Test issue 1 for displacement


Move disk 3: A → B

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


Code review: handoff.go changes (gt-yt6g, gt-tocb)

Review ~80 lines of Go changes to internal/cmd/handoff.go:

## Commits to review
- 1414081: Standardize session end with gt handoff (gt-yt6g)
  - Detect polecats via GT_POLECAT env var
  - Call gt done instead of respawning for polecats
  - +31/-11 lines

- 9c85b83: Support full session paths in gt handoff (gt-tocb)
  - resolveRoleToSession accepts <rig>/crew/<name>, <rig>/witness, <rig>/refinery
  - +46/-3 lines

## Review focus
- Error handling in path resolution
- Edge cases in polecat detection
- Test coverage needed?


Digest: mol-deacon-patrol

Patrol 5: routine


Digest: mol-deacon-patrol

Cycle 199: Nominal


Verify initial state

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


Add crew auto-start config to gt start

gt start needs a config file to specify:
- Which crew members auto-start per rig
- Which rigs to auto-start (instead of requiring --all or --rigs flags)

Requested defaults:
- beads rig: dave
- gastown rig: max, joe

This would allow 'gt start' to bring up the configured crew without manual flags.


Digest: mol-deacon-patrol

Patrol 8: all quiet


Fix CLI mismatches from bd-2fs7 (wisp->ephemeral migration)

bd-2fs7 moved wisp/pour under bd mol, but gastown wasn't updated.

Fixed:
- router.go: --wisp -> --ephemeral for bd create
- patrol_helpers.go: bd wisp create -> bd mol wisp create
- wisp_check.go: bd wisp gc -> bd mol wisp gc

This was causing handoff failures (gt mail send errored with 'unknown flag: --wisp').


Move disk 4: C → B

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


gt mq: Priority-ordered queue display and processing

Update MQ commands and refinery to process by priority score.

## Changes to gt mq list
- Add 'SCORE' column
- Sort by score descending
- Show convoy info if tracked

## Changes to gt mq next
- Return highest-score MR (not oldest)
- Or: `gt mq next --strategy=priority` (keep fifo as option)

## Changes to Refinery
- Query MQ with priority ordering
- Process highest-score first

## Implementation
- Add ScoreMR function (from gt-si8rq.1)
- Update mq.go query to include score calculation
- Update refinery formula to use priority ordering

## Output Example
```
ID         SCORE  PRI  CONVOY        BRANCH                AGE
gt-abc     87.5   P1   hq-cv-xyz     polecat/foo-123       2h
gt-def     72.3   P2   hq-cv-abc     polecat/bar-456       45m
gt-ghi     45.0   P3   (none)        polecat/baz-789       10m
```


Check Witness and Refinery health

Check Witness and Refinery health for each rig.

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

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

**Signals to assess:**

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

**Tracking unresponsive cycles:**

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

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

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

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

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

Reset unresponsive_cycles to 0 when component responds normally.


attached_args: Refactor runStartCrew into focused helper functions

Break up the 155-line runStartCrew function in start.go.

## Files to modify
- internal/cmd/start.go

## Current structure (lines 638-792)
runStartCrew does:
1. Parse crew target (rig/name)
2. Load rig config
3. Get/create crew workspace
4. Create/attach tmux session
5. Set environment variables
6. Apply theming
7. Start Claude

## Refactoring plan
Extract these helpers:
```go
func parseCrewTarget(args []string) (rigName, crewName string, err error)
func ensureCrewWorkspace(rig *rig.Rig, crewName string) (*crew.CrewWorker, error)
func startCrewSession(worker *crew.CrewWorker, opts CrewStartOpts) error
```

## Acceptance criteria
- [ ] runStartCrew reduced to <60 lines
- [ ] 3 helper functions extracted
- [ ] Each helper is <50 lines
- [ ] No change in behavior
- [ ] go test ./internal/cmd/... passes
- [ ] Manual test: gt start crew works correctly


Digest: mol-deacon-patrol

Patrol 14: Mayor OK, 11 sessions


Digest: mol-witness-patrol

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


Load persisted patrol state

Read handoff bead and get nudge counts.

Load persistent state from the witness handoff bead:
- Active workers and their status from last cycle
- Nudge counts per worker per issue
- Last nudge timestamps
- Pending escalations

```bash
bd show <handoff-bead-id>
```

If no handoff exists (fresh start), initialize empty state.
This state persists across wisp burns and session cycles.


Move disk 1: B → C

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


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

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


Digest: mol-deacon-patrol

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


Move disk 5: B → C

Move disk 5 from peg B to peg C. (Move 816/1023)


QUICK FIX: Make gt crew start use NudgeSession instead of SendKeys

## The Immediate Problem
`gt crew start gus` fails to deliver the GUPP nudge because:
1. Uses `t.SendKeys(sessionID, "gt prime")` which has the Enter-concatenation bug
2. Should use `t.NudgeSession()` which solves this reliably

## Quick Fix
In start.go, change line ~809:
```go
// Before
if err := t.SendKeys(sessionID, "gt prime"); err != nil {

// After
if err := t.NudgeSession(sessionID, "gt prime"); err != nil {
```

Same fix needed in:
- start.go:756 (restart path)
- crew_lifecycle.go:354
- crew_lifecycle.go:525

## Why This Is P0
Cold starts of crew workers are broken. This blocks basic usage.

## Note
This is a stopgap. The full solution is the StartupNudge refactor (gt-bgfqy).


Wire polecat-CLAUDE.md template into polecat spawn

The templates/polecat-CLAUDE.md file needs to be copied into each polecat worktree when spawned.

Location: templates/polecat-CLAUDE.md
Target: polecats/<name>/CLAUDE.md (with {{rig}} and {{name}} substituted)

Implementation:
- Update gt polecat spawn (or wherever worktrees are created)
- Template substitution for {{rig}}, {{name}} variables
- Ensure file is created before Claude session starts


Digest: mol-deacon-patrol

Patrol cycle 19: All healthy


Move disk 4: A → C

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


Move disk 3: B → C

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


Deacon trigger-pending-spawns: Auto-nudge polecats when ready

The Deacon's mol-deacon-patrol defines a trigger-pending-spawns step, but it's not implemented.

## Problem
After gt spawn creates a polecat session, Claude initializes for 10-20s. Nobody sends the initial 'Begin.' message to start work, so polecats sit at prompts forever.

## Current Workaround
Manual: gt nudge gt-<rig>-<polecat> 'Begin.'

## Required Implementation
1. Track pending spawns (polecats spawned but not triggered)
2. In Deacon patrol, poll WaitForClaudeReady for each pending spawn
3. When ready, send 'Begin.' via NudgeSession
4. Mark as triggered

## Evidence
Tracer bullet 2025-12-23: Had to manually nudge polecat/tracer to start work.


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 723/1023)


Day 5.2: Fix integration issues

Address any issues found in Day 5.1:
- Debug failures
- Fix edge cases
- Retry integration test
- Document remaining gaps

This is buffer time for reality.

Parent: gt-oki8p


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.


Bubbletea TUI dashboard

Interactive TUI using Charm Bubbletea. Root model, view routing, Lipgloss theme. Includes: dashboard, rig explorer, polecat detail with live tail, mail view, beads view, spawn wizard.


Digest: mol-deacon-patrol

Patrol #11: Quick cycle, all quiet.


Digest: mol-deacon-patrol

Patrol 15: all healthy


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 18: nominal


Move disk 1: B → C

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 4: All clear


Digest: mol-deacon-patrol

Patrol cycle 22 complete. All 3 rigs healthy. No orphans, gates, convoys, or plugins. Quick cycle.


Move disk 3: C → A

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


Merge: gt-5af.6

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


Merge: gt-7919

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


Digest: mol-deacon-patrol

Patrol 3: All healthy, no issues


Move disk 2: C → B

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


Merge: gt-si8rq.9

branch: polecat/nux-mjyruwvu
target: main
source_issue: gt-si8rq.9
rig: gastown
agent_bead: gt-gastown-polecat-nux
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Digest: mol-deacon-patrol

Patrol 4: stable


Digest: mol-deacon-patrol

Patrol 6: All healthy.


Digest: mol-deacon-patrol

Patrol 2: 3 rigs healthy, no incidents


gt-polecat-gastown-morsov

gt-polecat-gastown-morsov

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


Move disk 2: B → A

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


Witness should verify polecat submitted before stopping session

## Problem

Witness stopped dementus's session before it could call `gt done`, losing the MR submission. I had to manually push and submit the branch.

## Root Cause

Witness cleanup is triggered by nudge/manual check rather than by receiving POLECAT_DONE message. When Witness cleans up based on issue status (closed), it doesn't wait for the polecat to complete its shutdown sequence.

## Expected Behavior

Witness should only stop a polecat session after:
1. Receiving POLECAT_DONE message from that polecat, OR
2. Timeout waiting for POLECAT_DONE after issue is closed

## Current Behavior

Witness stops sessions immediately when asked to check for completions, even if polecat hasn't called `gt done` yet.

## Fix

In mol-witness-patrol inbox-check step:
- Only clean up polecats that have sent POLECAT_DONE
- For polecats with closed issues but no DONE message, nudge them to complete
- Add timeout before force-killing


Digest: mol-deacon-patrol

Patrol 7: nominal


Merge: rictus-mjuic92c

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


Witness template uses non-existent --assignee flag on bd mol wisp

## Bug

The witness.md.tmpl template uses an invalid flag:

```
bd mol wisp mol-witness-patrol --assignee={{ .RigName }}/witness
```

But `bd mol wisp` does NOT support the `--assignee` flag (only `--dry-run`, `--var`, and global flags).

## Location

`internal/templates/roles/witness.md.tmpl:142`

## Fix

Use the two-step pattern like the deacon template does:

```bash
bd mol wisp create mol-witness-patrol
bd update <wisp-id> --status=pinned --assignee={{ .RigName }}/witness
```

## Impact

Witness agents following the template will get a CLI error when trying to create patrol wisps.


Digest: mol-deacon-patrol

Patrol 79: Routine


Move disk 1: B → C

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


Move disk 2: C → B

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


Check own context usage.

Check own context usage.

If context is HIGH (>80%):
- Write handoff summary
- Prepare for burn/respawn

If context is LOW:
- Can continue processing

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


Move disk 2: C → B

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


Verify deacon patrol loop executes

Verify the deacon runs its patrol formula:

1. Start deacon: `gt daemon start`
2. Watch deacon session: `tmux attach -t gt-deacon`
3. Verify it cycles through:
   - inbox-check
   - trigger-pending-spawns
   - gate-evaluation
   - health-scan
   - orphan-check
   - session-gc
   - context-check
   - loop-or-exit

The deacon should continuously patrol, not stall.

Test: Watch 2-3 patrol cycles complete.


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 2: all healthy, no action needed


Move disk 1: C → A

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


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 14


Digest: mol-deacon-patrol

Patrol 158 complete


Digest: mol-deacon-patrol

Patrol 14: Quiet


Digest: mol-deacon-patrol

Patrol 7: Quiet


Digest: mol-deacon-patrol

P8: stable


verify-town-health

Final verification that Gas Town is healthy.

## Action
```bash
gt status
```

## Verify
1. Daemon running: Shows daemon status OK
2. Deacon active: Shows deacon in patrol mode
3. All witnesses: Each rig witness shows active
4. All refineries: Each rig refinery shows active

## OnStall
N/A - this is a read-only verification step.

## OnFail
Log degraded state but consider boot complete. Some agents may need manual recovery.
Run `gt doctor` for detailed diagnostics.


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


Digest: mol-deacon-patrol

Patrol 16: quiet


Digest: mol-deacon-patrol

Patrol 15: Quiet


Restart daemon to activate Boot integration

The running daemon (PID 70670) predates Boot code. Daemon heartbeat() now calls ensureBootRunning() but the stale process never executes it.

Fix: gt shutdown --force && gt start

This is a one-time operational task, not a code change.


Digest: mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 4: Quick cycle, all quiet


load-context

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

Read the assigned issue ({{issue}}) and understand the requirements.
Identify any blockers or missing information.


Digest: mol-deacon-patrol

Patrol cycle 18: All healthy.


Polecat: Clean exit after MR submission

Update polecat workflow to be truly ephemeral after MR submission.

## Current Behavior
- Polecat submits MR
- Polecat waits for merge or rebase request
- Session stays alive, sandbox persists

## New Behavior
- Polecat submits MR
- Polecat closes its work bead (status=in_review or similar)
- Polecat signals 'recyclable' to Witness
- Sandbox can be cleaned up after branch is pushed

## Implementation
1. Update mol-polecat-work.formula.toml
2. Add explicit 'submit and exit' step
3. Ensure branch is pushed before sandbox cleanup
4. Signal Witness that polecat is recyclable

## Considerations
- Sandbox cleanup can be deferred (worktrees are cheap)
- Or: Witness runs cleanup patrol for idle polecats

Implemented: Updated mol-polecat-work.formula.toml (v4) for ephemeral polecat model. Polecats now submit via gt done and become recyclable. No longer wait for Witness termination or close their own issues.


Move disk 2: B → A

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


Test merge request

branch: polecat/Test/gt-test
target: main
source_issue: gt-test
worker: TestWorker
rig: gastown


Digest: mol-deacon-patrol

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


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

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


Mayor session cycling prompting

Add session cycling section to Mayor CLAUDE.md template.

## When to Cycle

Cycle proactively when:
- Running for several hours
- Context feels crowded (losing track of earlier state)
- Major phase completed
- About to start complex new work

## Composing Handoff Notes

1. Gather information:
   town status    # Overall health
   town rigs      # Each rig state
   town inbox     # Pending messages
   bd ready       # Work items

2. Compose note with this structure:

[HANDOFF_TYPE]: mayor_cycle
[TIMESTAMP]: <current time>
[SESSION_DURATION]: <how long running>

## Active Swarms
<per-rig swarm status>

## Rig Status
<table of rig health>

## Pending Escalations
<issues needing your decision>

## In-Flight Decisions
<decisions being made>

## Recent Actions
<last 5-10 things you did>

## Delegated Work
<work sent to refineries>

## User Requests
<pending user asks>

## Next Steps
<what next session should do>

## Warnings/Notes
<critical info for next session>

3. Send handoff:
   town mail send mayor/ -s "Session Handoff" -m "<note>"

4. End session - next instance picks up from handoff.


Phase 1.1: gt rig init creates .beads-ephemeral/

Add ephemeral beads repo creation to rig initialization.

## Implementation

In `gt rig init` (or equivalent setup):
1. Create `<rig>/.beads-ephemeral/` directory
2. Initialize as git repo
3. Create minimal beads config (no sync-branch needed)
4. Add to .gitignore if not already

## Config

```yaml
# .beads-ephemeral/config.yaml
ephemeral: true
# No sync-branch - ephemeral is local only
```

## Verification

```bash
gt rig init gastown
ls gastown/.beads-ephemeral/  # Should exist
```


Design Deacon molecule health-check step

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

**New molecule step: health-scan**

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

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

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


Day 2.1: Daemon reads agent bead state field

Daemon queries agent beads for state instead of inferring from PID/tmux.

Change getAgentState() to:
1. Look up agent bead by ID (gt-mayor, gt-witness, etc.)
2. Read state field (idle|running|stuck|stopped)
3. Trust the value

Parent: gt-d0jqp


BUG: Boot spawns in wrong session (gt-deacon instead of gt-deacon-boot)

## Problem

Boot (the Deacon's watchdog) is supposed to spawn in its own session `gt-deacon-boot` per the code:
```go
const SessionName = "gt-deacon-boot"
```

But when checking tmux, Boot appears to be running in the `gt-deacon` session with cwd `dogs/boot`.

## Evidence

```
$ tmux capture-pane -t gt-deacon -p
⏺ Bash(cd /Users/stevey/gt/deacon && gt feed --since 10m --plain 2>/dev/null)
  Shell cwd was reset to /Users/stevey/gt/deacon/dogs/boot
```

## Impact

- `gt status` shows Deacon as "stopped" when Boot is running in its session
- Boot and Deacon lifecycle are confused
- Daemon's two-layer approach (Boot triage + Deacon heartbeat) doesn't work correctly

## Expected Behavior

1. Boot spawns in `gt-deacon-boot` session
2. Boot runs triage, decides if Deacon needs starting
3. If yes, Boot starts Deacon in `gt-deacon` session
4. Both sessions can coexist: Boot (ephemeral triage) and Deacon (persistent patrol)

## Investigation Needed

- Check `boot.spawnTmux()` - is it creating the right session name?
- Check if something is reusing the Deacon session for Boot
- Verify session naming throughout the daemon/boot code


Digest: mol-deacon-patrol

Cycle 299: All healthy, refinery queue 5


Digest: mol-deacon-patrol

Cycle 296: All healthy, refinery active


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 645/1023)


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol #3: Routine - 6 agents healthy


Digest: mol-deacon-patrol

Patrol 4: Routine, witnesses/refineries healthy


gt session restart/status: Complete session management

Add missing session subcommands:

- gt session restart <rig> <polecat> - Restart a session (stop + start)
- gt session status <rig> <polecat> - Show session status details

status should show:
- Running state
- Uptime
- Current activity
- Last output timestamp


Day 4.4: Witness calls nuke after MERGED signal

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

Parent: gt-4a2qt


Digest: mol-deacon-patrol

Patrol 12: 3 rigs healthy


Merge: furiosa-mjxc7zq9

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


Move disk 1: A → C

Move the smallest disk from peg A to peg C.


Day 3.0: Document mail protocol contracts

Document the formal mail protocol for Gas Town agent coordination.

Mail Types:

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

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

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

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

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

Create: docs/mail-protocol.md


Auto-restart patrol agents after N loops

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

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

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

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

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

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


mol-deacon-patrol


Update templates for Propulsion Principle

Overhaul agent prompts to embody the Universal Gas Town Propulsion Principle:

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

Templates to update:
- [ ] deacon.md.tmpl - Check hook first, no decision logic
- [ ] polecat.md.tmpl - Propulsion startup, follow molecule
- [ ] witness.md.tmpl - Sling wisps when spawning agents
- [ ] refinery.md.tmpl - Accept slung epics

Key changes:
1. Remove 'should I run this?' decision points
2. Add 'check your hook' as step 1 of startup
3. Make molecule-following the default mode
4. Simplify - agents don't think, they execute


Merge: gt-8v8

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


Digest: mol-deacon-patrol

P13: stable


Digest: mol-deacon-patrol

Patrol cycle 12: all healthy


Digest: mol-refinery-patrol

Patrol cycle: checked mail (empty), scanned MR queue (0 open), no branches to merge. All MRs already processed.


Digest: mol-deacon-patrol

Patrol 17: 5 new polecats spawned (17 total). All healthy.


Move disk 1: B → C

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


Beads CLI wrapper: shell out to bd

Wrapper for bd (beads CLI) commands.

## Interface

```go
type Beads struct {
    workDir string
}

func NewBeads(workDir string) *Beads

// Query
func (b *Beads) List(opts ListOptions) ([]*Issue, error)
func (b *Beads) Ready() ([]*Issue, error)
func (b *Beads) Show(id string) (*Issue, error)
func (b *Beads) Blocked() ([]*Issue, error)

// Mutations
func (b *Beads) Create(opts CreateOptions) (*Issue, error)
func (b *Beads) Update(id string, opts UpdateOptions) error
func (b *Beads) Close(ids ...string) error

// Sync
func (b *Beads) Sync() error
func (b *Beads) SyncStatus() (*SyncStatus, error)
```

## Data Types

```go
type Issue struct {
    ID          string
    Title       string
    Status      string
    Priority    int
    Type        string
    Description string
    Parent      string
    Children    []string
    DependsOn   []string
    Blocks      []string
}

type ListOptions struct {
    Status   string  // "open", "closed", "all"
    Type     string
    Priority int
}

type CreateOptions struct {
    Title       string
    Type        string
    Priority    int
    Description string
    Parent      string
}
```

## Implementation

Shell out to bd binary, parse JSON output where available.
```go
func (b *Beads) runBd(args ...string) ([]byte, error) {
    cmd := exec.Command("bd", args...)
    cmd.Dir = b.workDir
    return cmd.Output()
}
```

## Error Handling

- bd not installed: Clear error with install instructions
- Not a beads repo: Detect and report
- Sync conflicts: Parse and report


Digest: mol-deacon-patrol

Patrol 113: All healthy


Merge: gt-frs

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 2: No callbacks, 2 convoys in progress, all agents healthy


Formula execution: Spawn convoy from formula

Implement gt formula run <name>:
1. Load and parse formula
2. Create convoy bead (hq-cv-xxx)
3. For each leg, create child bead
4. Sling each leg to separate polecat with leg-specific prompt
5. Track leg completion via bead status
6. When all legs done, spawn synthesis polecat

Use existing gt sling and gt convoy infrastructure.


Digest: mol-deacon-patrol

Patrol 4: 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: B → C

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


Witness arm bonding integration test

Test witness with 3 polecats. Verify: arms bonded per worker, each arm captures/assesses independently, aggregation waits for all arms, witness proceeds after aggregation.


Define constants for magic strings

Several magic strings are hardcoded throughout the codebase:
- "mayor" appears in 20+ places as a path component
- "main" branch name appears in 20+ places
- "beads-sync" branch name in multiple files
- "rigs.json" filename

These should be constants in a central location for maintainability.


Digest: mol-deacon-patrol

Patrol #20: All healthy, 3 convoys active


Merge: furiosa-mjuk2tlb

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


Proto debugging and inspection tools

Proto debugging and inspection tools.

With ephemeral protos (gt-4v1eo), this becomes:
- `bd cook <formula> --dry-run` - preview cooked output without persisting
- `bd cook <formula> --json` - output proto as JSON for inspection
- `bd cook <formula> --graph` - visualize step DAG

No persistent proto beads to inspect - formulas are the source of truth.


Batch wisp squashing in Deacon maintenance

Add wisp squashing to Deacon's maintenance duties:
- Patrol plugin to find orphaned/completed wisps across all rigs
- Squash completed patrol wisps to digests
- Burn abandoned wisps that have no audit value
- Part of the hygiene/cleanup system

Also: Witness polecat shutdown should spawn its own short wisp for the cleanup protocol.


Move disk 4: A → C

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 5


Wisp directory and format

Define and implement the .beads-wisp directory structure.

## Directory Structure

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

## Wisp File Format

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

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

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

## Key Properties

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

## Implementation

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


gt rig info: Show detailed rig information

Add 'gt rig info <rig>' command to show detailed rig status.

Should show:
- Rig path and git URL
- Active polecats with status
- Refinery status
- Witness status
- Recent activity
- Beads summary (open issues count)


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


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 20: All agents healthy - triggering handoff


Merge: gt-84ery

branch: polecat/dementus-mjtlqmya
target: main
source_issue: gt-84ery
rig: gastown


Digest: mol-deacon-patrol

Patrol 7: Interrupted, routine


Swarm learning: Beads database locality gap

## PGT Bug (GGT Design Already Correct)

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

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

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


Digest: mol-deacon-patrol

Patrol 13: routine


CRITICAL: Polecats not pushing before signaling done

Pipeline failure - work being lost:

1. Polecat does work locally
2. Polecat closes bead, goes idle
3. BUT doesn't push commits first
4. Witness sends MERGE_READY to refinery
5. Refinery sees 'no commits ahead of main' - skips
6. Witness nukes polecat
7. Work lost forever

Evidence: Refinery log shows 'MERGE_SKIPPED: furiosa (gt-ft5eb) - No commits ahead of main'

All formula convoy work was lost this way.

Fix: gt done MUST verify push succeeded before signaling completion.


gt-gastown-polecat-eli

gt-gastown-polecat-eli

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


Testing: End-to-end rebase workflow validation

Comprehensive testing of the new rebase-as-work workflow.

## Test Scenarios

### Happy Path
1. Single MR, clean rebase → refinery merges
2. Multiple MRs, no conflicts → priority ordering works

### Conflict Handling
3. MR conflicts → conflict task created
4. Conflict task dispatched → polecat resolves
5. Resolved MR re-enters queue with priority boost
6. Multiple conflict cycles → retry_count tracked

### Priority Scoring
7. Older convoy MRs prioritized over newer
8. P1 epic MRs prioritized over P3
9. High retry_count gets appropriate adjustment

### Edge Cases
10. MR conflicts again after resolution
11. Polecat recycled before merge
12. Convoy completed with pending MRs

## Implementation
- Unit tests for ScoreMR function
- Integration tests for refinery flow
- Scenario tests with actual polecats (manual/semi-auto)


Digest: mol-deacon-patrol

Patrol 16: Green


Digest: mol-deacon-patrol

Patrol 9: All healthy


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol complete: inbox checked (4 msgs, 1 escalation resolved), all agents healthy (2 witnesses, 2 refineries, 3 polecats, 5 crew), cleaned 66 abandoned wisps


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol cycle 13


Digest: mol-deacon-patrol

Patrol cycle 3: routine check, all healthy


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

## Problem

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

## Evidence

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

## Impact

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

## Fix

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


Digest: mol-deacon-patrol

Patrol 17: all healthy


Move disk 1: A → B

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol #17: Stable


Maintain dog pool

Ensure dog pool has available workers for dispatch.

**Step 1: Check dog pool status**
```bash
gt dog status
# Shows idle/working counts
```

**Step 2: Ensure minimum idle dogs**
If idle count is 0 and working count is at capacity, consider spawning:
```bash
# If no idle dogs available
gt dog add <name>
# Names: alpha, bravo, charlie, delta, etc.
```

**Step 3: Retire stale dogs (optional)**
Dogs that have been idle for >24 hours can be removed to save resources:
```bash
gt dog status <name>
# Check last_active timestamp
# If idle > 24h: gt dog remove <name>
```

**Pool sizing guidelines:**
- Minimum: 1 idle dog always available
- Maximum: 4 dogs total (balance resources vs throughput)
- Spawn on demand when pool is empty

**Exit criteria:** Pool has at least 1 idle dog.


Digest: mol-deacon-patrol

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


Move disk 2: C → B

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


Move disk 3: B → C

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


Hardcoded session ID prefixes and paths

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

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

Low priority but improves maintainability.


MQ smart scheduling: dependency-aware queue reordering

Implement intelligent MQ reordering to minimize conflicts.

## Goal
Reorder the MQ so that MRs touching disjoint files merge "in parallel" (no conflicts), while MRs touching overlapping files are sequenced.

## Approach
1. For each MR, get list of changed files (from branch diff)
2. Build conflict graph: edge between MRs if files overlap
3. Find maximal independent sets (MRs that can merge in any order)
4. Schedule independent MRs first, then handle remaining sequentially

## Implementation
- Add file analysis to MR submission (gt done)
- Store changed_files in MR wisp
- Refinery sorts queue by: priority → conflicts → age

## Example
```
Queue: [A, B, C, D]
Files:
  A: auth/login.go
  B: payments/checkout.go
  C: auth/login.go ← conflicts with A!
  D: docs/readme.md

Optimal: [A, B, D, C] - A, B, D can merge without waiting
```

## Parent
gt-lxxh2


Refinery for gastown - processes merge queue.

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 2 complete: all systems healthy, no incidents


gt mq integration status: show integration branch status

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

Display:
- Integration branch name and creation date
- Commits ahead of main
- MRs merged to integration (closed)
- MRs pending (open, targeting integration)
- Comparison: main..integration/<epic>

Output example:
  Integration: integration/gt-auth-epic
  Created: 2025-12-17
  Ahead of main: 5 commits

  Merged MRs (3):
    gt-mr-001  Fix login timeout
    gt-mr-002  Fix session expiry
    gt-mr-003  Update auth config

  Pending MRs (1):
    gt-mr-004  Update auth tests (in_progress)

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

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


Implement aspect merging across formula chain

Implement merging of aspects when formulas extend each other.

## Current State

extends: already works for steps and vars.
Aspects need similar merge behavior.

## Implementation

1. In Resolve(), collect aspects from entire extends chain
2. Merge lists: parent aspects first, then child
3. Support exclude-aspects field to remove inherited aspects
4. Dedupe by aspect name (child wins on conflict)

## Files

- internal/formula/parser.go: Resolve()
- internal/formula/types.go: add ExcludeAspects field

## Tests

1. Child inherits parent aspects
2. Child adds additional aspects
3. Child excludes parent aspect
4. Three-level chain merges correctly


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.


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 17: Green


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

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

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

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

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


Merge: valkyrie-mjw71b7u

branch: polecat/valkyrie-mjw71b7u
target: main
source_issue: valkyrie-mjw71b7u
rig: gastown
agent_bead: gt-gastown-polecat-valkyrie


Move disk 1: C → A

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


Move disk 1: B → C

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


mol-deacon-patrol


Move disk 1: A → B

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


Document Overseer role (human operator)

Document the Overseer role in Gas Town architecture.

## The Overseer

The **Overseer** is the human operator of Gas Town. Not an agent - a person.

## Responsibilities

| Area | Overseer Does | Mayor/Agents Do |
|------|---------------|-----------------|
| Strategy | Define project goals | Execute toward goals |
| Priorities | Set priority order | Work in priority order |
| Escalations | Final decision on stuck work | Escalate to Overseer |
| Resources | Provision machines | Use allocated resources |
| Quality | Review & approve swarm output | Produce output |
| Operations | Run gt commands, monitor dashboards | Do the work |

## Key Interactions

### Overseer → Mayor
- Start/stop Mayor sessions
- Direct Mayor via conversation
- Review Mayor recommendations
- Approve cross-rig decisions

### Mayor → Overseer (Escalations)
- Stuck workers after retries
- Resource decisions (add machines, polecats)
- Ambiguous requirements
- Architecture decisions

## Operating Cadence

Typical Overseer workflow:
1. Morning: Check status, review overnight work
2. During day: Monitor, respond to escalations, adjust priorities
3. End of day: Review progress, plan next batch

## Commands for Overseers

```bash
gt status              # Quick health check
gt doctor              # Detailed diagnostics
gt doctor --fix        # Auto-repair issues
gt inbox               # Messages from agents
gt stop --all          # Emergency halt
```

## Documentation Updates

Add to docs/architecture.md:
- Overseer section under Agent Roles
- Clarify Mayor reports to Overseer
- Add Overseer to workflow diagrams


Merge: dex-mjufugxv

branch: polecat/dex-mjufugxv
target: main
source_issue: dex-mjufugxv
rig: gastown


Day 3.4: Refinery processes MERGE_READY mail

Refinery patrol handles merge requests:
1. Check inbox for MERGE_READY messages
2. For each, verify branch exists
3. Run merge checks (tests, lint)
4. If passing, merge to main
5. Send MERGED signal back

Parent: gt-hwka3


Digest: mol-deacon-patrol

Patrol cycle 3: healthy, 2 acks


Add handoff self-initiation protocol to role templates

Agents need clear protocol for self-initiated handoff:

1. Recognize: 'I should cycle now'
2. Prepare: Summarize current state, what's next
3. Send: gt mail send <self> -s '🤝 HANDOFF: ...' -m '...'
4. Exit: End session cleanly

This replaces external 'you should cycle now' nudging.
The agent owns its lifecycle.

Include examples for each role type.


Swarm learning: Session cleanup missing from swarm workflow

## Problem

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

## What Should Happen

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

## GGT Components

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

## Recommendation

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

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


gt crew next: Return self when only window in cycle group

## Problem
`gt crew next --session 'gt-mayor'` returns exit code 1 when the Mayor is the only window in that cycle group.

## Expected Behavior
When an agent is the only member of its cycle group (or not in any configured cycle group), `gt crew next` should return the current session itself rather than failing.

## Context
- C-b n in Mayor's session triggers this command
- Currently only rig crews have configured cycle groups
- Mayor is not part of any crew cycle group, so it should just return itself

## Fix
If no other windows exist in the cycle group, return the current session name instead of error.


Formula parser: Load and validate formula.toml files

Create internal/formula/parser.go:
- Parse formula.toml using BurntSushi/toml
- Validate required fields (name, legs)
- Resolve leg dependencies
- Return Formula struct

Add internal/formula/types.go for Formula, Leg, Input structs.


Refinery: Conflict-resolution task creation

When rebase fails, create a dispatchable task for conflict resolution.

## Task Format
```
Title: Resolve merge conflicts: <original-issue-title>
Type: task
Priority: inherit from original + boost
Parent: original MR bead
Description:
  - Original MR: gt-xxx
  - Branch: polecat/foo-branch
  - Conflict with: main@<sha>
  - Original issue: gt-yyy
  - Instructions: Resolve conflicts, force-push, close this task
```

## Metadata
- Link to original MR
- Link to original issue
- Conflict SHA (what main was when conflict occurred)
- Retry count (for priority scoring)

## Dispatch
- Task goes to bd ready
- Witness can dispatch to available polecat
- Or: Refinery directly dispatches if polecats available


Digest: mol-deacon-patrol

Patrol 20: routine, handing off


Move disk 2: B → A

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 9: Refineries healthy


Digest: mol-deacon-patrol

Patrol 2: all healthy, no incidents


Move disk 3: C → A

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


Move disk 4: C → B

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


Move disk 3: C → A

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


MQ conflict prediction: file hotspot tracking

Track which files change frequently to predict conflicts before spawn.

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

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

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

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

## Parent
gt-lxxh2


gt-gastown-polecat-testcat6

gt-gastown-polecat-testcat6

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


Digest: mol-deacon-patrol

P14: stable


Digest: mol-deacon-patrol

Patrol 14: All healthy


CLI API Audit: gt and bd command structure review before OSS launch

# CLI API Audit for OSS Launch

Before launching Gas Town + Beads as an SDK, we need to ensure the command-line
API is intelligently designed, consistent, intuitive, and structurally sound.

## Current State Audit

### gt (Gas Town) - 50+ top-level commands

**Agent Lifecycle:**
- `gt mayor`, `gt deacon`, `gt witness`, `gt refinery` - agent management
- `gt polecat` - worker management (subcommands: add, remove, list, etc.)
- `gt crew` - persistent workspace management
- `gt spawn` - create polecat with work

**Work Lifecycle:**
- `gt spawn` - assign work to new polecat
- `gt sling` - hook work + start immediately
- `gt hook` - attach work durably
- `gt handoff` - pass work to fresh session
- `gt done` - signal work complete
- `gt release` - release stuck issues

**Infrastructure:**
- `gt daemon`, `gt up`, `gt down`, `gt start`, `gt stop`, `gt shutdown`
- `gt init`, `gt install`, `gt doctor`

**Communication:**
- `gt mail` (subcommands: send, inbox, read, etc.)
- `gt nudge`, `gt broadcast`

**Molecules:**
- `gt molecule` / `gt mol` (17 subcommands!)

### bd (Beads) - Well-categorized but some sprawl

**Core CRUD:**
- `bd create`, `bd show`, `bd update`, `bd close`, `bd list`

**Molecules:**
- `bd mol` (5 subcommands: catalog, show, bond, run, distill)
- `bd wisp` (3 subcommands: create, gc, list)
- `bd pour` (top-level alias for instantiation)
- `bd cook` (compile formula to proto)

**Hook/Pin:**
- `bd pin` - attach mol to agent hook
- `bd unpin` - remove from hook
- `bd hook` - inspect what's on hook

## Structural Concerns

### 1. gt is sprawling (50+ top-level commands)

Many commands could be subcommands:
```
# Current                      # Could be
gt up/down/start/stop         gt daemon {up|down|start|stop}
gt spawn/sling/hook/handoff   gt work {spawn|sling|hook|handoff}
gt mayor/deacon/witness       gt agent {mayor|deacon|witness|...}
```

### 2. Overlap between gt and bd

| Concept | gt | bd |
|---------|----|----|
| Hook | `gt hook` | `bd pin`, `bd hook` |
| Mail | `gt mail` | `bd mail` (delegates) |
| Molecules | `gt mol` (17 cmds) | `bd mol` (5 cmds) |

Which owns what? User confusion likely.

### 3. Naming inconsistencies

- `gt polecat` (noun) vs `gt spawn` (verb) - both about polecats
- `gt done` vs `gt handoff` - both end work but different
- `bd mol run` vs `bd pour` - both instantiate

### 4. Subcommand depth decisions

**Good patterns:**
- `bd mol {catalog|show|bond|run|distill}` - coherent group
- `gt mail {send|inbox|read|archive}` - coherent group

**Questionable patterns:**
- `bd create --wisp` AND `bd wisp create` - two ways to do same thing
- `gt spawn --molecule X` AND `gt mol instantiate` - overlap

### 5. Flag vs subcommand guidelines needed

When to use flags vs subcommands?
- `--json` as flag ✓ (modifier)
- `--wisp` as flag for create? Or separate `bd wisp create`?
- `--molecule` on spawn? Or separate workflow?

## Recommendations to Evaluate

### A. Consolidate gt top-level commands

Group related commands:
```
gt agent {mayor|deacon|witness|refinery|polecat}
gt work {spawn|sling|hook|handoff|done}
gt infra {daemon|up|down|doctor}
```

### B. Clarify gt vs bd ownership

| Domain | Owner | Other defers |
|--------|-------|--------------|
| Issues | bd | gt uses bd |
| Agents | gt | bd doesn't touch |
| Molecules | bd mol | gt mol wraps for UX |
| Hooks | bd pin/hook | gt hook wraps |
| Mail | gt mail | bd mail delegates |

### C. Apply consistent naming

- All agent commands: nouns (`gt polecat`, `gt mayor`)
- All work commands: verbs (`gt spawn`, `gt sling`, `gt hook`)
- Avoid synonyms: pick one term and stick with it

### D. Flag vs subcommand rule

- Flags: modify behavior of command (`--json`, `--force`, `--wisp`)
- Subcommands: distinct operations (`mol run`, `mol squash`, `mol burn`)
- Exception: very common operations can have top-level aliases

## Tasks

1. [ ] Review gt command groupings - propose consolidation
2. [ ] Review bd command groupings - check for sprawl
3. [ ] Document gt vs bd ownership boundaries
4. [ ] Identify and resolve naming inconsistencies
5. [ ] Document flag vs subcommand decision criteria
6. [ ] Create migration plan for any breaking changes
7. [ ] Update help text to be consistent
8. [ ] Test agent UX: can Claude guess commands correctly?

## Success Criteria

- New user can guess command structure intuitively
- `gt --help` fits on one screen (or is well-categorized)
- No duplicate functionality between gt and bd
- Consistent naming throughout
- Claude agents can discover commands without documentation


Digest: mol-deacon-patrol

Patrol complete: checked inbox (0 msgs), gates (0), polecats (0), health OK, GC'd 6 old wisps


Digest: mol-deacon-patrol

Patrol OK: 0 polecats, 6 core sessions up, town quiet


Digest: mol-deacon-patrol

Cycle 192: Nominal


Layered context onboarding pattern

Pattern from handoff discussion:

## Pattern: Layered Context Onboarding

Town CLAUDE.md (user/org) -> Rig CLAUDE.md (project) -> Role priming

## Ultra-compressed HOP for workers (no reveal)

- Permanent record: All work tracked. Outcomes matter.
- Quality gates: Molecule steps exist for a reason.
- Attribution: Completions build your track record.
- Handoff clean: Leave state any worker can continue.

## Recommendation

Create Town @AGENTS.md for shared worker context that all workers see.
This provides common behavioral guidance without revealing full HOP context.


Move disk 6: A → C

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


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 11: All green


Digest: mol-deacon-patrol

Patrol cycle 37: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol 34: all quiet


Merge: toast-1767074299802

attached_args: Code review this merge request

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


Digest: mol-deacon-patrol

Patrol 8: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 15: Routine


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

Patrol 19: All healthy


Move disk 1: A → B

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


Move disk 2: C → B

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


Heartbeat convention: simple liveness signal for agents

Lightweight liveness signal extracted from Deacon epic (gt-5af).

**Implementation**: Each agent writes a timestamp file on activity:
```bash
echo '{"ts":"'$(date -Iseconds)'"}' > ~/gt/<role>/heartbeat.json
```

**Integration points**:
- SessionStart hook writes heartbeat
- Periodic activity (mail check, work completion) refreshes it
- `gt status` shows staleness (e.g., 'mayor: 5m ago')

**Weight**: ~5 lines per agent
**Value**: Quick debugging - see which agents are active at a glance

No monitoring daemon needed - human checks `gt status` when curious.


Merge: capable-mjtltnm5

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 15: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol 8: Quiet


Digest: mol-deacon-patrol

Patrol 8: All healthy


Digest: mol-deacon-patrol

Patrol 16: All clear


mol-deacon-patrol


Witness Role Definition

You are the Witness - per-rig worker monitor. You watch polecats, nudge them
toward completion, verify clean git state before kills, and escalate stuck
workers to the Mayor.

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

session_pattern: gt-{rig}-witness
work_dir_pattern: {town}/{rig}
needs_pre_sync: false
start_command: exec claude --dangerously-skip-permissions

default_molecule: mol-witness-patrol
capabilities:
  - monitor_workers
  - nudge_stuck
  - pre_kill_verify
  - session_lifecycle
  - escalation

## Core Responsibilities

1. Monitor workers: Track polecat health and progress
2. Nudge: Prompt slow workers toward completion
3. Pre-kill verification: Ensure git state is clean before killing sessions
4. Session lifecycle: Kill sessions, update worker state
5. Self-cycling: Hand off to fresh session when context fills
6. Escalation: Report stuck workers to Mayor

Key principle: You own ALL per-worker cleanup. Mayor is never involved in
routine worker management.

## Propulsion Principle

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

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

## Nudge Protocol

Progress through stages. Track nudge count per worker per issue.
- First Nudge (10+ min idle): Gentle inquiry
- Second Nudge (15 min): Direct question
- Third Nudge (20 min): Final warning
After 3 nudges with no progress then escalate to Mayor

## Pre-Kill Verification

Before killing ANY polecat session:
1. gt polecat git-state <name> - Must be clean
2. Check for uncommitted work
3. Check for unpushed commits
4. Verify issue closed
5. Verify PR submitted (if applicable)

## Commands

- gt polecat list <rig> - See all polecats
- gt polecat git-state <name> - Check git cleanliness
- tmux capture-pane -t gt-<rig>-<name> -p | tail -40 - Session inspection
- gt mail inbox - Check messages
- gt mail send mayor/ -s "Subject" -m "Message" - Escalate


Merge: rictus-1767084016819

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


gt install/bd init: ensure daemon can start

Validate database fingerprint during setup. Auto-migrate legacy databases (pre-0.17.5) that lack repository fingerprint.


gt handoff should accept full session paths like gastown/crew/max

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


Wisp burn after pickup

Implement wisp cleanup after work is picked up.

## When to Burn

After agent has picked up slung work:
- Agent claims the issue (bd update --status=in_progress)
- Or agent explicitly acknowledges the handoff
- Wisp file is deleted

## Implementation Options

Option A: Agent burns manually
```bash
gt hook burn  # Deletes current hook wisp
```

Option B: Auto-burn on claim
- bd update detects theres a hook for this issue
- Burns the wisp automatically

Option C: Burn in prime (after display)
- Once shown to agent, delete the wisp
- Simple but might lose info if agent crashes before reading

## Recommendation

Use Option A (manual burn) for v0.1:
- Explicit is better than implicit
- Agent controls when theyre done with handoff
- Add auto-burn in v0.2

## Command

```bash
gt hook burn
# Deletes .beads-wisp/hook-<agent>.wisp.yaml
# Confirms: "Hook cleared"
```


Rig doctor checks: Refinery health, clones, gitignore

Rig-level doctor checks.

## Checks

### RigIsGitRepo
- Verify .git/ directory exists
- Verify git status works
- Fix: Cannot auto-fix

### GitExcludeConfigured
- Check .git/info/exclude contains Gas Town dirs
- Required entries: polecats/ witness/ refinery/ mayor/
- Fix: Append missing entries

### WitnessExists
- Verify witness/ directory exists
- Verify witness/rig/ is a git clone
- Verify witness/mail/inbox.jsonl exists
- Fix: Create structure, clone repo

### RefineryExists
- Verify refinery/ directory exists
- Verify refinery/rig/ is a git clone
- Verify refinery/mail/inbox.jsonl exists
- Fix: Create structure, clone repo

### MayorCloneExists
- Verify mayor/ directory exists
- Verify mayor/rig/ is a git clone
- Fix: Create structure, clone repo

### PolecatClonesValid
- For each polecat in polecats/:
  - Verify is a git clone
  - Verify on polecat branch
  - Warn if has uncommitted changes
- Fix: Cannot auto-fix (data loss risk)

### BeadsConfigValid (if applicable)
- If .beads/ exists, verify bd commands work
- Check beads sync status
- Warn if out of sync
- Fix: Run bd sync

## Implementation

```go
var RigChecks = []Check{
    &RigIsGitRepoCheck{},
    &GitExcludeConfiguredCheck{},
    &WitnessExistsCheck{},
    &RefineryExistsCheck{},
    &MayorCloneExistsCheck{},
    &PolecatClonesValidCheck{},
    &BeadsConfigValidCheck{},
}
```


Merge: rictus-mjxemkiq

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


LESSONS: Idle Polecat Incident 2026-01-02

# Incident Summary

On 2026-01-02, discovered 9 polecats (5 gastown, 4 beads) sitting idle at Claude prompts with completed work, burning money.

## Root Cause Chain

1. **Polecats completed work, submitted MRs** - correct
2. **Refinery merged work, sent MERGED to Witness** - correct
3. **Witness had 50 unread protocol messages** - BUG
4. **Witness not processing mail = no cleanup** - BUG
5. **Polecats waiting for death that never comes** - SYMPTOM

## Why Witness Wasn't Patrolling

Witness is a Claude agent with template instructions. When it finishes one patrol cycle, it stops. The template doesn't emphasize continuous operation.

Claude agents are stateless between turns - they complete a task and wait for next input. Without continuous prompting, they idle.

## Design Flaw

The current model:
```
Polecat → gt done → WAIT for Witness to kill
Witness → process mail → nuke polecat
```

**Problem**: If Witness doesn't patrol, polecats wait forever.

## Fixes Implemented

1. **gt-lynar**: `gt done --exit` - polecats self-terminate after MR submission
2. **gt-x4ad3**: Update polecat template to use --exit
3. **gt-fo9iz**: Nuke safety check - verify work on main, not just 'pushed'

## Lessons

### L1: Agents Should Self-Terminate When Done
Don't rely on external actors to clean up. If an agent finishes work, it should exit immediately. Waiting = burning money.

### L2: Mail Is Not Reliable Signaling
Claude agents may not process mail continuously. Don't design protocols that require prompt mail processing.

### L3: Safety Checks Must Match Reality
After branch merge+delete, local branch looks 'unpushed' even though work is on main. Safety checks should verify actual state (is work on main?) not proxy state (is branch pushed?).

### L4: Idle State Is A Bug
Gas Town's propulsion principle: agents are pistons that fire. Idle agents violate this. If an agent can be idle, the design is wrong.

### L5: Monitor What Matters
We had convoy status, polecat lists, etc. But no alert for 'polecat at prompt doing nothing'. Add monitoring for actual idle time.

## Future Prevention

1. Polecat template: always use `gt done --exit`
2. Witness template: emphasize continuous patrol (or replace with daemon)
3. Add `gt doctor` check: 'polecats at prompt for >N minutes'
4. Consider: Replace Witness with daemon (more reliable than Claude patrol)


Digest: mol-deacon-patrol

Patrol 62: All agents healthy, routine scan


E2E Test: Add a comment to internal/util/process.go


Move disk 3: C → A

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


Merge: valkyrie-mjw71b7u

branch: polecat/valkyrie-mjw71b7u
target: main
source_issue: valkyrie-mjw71b7u
rig: gastown
agent_bead: gt-gastown-polecat-valkyrie


Merge: gt-h5n.5

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


Mail orchestrator daemon

Background mail orchestrator daemon.

## Command
```
gt mail orchestrate [--interval N] [--once] [--verbose]
```

## Purpose
Background process that:
1. Monitors outbox for pending mail
2. Delivers to recipient inboxes
3. Handles offline recipients (retry later)
4. Cleans delivered messages from outbox

## Why Needed?
Current mail is synchronous. If recipient is offline or mailbox locked, send fails.
Orchestrator enables async delivery with retry.

## Implementation
```go
func (o *Orchestrator) Run(interval time.Duration) error {
    ticker := time.NewTicker(interval)
    for range ticker.C {
        o.processOutbox()
    }
}

func (o *Orchestrator) processOutbox() {
    // List outbox/*.json
    // For each, attempt delivery
    // On success, delete from outbox
    // On failure, increment retry count
}
```

## Outbox Structure
```
<town>/mayor/mail/outbox/
├── msg-abc123.json
└── msg-def456.json
```

## Lower Priority
Current synchronous delivery works. Orchestrator is optimization.

## Acceptance Criteria
- [ ] Background daemon mode
- [ ] Retry failed deliveries
- [ ] --once for single pass
- [ ] Configurable interval


Check Witness and Refinery health

Check Witness and Refinery health for each rig.

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

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

**Signals to assess:**

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

**Tracking unresponsive cycles:**

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

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

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

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

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

Reset unresponsive_cycles to 0 when component responds normally.


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

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


Digest: mol-deacon-patrol

Patrol cycle 9: all healthy


Add gt hook command (wrapper for bd hook)

Add a thin wrapper command `gt hook` that calls `bd hook` to inspect what's pinned to an agent's hook.

## Usage

```bash
gt hook                    # Show what's on current agent's hook
gt hook --agent deacon     # Show Deacon's hook
gt hook --agent gastown/furiosa  # Show polecat's hook
```

## Implementation

Thin wrapper in gt that:
1. Determines current agent identity
2. Calls `bd hook [--agent <name>]`
3. Formats output for gt context

## Why gt wrapper?

- Consistent with gt ecosystem (gt mail, gt status, etc.)
- Can add gt-specific context (session status, etc.)
- Easier discovery for gt users

## Related

- bd hook command (implemented by Dave)
- Chemistry UX design: gastown/mayor/rig/docs/chemistry-design-changes.md


Digest: mol-deacon-patrol

Patrol cycle 1: All healthy - 3 rigs, 6 agents, 1 dog idle, no issues


Merge: slit-1767079899677

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


gt mol command tree: status, catalog, burn, squash

Add gt mol subcommand as agent-side API for molecule operations.

Commands needed:
- gt mol status - What's on my hook? (pinned molecule, current step, progress)
- gt mol catalog - List available protos (delegate to bd mol catalog)
- gt mol burn - Burn current attachment
- gt mol squash - Squash current molecule to digest

This completes the agent-side API and makes the docs (sling-design.md, propulsion-principle.md) match reality.

Blocks: deacon.md.tmpl update (can't use gt mol status until it exists)


Remove markdown molecule heresy from ~/gt/molecules/

The ~/gt/molecules/lifecycle/*.md files are outdated heresy - molecule definitions should only exist as formula.toml files in .beads/formulas/. Remove the markdown specs and update any docs that reference them.


Merge: rictus-1767081110235

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


Move disk 1: A → B

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


Move disk 1: A → B

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


Load context

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

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


Digest: mol-deacon-patrol

Patrol 12: healthy


Merge: gt-3x1.5

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


Digest: mol-deacon-patrol

Patrol 1 complete. All agents healthy. No callbacks, convoys, spawns, gates, orphans. 3 rigs monitored.


Merge: furiosa-1767079892643

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


Digest: mol-deacon-patrol

Patrol 11: All healthy


Move disk 4: B → A

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


Digest: mol-deacon-patrol

Patrol 19: OK


Digest: mol-deacon-patrol

Patrol 5: all clear, proto closure warning noted


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.


Digest: mol-deacon-patrol

Patrol 11: Quiet


bd sync --from-main: fresh sync from main branch

## Summary

Add `--from-main` flag to `bd sync` to pull fresh beads state from main branch.

## Use Case

When starting a patrol or fresh session, agent wants clean beads state:
```bash
bd sync --from-main    # Pull latest from origin/main, ignore local changes
```

## Behavior

1. Fetch origin/main
2. Reset local .beads/ to match origin/main
3. Rebuild SQLite DB from fresh JSONL

Useful for polecats/crew starting work to avoid stale state.


Fix out-of-sync molecule test expectations

Tests in builtin_molecules_test.go have hardcoded expectations that no longer match actual molecules:
- TestBuiltinMolecules: expects 9 molecules, got 11
- TestPolecatWorkMolecule: step refs out of sync
- TestDeaconPatrolMolecule: step count and refs out of sync

This is pre-existing on main, not introduced by any polecat work.


Account management for multi-account Claude Code usage

Enable Gas Town to manage multiple Claude Code accounts (e.g., personal vs work) with easy switching. Core mechanism: CLAUDE_CONFIG_DIR env var per account. See docs/design/account-management.md for full design.


gt uninstall: Clean removal of Gas Town harness

Add 'gt uninstall' command to cleanly remove a Gas Town installation.

Should:
- Remove harness directory structure
- Optionally preserve rigs/data with --keep-data flag
- Warn about running sessions
- Clean up any global config references


Move disk 1: C → A

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


gt-gastown-polecat-testcat

gt-gastown-polecat-testcat

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


Digest: mol-deacon-patrol

Patrol 18: quiet


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

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

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


Merge: dementus-1767074970788

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


Digest: mol-deacon-patrol

Patrol 160: All healthy - handoff after 20 cycles


Digest: mol-deacon-patrol

Patrol: read mayor handoff (gt-mzal boot design), all agents up, furiosa working gt-oiv0, note: gt-4eim orphaned (angharad gone)


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol cycle 27: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol 1: 3 rigs healthy, no incidents


Break up long functions in start.go

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

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


Digest: mol-deacon-patrol

Patrol 9: all clear


Merge: furiosa-mjw349y2

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


Move disk 2: B → A

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


Move disk 1: C → A

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


Agent bead creation uses wrong prefix for non-gastown rigs

When adding a polecat to beads rig, agent bead creation fails:
  Error: issue ID 'gt-polecat-beads-Toast' does not match configured prefix 'bd'

The agent bead ID should use the rig's prefix (bd-) not hardcoded gt-.


Merge: morsov-mjxpeg1a

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


Remove pinned field workaround after beads fix

## Summary

Once bd-phtv is fixed in beads, we can remove the workaround documentation and potentially simplify the pinToHook() implementation.

## Current Workaround

The handoff bead attachment mechanism (AttachMolecule) is used as the primary work assignment mechanism instead of the pinned field. This works correctly but adds complexity.

## Changes After Beads Fix

1. Remove the NOTE comment in internal/beads/beads.go:Pin() explaining the bug
2. Consider simplifying pinToHook() if the pinned field becomes reliable
3. Update gt-o3is to reference the fix

## Blocked By

This issue is blocked by external:beads:pinned-field-fix (bd-phtv).
When that capability is shipped, this issue becomes ready.

## Related

- gt-o3is: Original investigation that found this bug
- bd-phtv: The beads fix (in ~/gt/beads)

BLOCKED: Can't add external:beads:pinned-field-fix dependency due to bd-ucgz (migration invariants bug). Once that's fixed, add: bd dep add gt-hj9e external:beads:pinned-field-fix


Digest: mol-deacon-patrol

Patrol 18: Quiet


Move disk 2: A → C

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


Fetch and conflict check: git operations for MR

Implement git operations for MR processing.

Steps:
1. git fetch origin <mr.branch>
2. git checkout <mr.target> (main or integration/xxx)
3. git merge --no-commit --no-ff <mr.branch> (test merge)
4. Check for conflicts
5. If conflicts: abort and return Failure(conflict, files)
6. If clean: abort (actual merge in next step)

Helper functions:
- FetchBranch(branch string) error
- CheckConflicts(source, target string) ([]string, error)

Reference: docs/merge-queue-design.md#process-merge-steps


Errant redirect file in .beads/ causes chain warnings

A redirect file appeared in gastown/mayor/rig/.beads/ alongside the actual beads.db, causing 'redirect chains not allowed' warnings. The redirect pointed to ../../mayor/rig/.beads which is circular. Had to manually delete the redirect file.


Merge: gt-pnv61

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


Digest: mol-deacon-patrol

P12: stable


Move disk 2: A → C

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


Move disk 1: C → A

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


Move disk 2: A → C

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


README missing prerequisites section (tmux required)

The README.md does not mention that tmux is required.
All agent sessions use tmux, but fresh users have no way to know this.

Add prerequisites section:
- Go 1.23+
- Git
- tmux (required for agent sessions)
- Claude Code CLI (for agents)


Merge: keeper-dogs

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


Digest: mol-deacon-patrol

Patrol 3 complete. All healthy.


Move disk 1: A → B

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


request-shutdown

Send shutdown request to Witness.
Wait for termination.

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

Depends: generate-summary


Build rig/worker tree view component

Bubbletea component showing hierarchical rig list with workers. Each rig expandable to show workers. Each worker shows: status indicator, current molecule title, step progress (X/Y), time since last activity.


Day 1.1: Add type=agent to bead schema

Add agent as a valid bead type in the schema. This is the foundation for agent-as-bead.

Parent: gt-d0jqp

Re-opened: Close reason referenced non-existent commit 927e8374. Type=agent not yet implemented in bd CLI.


Day 5.3: Declare liftoff or document gaps

Final assessment:
- If E2E works: Close gt-oki8p as complete, declare liftoff
- If gaps remain: Document what's missing, file follow-on beads

Either way, the 4.5 day sprint is complete.

Parent: gt-oki8p


Digest: mol-deacon-patrol

Patrol #16: Quick cycle, all quiet.


Add tests for gt crew restart --all

Add integration tests for the crew restart flow:

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

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Update architecture.md: Engineer role and Beads merge queue

Update docs/architecture.md with recent design decisions:

1. Agent table: Change "Refinery" role to "Engineer"
   - Refinery = place/module/directory
   - Engineer = role (agent that works in the Refinery)

2. Merge Queue section: Document Beads-native model
   - MRs are beads issues with --type=merge-request
   - gt mq commands (submit, list, next, process, reorder)
   - Ordering via depends-on links

3. CLI section: Add gt mq commands

4. Key Design Decisions: Add decisions for:
   - #15: Merge Queue in Beads
   - #16: Engineer role (distinct from Refinery place)
   - #17: Session restart protocol for Engineer


Digest: mol-deacon-patrol

Patrol 205: All nominal


Merge: toast-mjxm0mmo

branch: polecat/toast-mjxm0mmo
target: main
source_issue: toast-mjxm0mmo
rig: gastown
agent_bead: gt-gastown-polecat-toast


Digest: mol-deacon-patrol

Patrol 9: all healthy


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 13: Nominal


Move disk 2: B → A

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


Merge: gt-lynar

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


Digest: mol-deacon-patrol

Patrol cycle 1: All 3 rigs healthy (beads, gastown, wyvern). Witnesses/Refineries running. No orphans, no zombies, 1 dog idle. 3 convoys open tracking work.


Merge: capable-mjxogaq4

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


Digest: mol-deacon-patrol

Patrol 4: 9 sessions healthy


Digest: mol-deacon-patrol

Patrol cycle 14: all healthy


Merge: goose-mjwlipjg

branch: polecat/goose-mjwlipjg
target: main
source_issue: goose-mjwlipjg
rig: gastown
agent_bead: gt-gastown-polecat-goose


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 3: All healthy, quiet


Digest: mol-deacon-patrol

Patrol 10: Midpoint, all healthy


Digest: mol-deacon-patrol

Patrol 1: Closed 2 complete convoys (heartbeat fix, refinery fix). All 3 rigs healthy. 12 polecats active. No zombies, no orphans, inbox clear.


Add GitHub issue/PR templates

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


Add gate checking to Deacon patrol loop

Integrate gate checking into Deacon's patrol cycle.

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

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

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

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


Session: gt-gastown-test2 completed gt-f7jxr


Digest: mol-deacon-patrol

Patrol cycle 4: routine check, all nominal


Digest: mol-deacon-patrol

Patrol 20: healthy - handoff cycle


Filter agent session molecule noise from activity feed

Agent session molecules (gt-crew-gastown-joe, gt-crew-gastown-max, etc.) update frequently
and create noisy entries like:

  [10:22:37] → gt-crew-gastown-joe updated · gt-crew-gastown-joe

These are not useful in the activity feed. Options:
1. Filter them out entirely
2. Collapse repeated updates into single entries
3. Show them in a separate "agent status" section

Part of epic gt-u7dxq


Digest: mol-deacon-patrol

Patrol 17: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol cycle 13: All healthy


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 100: All healthy - milestone!


Merge: gt-7hor

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


tmux notifications: display-message too subtle, use send-keys instead

## Problem

`tmux display-message` notifications are not visible enough - they appear briefly in the status bar and are easy to miss.

## Current Behavior

router.go uses:
```go
r.tmux.DisplayMessageDefault(sessionID, notification)
```

## What Works

Sending echo commands directly to the terminal:
```bash
tmux send-keys -t <session> "echo '📬 NEW MAIL from mayor'" Enter
```

## Proposed Fix

Change notification method to send visible output to the terminal, perhaps with a box/banner:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📬 NEW MAIL from mayor
Subject: <subject>
Run: bd mail inbox
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```

## Considerations

- This interrupts the terminal output (acceptable for important mail)
- Could check if Claude is mid-response and queue notification
- Or use tmux popup if available

Additional issues:
1. Enter key not sent properly when chained with send-keys
2. Need to debounce and send Enter separately
3. Correct pattern: send text, sleep briefly, then send Enter


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol cycle 1: inbox clear, 8 in-progress issues, sessions healthy, gc not implemented


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy, handoff threshold reached