Exponential backoff for idle patrol agents

## Problem

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

## Solution: Feed-Driven Backoff

### The Pattern (from PRIMING.md)

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

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

### Data Flow

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

### Backoff Formula

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

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

### Agent State Storage

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

### Implementation Layers

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

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

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

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

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

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

### ZFC Compliance

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

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

### Existing Infrastructure

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

### Exit Strategy

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

All subtasks complete: gt agent state command, patrol formula updates, feed signal verification


Implement gt agent state command for label-based state

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

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

Implemented gt agent state command with get/set/incr/del operations


Update patrol formulas to use await-signal backoff

Layer 3: Update patrol formulas to use new gt mol await-signal with --agent-bead flag.

Update burn-or-loop steps in patrol formulas:
- mol-witness-patrol.formula.toml
- mol-refinery-patrol.formula.toml
- mol-deacon-patrol.formula.toml

The step should:
1. Reset idle counter on work found: gt agent state $AGENT_BEAD --set idle=0
2. Wait with backoff when no work: gt mol await-signal --agent-bead $AGENT_BEAD --backoff-base 30s --backoff-mult 2 --backoff-max 5m
3. Exit after 10 consecutive max-timeout cycles for fresh session

Updated all 3 patrol formulas (witness, refinery, deacon) with exponential backoff pattern. Changes in mayor/rig/.beads/formulas/ - need sync to main.


Verify feed signal sources emit events

Layer 4: Verify that all required sources emit events to the activity feed.

Sources that should emit events:
- gt sling → TypeSling event
- bd create/update/close → BeadMutation event
- gt mail send → TypeMail event

Check internal/events package and verify event emission in each command.

All feed signal sources verified: gt sling emits TypeSling (sling.go:407,799), bd create/update/close emits MutationCreate/Update/Status (server_issues_epics.go:426,667-680,752), gt mail send emits TypeMail (mail.go:407)


Digest: mol-deacon-patrol

Patrol 130: All healthy


Digest: mol-deacon-patrol

Patrol cycle 7: All quiet.


Deacon patrol molecules stored in wrong beads location

outputDeaconPatrolContext in prime.go hardcodes 'gastown/mayor/rig' (line 691) to find patrol molecules. But Deacon is a town-level role, not a rig role. Deacon molecules should be in town root beads (~/gt/.beads/) not rig beads. This also affects gt mol status which uses findLocalBeadsDir() - from ~/gt/deacon/ it won't find the right beads location.


check-refinery

Ensure the refinery is alive and processing merge requests.

Needs: inbox-check


Atomic gt done: all-or-nothing work submission

gt done performs multiple operations that can partially fail.

## Current Flow (non-atomic)
1. Create MR bead ← can fail
2. Send POLECAT_DONE mail ← can fail
3. Update agent bead state ← can fail
4. Report cleanup status ← can fail

If session dies mid-execution, state is inconsistent.

## Fix Options

### Option A: Retry on restart
- Write intent file before starting
- On polecat restart, check for incomplete gt done
- Resume/retry from where it left off

### Option B: Single-write submission
- Create a single 'submission' bead that contains all info
- Witness unpacks it into MR bead + cleanup wisp
- Polecat only needs one successful write

### Option C: Idempotent operations
- Each step checks if already done before doing
- Safe to re-run gt done multiple times

Recommend Option C for simplicity.

Implemented Option C (idempotent operations) for MR bead creation. Added FindMRForBranch to check for existing MR before creating.


Merge: cheedo-1767088553821

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


Digest: mol-deacon-patrol

Patrol 124: All healthy, 2 new polecats


Digest: mol-deacon-patrol

Patrol 17


Digest: mol-deacon-patrol

Patrol cycle 76: All healthy


ZFC #5: Move merge/conflict decisions from Go to Refinery agent

**ZFC Violation:** internal/refinery/manager.go:389-517

Go code currently makes engineering decisions in ProcessMR():
- Detect conflicts via string matching
- Decide to abort merge
- Decide to roll back on test failure
- Decide retry strategy

**Current anti-pattern:**
```go
if strings.Contains(errStr, "CONFLICT") {
    result.Conflict = true
    _ = m.gitRun("merge", "--abort")
    // Go decides what to do
}
```

**ZFC-compliant solution:**
Refinery AGENT runs the merge loop:
- Agent attempts merge
- Agent detects conflict and decides: retry, notify polecat, escalate
- Agent runs tests and decides: proceed, rollback, retry
- Go provides git operations, agent makes decisions

**Relates to:** Day 3.4 (Refinery processes MERGE_READY mail) but needs explicit agent decision-making

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

Implemented ZFC #5: ProcessMR deprecated, agent runs git commands directly and makes all merge/conflict decisions. Role template updated with ZFC compliance section.


Merge: dementus-1767073385126

attached_args: Code review this merge request

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

REJECTED: The swarm fix (gt-qd9p0) is already on main (commit 10e79789). This branch is stale and would revert important changes if merged (hookIssue support from 81b250ee, overseer validation from 32a623f8). No merge needed - work already complete.


Digest: mol-deacon-patrol

Patrol 241 complete: 3 witnesses, 3 refineries healthy; 6 polecats active; 1 dog idle; no orphans; no incidents


Merge: nux-1767084010093

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


Add gt mail claim command for queue message claiming

Add claim subcommand to internal/cmd/mail.go.

SYNTAX:
gt mail claim <queue-name>

BEHAVIOR:
1. List unclaimed messages in queue (claimed_by empty)
2. Pick oldest unclaimed message
3. Set claimed_by to caller identity
4. Set claimed_at to now
5. Print claimed message details

ELIGIBILITY CHECK:
- Load queue config from messaging.json
- Check if caller matches any pattern in workers list
- Reject if not eligible

FILE: internal/cmd/mail.go
ADD: claimCmd as subcommand of mailCmd

TESTS: Add TestMailClaim in mail_test.go or cmd_test.go

Implemented gt mail claim command with eligibility checking and tests


Beads witness sends HEALTH_OK to mayor instead of deacon

The beads/witness is responding to deacon health checks by sending to 'mayor/deacon' or 'mayor/' instead of 'deacon/'.

Current behavior:
gt mail send mayor/deacon -s "HEALTH_OK" ...

Expected behavior:
gt mail send deacon/ -s "HEALTH_OK" ...

The gastown witness was fixed and now correctly sends to deacon/. The beads witness needs the same fix.

Added Health Check Protocol section to witness template with correct deacon/ address


Digest: mol-deacon-patrol

Patrol 16: Routine


Add INSTALLING.md with full setup guide

README Quick Start is too brief. Create docs/INSTALLING.md with:
1. All prerequisites with install commands
2. Step-by-step install for macOS and Linux
3. Verification steps (gt doctor, gt status)
4. Troubleshooting common issues
5. Minimal mode vs full-stack mode setup

Created docs/INSTALLING.md with full setup guide


Refinery Patrol

Merge queue processor patrol loop with verification gates.


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.


Design: Polecat lifecycle and patrol coordination

## Context

This design captures thinking from a deep session about the Gas Town propulsion system - how Deacon, Witness, Refinery, and Polecats coordinate to move work smoothly through the system.

## Core Insight: Session-Per-Step Model

Polecats do NOT complete complex molecules end-to-end. Instead:
- One polecat SESSION per molecule STEP
- Same sandbox (branch/worktree) persists across sessions
- Each step: spawn → work → close bead → recycle session
- Final step: spawn → work → close bead → signal complete → merge → nuke sandbox

## Two Cleanup Stages

| Stage | Trigger | Kills | Survives |
|-------|---------|-------|----------|
| Step cleanup | Step bead closed | Session | Branch, worktree, molecule |
| Molecule cleanup | Merged | Session, branch, worktree | Digest |

## Per-Rig Polecat Channel

Need a mailing list/queue per rig for session-lifecycle requests:
- "Recycle me" (from polecat)
- "Recycle worker X" (from witness/mayor)
- "Spawn for step Y" (from anyone)

First-come-first-served by patrolling agents. Anyone on patrol (Witness, Refinery, Crew, Mayor) can service requests.

## GUPP + Pinned Work = Completion

As long as:
1. Work is pinned to polecat identity (e.g., gastown/furiosa)
2. Sandbox persists (branch + worktree)
3. Someone keeps spawning polecat when it dies

→ The molecule WILL get finished. GUPP ensures wake-and-work.

## Daemon → Deacon Heartbeat

The daemon pings the deacon, keeping the cycle alive. Deacon peeks into rig-wide channels during patrol and can service lifecycle requests.

## Open Design Questions

### Q1: Spoon-Feeding Bin-Packing
Two dimensions of granularity trade-offs:
- How many logical steps per physical molecule step?
- How many molecule steps per polecat session?

Too few steps → context exhaustion, forgetting
Too many steps → overhead, fragmentation

Needs: Analysis of optimal granularity based on step complexity.

### Q2: Mechanical vs Agent-Driven Recycling
Caution from deacon murder spree bug: mechanical detection of "stuck" workers is fragile.

Prefer: Explicit "recycle me" requests serviced by patrol agents.

Question: When is mechanical intervention appropriate?

### Q3: Channel Implementation
Options:
- Mail-based (gt mail to rig/polecats)
- Beads-based (special issue type)
- State file (rig/polecat-queue.json)

Mail seems most consistent with Gas Town patterns.

### Q4: Who Spawns Next Step?
Current: gt sling spawns fresh polecat
Needed: Mechanism for "continue molecule on existing sandbox"

Maybe: gt sling --continue or witness detects pending step.

## Related Issues

- gt-dtw9u: Witness monitoring (enhance survey-workers)
- gt-qpwv4: Completion detection (check ready branches)
- gt-6qyt1: Refinery queue (process MERGE_READY)
- gt-budeb: Auto-nuke (handle MERGED signal)
- gt-5j3ia: Swarm aggregation (batch completion)
- gt-1dbcp: Polecat auto-start (SessionStart hook issue)

## Design Principles (from HOP/MEOW context)

1. **Discovery over tracking** - observe reality each cycle
2. **Mail as coordination primitive** - agents signal via mail
3. **ZFC** - Claude makes judgment calls, no hardcoded thresholds
4. **Redundant monitoring** - overlapping observation is resilience
5. **Wisps are ephemeral** - patrol molecules flow like water

## Next Steps

1. Finalize channel design (mail-based queue)
2. Enhance witness patrol formula with completion detection
3. Enhance refinery patrol with MERGED signaling
4. Implement step-level recycling
5. Design spoon-feeding granularity guidelines


ZFC #4: Replace daemon identity parsing with agent self-registration

**ZFC Violation:** internal/daemon/lifecycle.go:209-309

The daemon has embedded switch statements that parse agent identity strings to determine:
- Session names
- Working directories
- Which agents need pre-sync
- Restart commands

**Current anti-pattern:**
```go
if strings.HasSuffix(identity, "-refinery") {
    needsPreSync = true
    workDir = filepath.Join(...)
}
```

**ZFC-compliant solution:**
Agent types self-register via role beads:
- Role bead contains: working_dir, session_name_pattern, needs_sync, restart_command
- Daemon reads role bead to get lifecycle config
- No identity string parsing in Go

**Depends on:** Day 1.5 (role beads exist)

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

Implemented role-based lifecycle configuration - daemon now uses role beads for session patterns, work directories, pre-sync, and start commands


gt mol attach: Auto-detect agent from cwd when single arg provided

## Current Behavior

gt mol attach requires 2 args:
  gt mol attach <agent-bead-id> <molecule-id>

## Expected Behavior

When called with 1 arg from an agent working directory:
  gt mol attach <molecule-id>

Should auto-detect the agent from cwd (same detection used by gt mail, bd, etc.)
and attach the molecule to that agent hook.

## Example

From ~/gt/gastown/mayor/rig:
  gt mol attach gt-y14l7
  -> detects mayor role
  -> attaches gt-y14l7 to gt-mayor hook

## Implementation

1. Check arg count
2. If 1 arg, call role detection from cwd
3. Resolve agent bead ID from role (gt-mayor, gt-witness-gastown, etc.)
4. Proceed with attachment

This makes the common case (attaching work to yourself) ergonomic.

Implemented: gt mol attach now accepts 1 arg and auto-detects agent bead ID from cwd


Merge: cheedo-mjtmlvge

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


Digest: mol-deacon-patrol

Patrol 20: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol 20: All healthy, cycling session


gt mr: Add alias for merge request operations

Agent guessed `gt mr register <branch>` to submit a branch to the merge queue. The actual command is `gt mq submit`.

**Suggestion**: Add `gt mr` as an alias or subcommand for merge request workflows:
- `gt mr submit` → `gt mq submit`
- `gt mr status` → `gt mq status`
- `gt mr list` → `gt mq list`

**Why**: 'MR' (merge request) is the conceptual noun; 'mq' (merge queue) is the implementation detail. Agents and humans think in terms of 'I have a merge request' not 'I need to interact with the queue'.

**Alternative**: Just document `gt mq` more prominently, but aliases cost little and reduce friction.

Filed by: gastown/polecats/nux (agent UX feedback)

Added 'gt mr' as alias for 'gt mq' commands. MR submitted: gt-mcbna


Digest: mol-deacon-patrol

Patrol cycle 11: all healthy


Digest: mol-deacon-patrol

Patrol cycle 1: all healthy, 3 rigs, 6 agents, no incidents


Digest: mol-deacon-patrol

Patrol 6: All healthy.


Boot needs CLAUDE.md and directory setup

Boot spawns in ~/gt/deacon but:
1. No ~/gt/deacon/dogs/boot/ directory exists
2. Boot reads Deacon's CLAUDE.md (wrong role context)
3. spawnTmux() doesn't send initial triage prompt

Fix:
- Create ~/gt/deacon/dogs/boot/CLAUDE.md with Boot role instructions
- Update EnsureDir() to create directory on spawn
- Consider sending 'gt boot triage' as initial prompt

Boot should know it's a fresh-each-tick watchdog that:
- Observes Deacon state
- Decides: start/wake/nudge/nothing
- Cleans stale inbox
- Exits (never handoffs)

Implemented: Created ~/gt/deacon/dogs/boot/CLAUDE.md with Boot role context, updated spawnTmux() to use bootDir instead of deaconDir, added 'gt boot triage' as initial prompt.


Digest: mol-deacon-patrol

Patrol 106: All healthy


Digest: mol-deacon-patrol

Patrol 2: All healthy, routine


Digest: mol-deacon-patrol

Patrol cycle 16


Digest: mol-deacon-patrol

Patrol #5: All systems nominal


## @group Dynamic Resolution in Mail Router

Wire agent bead queries into mail router for @group addresses.

## Updated Approach (post agent-as-bead + Dogs)

Agent discovery uses bead queries:

```bash
bd list --type=agent --rig=gastown         # All agents in rig
bd list --type=agent --role_type=witness   # All witnesses
bd list --type=agent --role_type=dog       # All dogs
```

## Supported Patterns

| Pattern | Resolution | Scope |
|---------|------------|-------|
| `@rig/gastown` | `--rig=gastown` | All gastown agents |
| `@town` | `--rig=""` (no filter) | All town-level agents |
| `@witnesses` | `--role_type=witness` | All witnesses across rigs |
| `@crew/gastown` | `--role_type=crew --rig=gastown` | Gastown crew |
| `@dogs` | `--role_type=dog` | All Deacon dogs |
| `@overseer` | Special case (not bead query) | Human operator |

## Deliverables

1. Parse @group syntax in router
2. Resolve via `bd list --type=agent` queries
3. Fan-out at send time (N copies, one per recipient)
4. Special handling for `@overseer` (single recipient, uses overseer.json)

## @overseer Special Case

The overseer is the human operator - NOT an agent bead. Resolution:
- Load `mayor/overseer.json`
- Use `overseer/` as recipient address
- No bead query needed

## Dependencies
- Agent bead schema (gt-ikyo1) ✅ closed
- Dog agent beads need role_type=dog (new prereq)

## Acceptance
- @rig/gastown sends to all gastown agents
- @dogs sends to all Deacon dogs
- @overseer sends to human operator
- Each recipient gets own message copy

Beads dependency: bd-jsk7 (Agent beads: structured labels for filtering)

Implemented @group dynamic resolution in mail router with fan-out support


Add agent abstraction layer to support non-Claude agents

Currently Gas Town hardcodes 'claude --dangerously-skip-permissions' throughout the codebase for spawning agents. We should add an abstraction layer to support other AI agents (e.g., Gemini CLI, OpenAI agents, local models).

Locations that spawn Claude:
- internal/cmd/mayor.go:131
- internal/cmd/deacon.go:150
- internal/cmd/witness.go:280
- internal/cmd/crew.go (multiple locations)
- internal/cmd/up.go:190, 229
- internal/session/manager.go:146
- internal/refinery/manager.go:207

Suggested approach:
1. Create an agent package with an interface
2. Add configuration for agent type in town/rig config
3. Replace hardcoded claude commands with agent.Spawn() calls
4. Support agents: claude, gemini, openai, local (ollama, etc.)


Merge: capable-1767074974673

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


attached_args: Refactor runStart into focused helper functions

Break up the 126-line runStart function in start.go.

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

## Current structure (lines 129-255)
runStart does:
1. Crew path detection
2. Workspace verification
3. Mayor session start
4. Deacon session start
5. Optional rig agent startup
6. Configured crew auto-start

## Refactoring plan
Extract these helpers:
```go
func startMayorSession(townRoot string, verbose bool) error
func startDeaconSession(townRoot string) error
func startRigAgents(townRoot string, rigs []string) error
func startConfiguredCrew(townRoot string, config *TownConfig) error
```

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


Digest: mol-deacon-patrol

Patrol 19: quick pass


Merge: rictus-1766959789036

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


queue: shared storage work queues

## queue: Shared Storage Work Queues

Work queue with shared storage (single copy, first-to-claim).

## Pattern Clarification

**Queue is a MAILBOX pattern** (pull-based):
- Workers poll shared queue
- First to claim gets the work
- Worker decides when to check

**This is DIFFERENT from Dog dispatch** (push-based):
- `gt sling <work> deacon/dogs` pushes to hook
- GUPP fires immediately
- Deacon decides when to assign

| Pattern | Mechanism | Initiative |
|---------|-----------|------------|
| `queue:` | Poll mailbox, claim | Worker pulls |
| Dog sling | Hook assignment | Deacon pushes |

## Use Cases for queue:

1. **Batch cleanup tasks** - Multiple agents can help, order does not matter
2. **Overflow work** - When primary handler is busy
3. **Opportunistic tasks** - Agents check between other work

## Deliverables

1. Parse queue:name syntax in router
2. Shared storage model:
   - Single message copy (NOT fan-out)
   - Stored in queue-specific location
   - Multiple agents can see it
3. Queue configuration in ~/gt/config/queues.json
4. Queue inbox command: gt mail queue <name>
5. Claim semantics: `gt mail claim <msg-id>` marks as claimed

## Key Difference from list:
- list: creates N copies (N obligations)
- queue: creates 1 copy (1 obligation, first-to-claim)

## Dependencies
- Config directory (gt-i6jvc) ✅ closed

## Acceptance
- queue:cleanup creates single message
- Multiple agents can view queue
- Claim marks message as taken
- Message invisible to others after claim

Implemented queue:name syntax, shared storage, gt mail queue, and gt mail claim


Digest: mol-deacon-patrol

Patrol 216: All nominal


Merge: furiosa-mjvtknih

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


Add witness plugin hook support

Implement plugin directories for witness patrol.

Structure:
  <rig>/plugins/witness/
  ├── pre-inspection/
  │   └── stale-branch-check/
  │       └── CLAUDE.md
  └── post-action/
      └── mq-health/
          └── CLAUDE.md

run-plugins step scans these directories and bonds mol-plugin-runner for each.


Analysis: Beads database size and hygiene strategy

Audit beads database size and plan medium-term hygiene.

## Questions
1. How many issues total (including tombstones)?
2. Size of issues.jsonl?
3. Growth rate per day/week?
4. What percentage are tombstones?

## Hygiene Topics
- Compaction: squash tombstones periodically
- Archival: move old closed issues to archive file
- Pruning: delete truly stale items (test beads, old MRs)
- Sync efficiency: large JSONL = slow sync

## Action Items
- [ ] Count total issues by status
- [ ] Count tombstones
- [ ] Measure file sizes
- [ ] Propose hygiene schedule


MCP beads tools fail from polecat directories

The beads MCP plugin (plugin:beads:beads) fails to find issues when invoked from polecat directories.

## Observed
- Polecat in /gt/gastown/polecats/dementus
- MCP tool: plugin:beads:beads - show (issue_id: 'gt-th7')
- Error: 'bd command failed: Error: no issue found matching gt-th7'

## Expected
MCP tools should work the same as running bd directly.

## Note
This may be related to gt-tmm (beads sync issue) rather than an MCP-specific bug. The MCP tool uses bd under the hood, and bd can't find the issue because the polecat's beads database is stale.

Fixed in beads-mcp plugin (bd-7t9a): Added _resolve_beads_redirect() function to follow .beads/redirect files during workspace auto-detection. Tests added and passing.


Digest: mol-deacon-patrol

Patrol 76: Routine


Merge: keeper-1767074342207

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

Branch polecat/keeper-1767074342207 does not exist - polecat decommissioned without work to merge


Digest: mol-deacon-patrol

Patrol cycle 9: All 6 agents healthy


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.


Zombie session detection for refinery/witness

A Claude session can crash or hang while still appearing as 'running' in tmux. The current IsRunning checks only verify tmux session exists, not that Claude is actually processing.

## Problem
- Refinery session might be hung (Claude crashed, infinite loop, etc.)
- tmux HasSession returns true, so auto-start doesn't trigger
- MRs pile up with no processing

## Solution Options
1. **Activity-based detection**: Check last output timestamp in tmux
2. **Heartbeat file**: Agents write timestamp to file, check staleness
3. **Prompt detection**: Look for Claude '>' prompt indicating idle/stuck

## Related
- gt-bjft (spawn auto-start) assumes IsRunning means healthy
- Witness patrol assumes running refinery is processing


Digest: mol-deacon-patrol

Patrol 3: All healthy, routine


Merge: gt-h5n.5

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


Merge: nux-mjui76op

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


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


Digest: mol-deacon-patrol

Patrol 18: All healthy.


Digest: mol-deacon-patrol

Patrol cycle 9: All quiet.


Track operational stats as entity/audit beads

Witness and refinery track operational stats in JSON files:
- total_merged, today_merged, total_failed (refinery)
- total_checks, total_nudges, total_escalations (witness)

For HOP entity CV tracking, these could become:
- type=audit beads (daily roll-ups of operational metrics)
- Entity chain entries showing validator activity

This provides observability and contributes to entity reputation tracking (e.g., refinery X has merged 500 PRs with 2% failure rate).

Not critical for launch but aligns with HOP Platform of Platforms vision.


Merge: toast-mjw7062w

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


Merge: furiosa-mjuk2tlb

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


MQ summary in gt status

Add per-rig MQ summary to gt status output.

Current gt status shows:
  gastown
    refinery  ✓ running

Add:
  gastown
    refinery  ✓ running
    MQ: 4 pending, 1 in-flight

Implementation:
- Query beads for merge-request type issues
- Count by status (open=pending, in_progress=in-flight)
- Display in rig section

Implemented MQ summary in gt status output - shows pending, in-flight, and blocked MR counts under Refinery section


Digest: mol-deacon-patrol

Patrol 59: All healthy


Digest: mol-deacon-patrol

Patrol 142 complete: All agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol 12: All healthy


Digest: mol-deacon-patrol

P16: stable


Digest: mol-deacon-patrol

Patrol 115: All healthy


Merge: nux-1767080427756

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


Digest: mol-deacon-patrol

Patrol cycle 18: All healthy


Plugin system: subprocess JSON protocol

Language-agnostic plugin system via subprocess JSON protocol.

## Concept

Allow extending Gas Town with external scripts/programs. Plugins communicate via stdin/stdout JSON.

## Protocol

Request (gt → plugin):
```json
{"method": "check", "params": {"rig": "wyvern", "polecat": "Toast"}}
```

Response (plugin → gt):
```json
{"result": {...}, "error": null}
```

Error response:
```json
{"result": null, "error": {"code": 1, "message": "..."}}
```

## Interface

```go
type Plugin struct {
    Name    string
    Path    string  // executable path
    Methods []string
}

type PluginManager struct {
    plugins map[string]*Plugin
}

func NewPluginManager() *PluginManager
func (pm *PluginManager) Register(plugin *Plugin) error
func (pm *PluginManager) Call(plugin, method string, params any) (any, error)
func (pm *PluginManager) Discover(dir string) error  // auto-discover plugins
```

## Plugin Discovery

Look in:
1. `<town>/plugins/`
2. `~/.config/gastown/plugins/`
3. System path with `gt-plugin-*` prefix

## Built-in Hooks

Plugins can register for events:
- `polecat.started` - Polecat session started
- `polecat.done` - Polecat signals done
- `merge.requested` - MR submitted
- `merge.completed` - MR merged

## Use Cases

- Custom health checks
- Integration with external systems (Slack, etc.)
- Custom merge policies
- Metrics collection

## Future

Consider MCP integration for richer plugin capabilities.


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.


Merge: dag-mjtm8k85

branch: polecat/dag-mjtm8k85
target: main
source_issue: dag-mjtm8k85
rig: gastown

Branch deleted, no audit trail - unverifiable


Digest: mol-deacon-patrol

Cycle 191: Nominal


Digest: mol-deacon-patrol

Patrol 7: All healthy.


Remove stubbed ProcessMRFromQueue and mrqueue package

internal/refinery/engineer.go has stubbed ProcessMRFromQueue() that returns hardcoded failure.
internal/mrqueue/ package exists but isn't used.

This was aspirational 'beads-based MR automation' but:
1. Refinery agent just runs git commands per role prompt
2. manager.ProcessMR() is already fully implemented if we need Go automation
3. The stub creates confusion about what's working

Either:
1. Remove engineer.ProcessMRFromQueue and mrqueue package entirely
2. Or finish implementing it if there's a real use case

Leaning toward removal - YAGNI.

Removed ProcessMRFromQueue, mrqueue package, and related queue handlers from engineer.go. Manager.ProcessMR is the working implementation.


Digest: mol-deacon-patrol

Patrol 122: All agents healthy, no incidents


Merge: valkyrie-1767106008400

branch: polecat/valkyrie-1767106008400
target: main
source_issue: valkyrie-1767106008400
rig: gastown


Digest: mol-deacon-patrol

Patrol cycle 2: All rigs healthy. No callbacks. Town idle.


Digest: mol-deacon-patrol

Patrol cycle 61: All agents healthy, no orphans, archived 1 ACK


Day 3.3: Witness sends MERGE_READY to refinery

When polecat completes work:
1. Witness detects completion (hook_bead closed, state=stopped)
2. Witness sends mail to refinery: MERGE_READY
3. Mail includes branch name and work bead ID

Parent: gt-hwka3


Activity feed improvements

Make the activity feed (gt feed) a first-class TUI experience using charmbracelet.

## Vision

A real-time dashboard showing all Gas Town activity with:
- Agent tree organized by role (mayor, witnesses, crew, polecats)
- Live event stream
- Vim-style navigation
- Filtering and search

## Architecture

Two-tier event system:
- ~/gt/.events.jsonl (raw, audit) - all events from gt, bd, agents
- Feed daemon curates → ~/gt/.feed.jsonl (user-facing) - filtered, deduped

TUI reads from curated feed for smooth UX.

## Layout (Dashboard + Stream)
```
┌─────────────────────────────────────────────────────────────┐
│ GT Feed                                    Filter: all      │
├─────────────────────────────────────────────────────────────┤
│ gastown/                                                    │
│   🎩 mayor      [10:30] Dispatched gt-xyz → Toast           │
│   👁 witness    [10:28] Nudged polecat-3 (idle 5m)          │
│   🏭 refinery   [10:25] Merged PR #123                      │
│   👷 crew/                                                   │
│      joe        [10:22] ✓ Completed gt-95j13                │
│      max        [10:18] → Working on gt-s6r44               │
│   😺 polecats/                                               │
│      Toast      [10:30] Received gt-xyz, starting...        │
├─────────────────────────────────────────────────────────────┤
│ [10:30] 😺 Toast: Received molecule gt-xyz                  │
│ [10:28] 👁 witness: Nudged polecat-3 after 5m idle          │
│ [10:25] 🏭 refinery: Merged PR #123                         │
├─────────────────────────────────────────────────────────────┤
│ j/k: scroll  /: search  f: filter  q: quit  ?: help         │
└─────────────────────────────────────────────────────────────┘
```

## Key Features
1. Real-time updates - events stream in live
2. Agent tree - all agents grouped by role with status
3. Vim-style navigation - j/k, gg/G, /search
4. Filtering - by rig, role, event type, time
5. Collapsible sections
6. Details on select

## Tech Stack
- bubbletea - TUI framework
- bubbles - viewport, list components
- lipgloss - styling (already have)

## Success Criteria
- Feed is beautiful and scannable at a glance
- Agent activity visible in real-time
- Works in any terminal, degrades gracefully for pipes


Digest: mol-deacon-patrol

Patrol 4: routine, all healthy


Digest: mol-deacon-patrol

Patrol 2: 1 msg (Nux done), health OK


Merge: slit-mjvtz18y

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

Already merged to main at 2bcfa763 - stale MR bead


Digest: mol-deacon-patrol

Patrol 247 complete: no incidents


Digest: mol-deacon-patrol

Patrol 3: Routine


Digest: mol-deacon-patrol

Patrol 6: All clear


Formula Molecules: Guzzoline production for Gas Town

## Vision

Gas Town executes work. But it also needs to PRODUCE work - structured, high-quality guzzoline on demand. **Formula Molecules** are recipes that spawn structured convoys.

## Core Insight

A formula is a molecule template that:
1. Takes input (a PR, a design problem, a codebase)
2. Spawns multiple polecats with specific focuses
3. Each leg produces structured output
4. Synthesis step combines into unified deliverable

Gas Town becomes both consumer AND producer of guzzoline.

## Example Formulas

### Design Convoy Formula
Input: Feature request or problem statement
Legs (parallel):
- API design polecat
- Data model polecat
- UX/ergonomics polecat
- Scalability polecat
- Security polecat
Synthesis: Unified design doc with tradeoffs

### Code Review Convoy Formula
Input: PR or file set
Legs (parallel):
- Correctness: Does it work?
- Performance: Any bottlenecks?
- Security: Vulnerabilities?
- Elegance: Clean design?
- Resilience: Error handling?
- Style: Convention compliance?
- Smells: Anti-patterns?
- Legacy: Respects existing patterns?
Synthesis: Categorized review with priority issues

### Other Formula Ideas
- Test Coverage Convoy: Unit, integration, edge cases, error paths
- Documentation Convoy: API docs, user guide, examples, changelog
- Migration Convoy: Database, API, config, rollback plan
- Incident Response: Root cause, timeline, fix, prevention

## Mol Mall

Library/marketplace of formulas:
```bash
gt formula list              # Available formulas
gt formula show code-review  # Formula details
gt formula run code-review --pr=123  # Execute formula → convoy
gt formula create my-review  # Create custom formula
```

## Technical Design

### Formula Structure (in beads)
```yaml
id: formula-code-review
type: formula
name: Code Review
inputs:
  - name: target
    type: pr | files | branch
legs:
  - name: correctness
    focus: "Verify logical correctness and edge cases"
    output: findings.md
  - name: security
    focus: "Identify security vulnerabilities"
    output: findings.md
  # ...
synthesis:
  inputs: all leg outputs
  output: review-summary.md
```

### Execution Model
1. `gt formula run` creates convoy with formula reference
2. Spawns polecats for each leg (parallel where possible)
3. Each polecat gets leg-specific prompt + shared context
4. Outputs collected as bead attachments or slots
5. Synthesis polecat reads all outputs, produces final deliverable
6. Convoy lands with unified result

### Dependencies
- Leg outputs feed synthesis (internal convoy deps)
- Formula can specify leg ordering if needed
- Parallel by default, sequential where required

## Open Questions

1. Where do formulas live? Town-level beads? Separate formula registry?
2. How to version/share formulas across towns?
3. Leg output format standardization?
4. Human checkpoints between legs or only at end?
5. Partial formula runs (skip some legs)?
6. Formula composition (formula that includes other formulas)?

## Why This Matters

Gas Town currently waits for humans to create work. With formulas:
- Mayor can invoke structured reviews on any PR
- Design work follows consistent methodology
- Quality processes are repeatable and scalable
- Work generation becomes as automated as work execution

**Guzzoline factory, not just guzzoline consumer.**


Code Review Convoy formula (first formula implementation)

## First Formula: Code Review Convoy

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

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

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

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

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

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

Implementation already complete: code-review.formula.toml with 7 legs (correctness, performance, security, elegance, resilience, style, smells) + synthesis. Execution via gt formula run creates convoy, leg beads, and slings to polecats. Synthesis pipeline in gt synthesis start/status/close.


Design Convoy formula

## Design Convoy Formula

Structured design exploration for features/architecture.

### Input
- Problem statement or feature request

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

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

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

Created design convoy formula with 6 legs and synthesis step


Mol Mall: Formula library and sharing

## Mol Mall

Library/marketplace for formula molecules.

### Features
- Browse available formulas
- Formula metadata (author, version, inputs, outputs)
- Custom formula creation
- Formula versioning
- Cross-town formula sharing (future)

### Commands
```bash
gt formula list              # List available formulas
gt formula show <name>       # Formula details
gt formula create <name>     # Create new formula
gt formula edit <name>       # Modify formula
gt formula export <name>     # Export for sharing
gt formula import <file>     # Import shared formula
```

### Storage
- Formulas as beads in town-level .beads/
- type: formula
- Structured schema for legs, synthesis, inputs

### Future: Public Mol Mall
- Central registry of community formulas
- gt formula search 'code review'
- gt formula install community/security-audit


Digest: mol-deacon-patrol

Patrol 209: All nominal


Add GH deployment artifacts (homebrew, npm)

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

Reference Beads implementation for patterns.

Added .goreleaser.yml, npm-package/, and release.yml workflow


Digest: mol-deacon-patrol

Patrol 7: quick pass


Digest: mol-deacon-patrol

Patrol 64: Routine


Digest: mol-deacon-patrol

Patrol cycle 72: All healthy


Merge: capable-mjtltnm5

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


gt mq list shows empty when MRs exist

The gt mq list command returns empty results even when merge requests exist in the queue.

Fixed - mq_list.go now uses r.BeadsPath() instead of r.Path to read from the git-synced beads location


Merge: rictus-mjw3nj1a

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


Merge: furiosa-1766987668522

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


Digest: mol-deacon-patrol

Patrol complete: all witnesses/refineries healthy, burned 1 stale wisp, no callbacks, convoys in progress


Digest: mol-deacon-patrol

Patrol cycle 3: All healthy. 3 rigs responding.


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 cycle 28: All healthy, no incidents


Enhance gt status with role hierarchy view

Show identity and role hierarchy in gt status:

## Current Output
Flat list of agents by rig, no clear role hierarchy.

## Desired Output
Tree structure showing:
- Town-level roles (Mayor, Deacon)
- Per-rig role slots with their role_bead references
- Each agent slot with pinned work

Example:
```
Town: gt
├── 🎩 Mayor (gt-mayor-role)
│   └── gt-mayor [running] → gt-u7dxq
├── 🔔 Deacon
│   └── gt-deacon [running]
└── Rigs
    └── gastown/
        ├── 👁 Witness (gt-witness-role)
        │   └── gt-witness-gastown [running]
        ├── 🏭 Refinery (gt-refinery-role)
        │   └── gt-refinery-gastown [running] → (work)
        ├── 👷 Crew
        │   ├── jack [running] → gt-xxxx
        │   └── joe [running]
        └── 😺 Polecats
            └── (none)
```

## Key Changes
1. Use tree-style indentation (├── └──)
2. Group agents by role type
3. Show role_bead for each role category
4. Use emojis for quick visual scanning


Update docs with molecule navigation workflow

Update architecture and workflow docs with new molecule navigation.

## Docs to update

### docs/molecules.md
- Add 'Navigating Molecules' section
- Document bd mol current usage
- Document bd close --continue workflow
- Show the propulsion pattern

### docs/propulsion-principle.md
- Add molecule navigation as key enabler
- Show before/after workflow comparison

### docs/polecat-wisp-architecture.md
- Update step execution section
- Show bd close --continue in examples

## New section content

### Molecule Navigation

Finding your place:
  bd mol current              # Where am I?
  bd mol current gt-abc       # Status of specific molecule

Seamless transitions:
  bd close gt-abc.3 --continue   # Close and advance
  bd close gt-abc.3 --no-auto    # Close but don't auto-claim next

The old way (3 commands):
  bd close gt-abc.3
  bd ready --parent=gt-abc
  bd update gt-abc.4 --status=in_progress

The new way (1 command):
  bd close gt-abc.3 --continue

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

Created three docs: molecules.md (navigation section), propulsion-principle.md (molecule navigation enabler), polecat-wisp-architecture.md (step execution with --continue)


Clean up ~/gt root directory cruft

The town root has accumulated various directories and files that need review:

**To evaluate:**
- daemon/ - old daemon code? move or delete?
- deacon/ - WIP deacon work? consolidate with gastown?
- mayor/ - old mayor structure?
- AGENTS.md - is this still used?
- gt binary at root - should be gitignored

**Already correct:**
- .beads/, .claude/, .gastown/, .runtime/ - runtime dirs
- beads/, gastown/ - rig directories
- docs/hop/ - strategic docs
- CLAUDE.md - mayor context

Clean up, consolidate, update .gitignore as needed.


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol complete: No callbacks, no gates, witness/refinery healthy, no orphans, clean cycle


Digest: mol-deacon-patrol

Patrol cycle 1: All 3 rigs healthy (beads, gastown, wyvern), no orphans, no cleanup needed, inbox clean


Refinery Patrol

Merge queue processor patrol loop with verification gates.

Duplicate patrol molecule beads - keeping gt-t5i07, gt-8ynws, gt-kt9qq


Digest: mol-deacon-patrol

Patrol cycle 3: All 3 rigs healthy. 0 messages. No incidents.


Fix SQL injection in convoy panel getTrackedIssueStatus

convoy.go:151-152 interpolates convoyID directly into SQL query without sanitization. Add input validation for hq-* pattern.


Daemon: configurable heartbeat interval

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

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


Digest: mol-deacon-patrol

Patrol 13: quick pass


Merge: imperator-mjwjc4ov

branch: polecat/imperator-mjwjc4ov
target: main
source_issue: imperator-mjwjc4ov
rig: gastown
agent_bead: gt-gastown-polecat-imperator

Branch reset to main - work superseded by existing code


Digest: mol-deacon-patrol

Patrol 3: All healthy, MQ 1 pending


Digest: mol-deacon-patrol

Patrol 16


Digest: mol-deacon-patrol

Cycle 189: Nominal


Merge: rictus-mjw3nj1a

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


Digest: mol-deacon-patrol

Patrol 156 complete


Merge: slit-mjwohabk

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


Merge: rictus-1767082306179

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


Digest: mol-deacon-patrol

Patrol cycle 24: quick check, all healthy


Day 1.2: Add agent-specific fields to schema

Add fields for agent beads:
- hook_bead: reference to current work (0..1 cardinality)
- role_bead: reference to role definition (1)
- state: agent-reported state (idle|running|stuck|stopped)

Parent: gt-d0jqp

Re-opened: Close reason referenced non-existent commit b5c69507. Agent fields not yet implemented in bd CLI.


Patrol exponential backoff for cost savings

Agent-side backoff state tracking in patrol molecules.

## State

Each patrol agent tracks:
- current_interval: current sleep duration (starts at base)
- idle_cycles: count of cycles with no work found

## Backoff Logic

```
on await-signal timeout (no nudge):
    idle_cycles++
    current_interval = min(base * 2^idle_cycles, max_interval)

on nudge received:
    idle_cycles = 0
    current_interval = base
    wake immediately

on work found:
    idle_cycles = 0
    current_interval = base
```

## Where State Lives

Options:
A. Agent bead fields (persistent across sessions)
B. In-memory during patrol (resets on restart)
C. Wisp fields (ephemeral but survives handoff)

Option B is simplest - backoff resets when agent restarts anyway.

## Depends On

- gt-l6ro3.3: await-signal step type


Digest: mol-deacon-patrol

Patrol 14: Quiet


Digest: mol-deacon-patrol

Patrol 243 complete: no incidents


Digest: mol-deacon-patrol

Patrol 210: Deep health check - 3 witnesses, 3 refineries, 10 polecats all healthy


Synthesis: Combine leg outputs into final deliverable

Implement synthesis step:
1. Collect all leg outputs (findings.md files)
2. Spawn synthesis polecat with combined context
3. Synthesis prompt: dedupe, prioritize, format
4. Output: review-summary.md attached to convoy bead
5. Close convoy when synthesis complete

Consider: bd slot or bd attach for outputs.


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.


Digest: mol-deacon-patrol

Patrol 12 complete


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

Witness nukes on MERGED signal without verifying merge actually succeeded.

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

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

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

Only nuke if verification passes.

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

Implemented commit verification in HandleMerged


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

Duplicate - filed as bd-kvus in beads repo


Digest: mol-deacon-patrol

Patrol 8: All healthy.


Merge: valkyrie-1767074338488

attached_args: Code review

branch: polecat/valkyrie-1767074338488
target: main
source_issue: valkyrie-1767074338488
rig: gastown

CODE REVIEW (furiosa): REJECT

Issue: Commit modifies CLAUDE.md which is gitignored on main.

Findings:
1. CLAUDE.md is in .gitignore (clone-specific file)
2. CLAUDE.md is NOT tracked on main branch
3. Polecat manager has installCLAUDETemplate() to generate this file locally per worktree
4. The commit adds a file that should not be committed

Recommendation: Do not merge. CLAUDE.md should be locally generated, not committed.

This merge request has no valid changes to merge.

REJECTED: CLAUDE.md is gitignored and clone-specific. The polecat manager generates this file locally via installCLAUDETemplate(). No valid changes to merge.


Digest: mol-refinery-patrol

Patrol: No new branches to merge (all already cherry-picked). Archived 100+ stale MERGE_READY messages. Inbox clean.


gt rig status <rig> - show status for specific rig

Show detailed status for a specific rig including all workers (witness, refinery, polecats, crew).


Digest: mol-deacon-patrol

Patrol 140: All healthy


Merge: gt-bca67

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


Feed-Based Wake Model for Patrol Agents

## The Paradigm Shift

> **Backoff is not about polling less. It is about waiting for signals with a timeout.**

This epic captures the shift from time-driven to event-driven patrol wake.

## Key Insight (Recovered from 2025-12-29 session crash)

The Beads activity feed (bd activity --follow) is the universal data plane for
wake signals. Every meaningful action creates a beads mutation; agents subscribe to
the feed and wake within ~500ms. The timeout is just a safety net.

**OLD**: Time-driven. Wake because time passed. Poll less when idle.
**NEW**: Event-driven. Wake because signal arrived. Timeout is safety net.

## Architecture

ANY MUTATION:
  bd create/update/close -> issues.jsonl mutation
                        -> bd activity --follow sees it (~500ms)
                        -> All subscribed agents wake immediately

PATROL AGENT:
  Runs bd activity --follow as background source
  Any output line = wake signal
  Timeout expiry = safety net (not primary wake)

## Wake Sources (Priority Order)

| Source | Latency | Purpose |
|--------|---------|---------|
| Feed | ~500ms | Primary - any beads mutation |
| Nudge | Instant | Explicit wake (startup hooks) |
| Timeout | Backoff | Safety net for missed signals |
| Daemon | 5-60min | GUPP backstop, session recovery |

## Key Design Decisions

1. No wake_on conditions - signals carry no semantic meaning. Just wake up.
   Agent discovers reality by checking mail, beads, hook, git state.

2. Read-only commands do not wake - gt status, bd show create no mutations.

3. Daemon is recovery-focused - catches edge cases (GUPP violations, dead sessions).

4. Keepalive file deprecated - the feed replaces the keepalive mechanism.

## Reference

- ~/gt/docs/patrol-system-design.md (Sleeping Agents section)
- ~/gt/docs/PRIMING.md (Feed Is the Signal insight)

## Related

- gt-l6ro3: Patrol Exponential Backoff System (backoff timing, complements this)

Feed-based wake model complete: patrol agents subscribe to bd activity --follow, daemon uses fixed 10-min recovery heartbeat, keepalive file infrastructure removed


Patrol agents subscribe to bd activity --follow

Each patrol agent (Deacon, Witness, Refinery) should run bd activity --follow as a background process. Any output line is a wake signal. This is the primary wake mechanism.

Implementation:
1. Add feed subscription to await-signal step logic
2. Agent starts bd activity --follow on entering await-signal
3. Any line of output breaks the wait immediately
4. Timeout still applies as safety net

See patrol-system-design.md for full specification.

Implemented await-signal command that subscribes to bd activity --follow


Remove keepalive file infrastructure

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

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

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

Removed keepalive infrastructure: TouchTownActivity/ReadTownActivity deleted from keepalive.go, activity-based backoff removed from daemon.go (now uses fixed 10-min recovery interval), PersistentPreRun hook removed from root.go


Startup hooks nudge Deacon

When a new Claude session starts (via startup hook), it should nudge Deacon so Deacon knows a new agent has appeared. This is one of Deacons extra wake sources for GUPP backstop.

Implementation: Add gt nudge deacon session-started to the startup hook chain.

Implemented: Added gt nudge deacon session-started to startup hooks, with special deacon target handling in nudge.go


Daemon heartbeat becomes recovery-focused

Update daemon heartbeat to be recovery-focused, not wake-focused.

Current: Daemon pokes agents every 5-60min as primary wake.
New: Daemon only checks for:
- Dead sessions that need restart
- Agents with work-on-hook not progressing (GUPP violation)
- Orphaned work

Feed handles normal wake; daemon is the safety net for edge cases.

Implemented recovery-focused daemon heartbeat: removed poke functions, added GUPP violation and orphaned work checks


Documentation: Feed-based wake model

Document the feed-based wake model in patrol-system-design.md and PRIMING.md.

DONE (2025-12-29):
- Updated patrol-system-design.md with full feed-based wake specification
- Added Feed Is the Signal and Discover Dont Be Told insights to PRIMING.md
- Committed as 39e46148


Digest: mol-deacon-patrol

Patrol 3: Routine. All healthy.


Merge: rictus-mjtlq9xg

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


Add 'spawn' as alias for 'start' subcommand across all roles

Agents are guessing 'spawn' when trying to start roles (witness, refinery, etc). Need to add 'spawn' as an alias for 'start' for consistency.

Affected commands:
- gt witness start → also gt witness spawn
- gt refinery start → also gt refinery spawn
- gt polecat start → also gt polecat spawn
- gt crew start → also gt crew spawn

Implementation: Add Aliases field to cobra commands.

Added spawn alias to witness, refinery, deacon, and crew start commands


Digest: mol-deacon-patrol

Patrol 43: All healthy, 6 agents pinged


Use Beads issue status as spawn source of truth

Currently witness tracks spawned issues in .gastown/witness.json to prevent re-spawning:

{"spawned_issues": ["gt-abc1", "gt-def2", ...]}

This is redundant with Beads issue status (in_progress). The witness could query:
  bd list --status=in_progress

The local list serves as a performance cache to avoid querying beads every cycle. Consider:
1. Use Beads as source of truth
2. Keep local cache with TTL
3. Sync cache on witness start

This simplifies state management and ensures consistency.


Session: gt-gastown-test2 completed gt-f7jxr


Merge: furiosa-mjtj9d4g

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


Digest: mol-deacon-patrol

Patrol 20: final cycle


Merge: rictus-1767079818240

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


Digest: mol-deacon-patrol

Patrol 12: routine


Digest: mol-deacon-patrol

Patrol cycle 1: All rigs healthy, no incidents


Mol Mall: Formula Package Registry

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

## Concept

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

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

## Resolution Hierarchy

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

## Package Manifest

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

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

## Distribution Scenarios

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

## Open Questions

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

## Related

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


Merge: rictus-mjw3nj1a

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


Digest: mol-deacon-patrol

Patrol 150: All healthy


Digest: mol-deacon-patrol

Patrol cycle 1: 17 sessions healthy, 3 agents responded to health check, all core systems normal


Digest: mol-deacon-patrol

Patrol #11: Quick cycle, all quiet.


Digest: mol-deacon-patrol

Patrol 96: All healthy


Digest: mol-deacon-patrol

Patrol 2: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol cycle 9: All healthy


Merge: rictus-mjvtzdm2

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


Digest: mol-deacon-patrol

Patrol cycle 52: All healthy


Digest: mol-deacon-patrol

Patrol #7: nominal


Digest: mol-deacon-patrol

Patrol cycle 2: Witnessed escalation re: 14 polecats with unpushed work. All agents healthy. No pending work.


Agent bead IDs should use rig prefix, not hardcoded gt-

When spawning beads polecats, agent bead creation fails:

```
Error: invalid agent ID: agent ID must start with 'gt-' (got "bd-beads-polecat-pearl")
```

The validation is hardcoded to expect 'gt-' but beads rig uses 'bd-' prefix.

Fix: Agent bead ID validation should accept the rig's configured prefix, not hardcode 'gt-'.

Fixed agent bead ID validation in beads CLI to accept any prefix, and updated gastown's witness/handlers.go and cmd/crew_lifecycle.go to use rig prefix


Digest: mol-deacon-patrol

Patrol cycle 2: All 3 rigs healthy. 0 messages. No incidents.


gt nudge should accept role shortcuts like 'mayor' not just 'gt-mayor'

Implemented role shortcuts (mayor, witness, refinery) that expand to session names


BUG: gt polecat nuke also tries to nuke rig/rig (e.g. gastown/gastown)

When running 'gt polecat nuke <name> <rig> --force', it successfully nukes the polecat but then also attempts to nuke '<rig>/<rig>' (e.g. gastown/gastown).

Example output:
  ⚠ Nuking gastown/angharad (--force)...
    ✓ killed session
    ...
  ⚠ Nuking gastown/gastown (--force)...
    ○ worktree already gone

This is harmless but indicates a bug in argument parsing or loop logic.

Fixed: Added validation requiring rig/polecat format for nuke and remove commands


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


Merge: furiosa-dogs

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


Digest: mol-deacon-patrol

Patrol cycle 7


Show active workers in gt convoy status output

Enhance convoy status to show which workers are currently assigned to tracked issues.

CURRENT OUTPUT:
  Tracked Issues:
    ○ gt-xyz: Fix bug [task]
    ○ gt-abc: Add feature [task]

DESIRED OUTPUT:
  Tracked Issues:
    ○ gt-xyz: Fix bug [task]
    ○ gt-abc: Add feature [task]  @gastown/nux (12m)

  Active Workers (the swarm):
    gastown/nux     gt-abc     running 12m
    beads/amber     bd-def     running 5m

IMPLEMENTATION:
1. Query hooked molecules to find workers with tracked issues
2. Match issue IDs to tracked issues
3. Show worker assignments inline and/or in separate section

File: internal/cmd/convoy.go (runConvoyStatus)

Added worker display to convoy status with inline @worker (age) format


Test Polecat Arm

Test child for bonding pattern


Test refile v2

Testing improved refile

(Refiled from bd-eysh)


Digest: mol-deacon-patrol

Patrol 139: All healthy


witness Handoff


Digest: mol-deacon-patrol

Patrol cycle 70: All healthy


Digest: mol-deacon-patrol

Patrol 148: All healthy


Fix N+1 query problem in convoy status fetching

getTrackedIssueStatus spawns a new bd show for each tracked issue. With 10 convoys x 5 issues = 50+ subprocesses every 10s. Consider batching or caching.


Digest: mol-deacon-patrol

Patrol cycle 5: Routine.


Digest: mol-deacon-patrol

Cycle 183: All agents healthy, no incidents


Merge: gt-znma3

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


Merge: nux-1767087680976

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


Digest: mol-deacon-patrol

Cycle 7


Digest: mol-deacon-patrol

Patrol 4: All healthy.


Check own context limit

Check own context limit.

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

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

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

This enables the Deacon to burn and respawn cleanly.


Evaluate pending async gates

Evaluate pending async gates.

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

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

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

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

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

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

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


Execute registered plugins

Execute registered plugins.

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

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

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

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

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

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


Burn and respawn or loop

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

Decision point at end of patrol cycle:

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

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

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

This enables infinite patrol duration via context-aware respawning.


Clean dead sessions

Clean dead sessions and orphaned state.

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

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

# Fix everything
gt doctor --fix
```

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

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


Find abandoned work

Find abandoned work.

Scan for orphaned state:
- Issues marked in_progress with no active polecat
- Polecats that stopped responding mid-work
- Merge queue entries with no polecat owner
- Wisp sessions that outlived their spawner

```bash
bd list --status=in_progress
gt polecats --all --orphan
```

For each orphan:
- Check if polecat session still exists
- If not, mark issue for reassignment or retry
- File incident beads if data loss occurred


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.


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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


mol-witness-patrol

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

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

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

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

## The Christmas Ornament Shape

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


Handle callbacks from agents

Handle callbacks from agents.

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

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

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


gt-witness-gastown

gt-witness-gastown

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

Migrated to canonical naming: gt-gastown-witness/refinery


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


Digest: mol-deacon-patrol

Patrol cycle 80: All healthy


Digest: mol-deacon-patrol

Patrol cycle 40: All healthy, 20 cycles complete - handoff per heuristic


Digest: mol-deacon-patrol

Patrol 116: All healthy


Use atomic write pattern for state files

attached_args: Atomic write pattern for state files

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 4 complete. All healthy.


Digest: mol-deacon-patrol

Patrol 2: All healthy, no issues


gt feed: Add convoy dashboard panel for in-progress and recently-landed

## The Insight

Convoys are now the most important unit of work for certain Gas Town users.
The convoy-landing feed is THE view of feature work and fixes actually shipping.

## Current State

gt feed shows:
- Agent tree (top panel): agents by role
- Event stream (bottom panel): issue/molecule activity

Missing: **Convoy status panel**

## Proposed Enhancement

Add a convoy panel showing:

```
┌─🚚 Convoys─────────────────────────────┐
│ IN PROGRESS                            │
│  hq-qrfz4  cv-startup      2/4 ●●○○   │
│  hq-wvqi6  Boot+Polish     3/5 ●●●○○  │
│                                        │
│ RECENTLY LANDED (24h)                  │
│  hq-abc12  Auth refactor   ✓ 2h ago   │
│  hq-def34  API cleanup     ✓ 5h ago   │
└────────────────────────────────────────┘
```

## Components

1. **In-progress convoys**: Open convoys with progress bars (completed/total)
2. **Recently landed**: Convoys that closed in last 24h (configurable)
3. **Quick stats**: Total in-flight, landed today, etc.

## Integration Options

A) New panel in existing TUI (3-panel layout)
B) Dedicated `gt convoy feed` or `gt convoy watch` command
C) Both - convoy panel in main feed + dedicated convoy view

## Why This Matters

The agent tree shows WHO is working.
The event stream shows WHAT is happening.
The convoy panel shows WHAT IS SHIPPING.

For stakeholders, the convoy view is the most important - "what features landed today?"

Implemented convoy dashboard panel in gt feed TUI with progress bars and recently-landed section


Digest: mol-deacon-patrol

Patrol cycle 25: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol cycle 4: All quiet.


Digest: mol-deacon-patrol

Patrol cycle 2: All healthy, idle town


gt hook: Cannot resolve HQ beads from polecat context

## Problem
`gt hook hq-eggh5` fails from within a polecat clone:
```
Error: resolving ID hq-eggh5: operation failed: failed to resolve ID: no issue found matching "hq-eggh5"
```

## Context
- Ran from: ~/gt/gastown/polecats/furiosa
- Bead exists: `bd show hq-eggh5` works from town root
- Routes exist: ~/gt/.beads/routes.jsonl has hq- prefix mapped

## Expected
HQ beads (hq-* prefix) should be resolvable from anywhere in town via prefix-based routing.

## Actual
Polecat can only resolve beads with its own rig's prefix (gt-*).

## Impact
Cannot sling HQ-level issues to polecats - breaks cross-rig coordination.

## Workaround
Unknown - possibly need to copy/mirror the bead to rig-level beads first.

Fixed: bd update now checks needsRouting() before daemon RPC to enable cross-rig bead updates


Digest: mol-deacon-patrol

Patrol 95: All healthy


Merge: rictus-mjw3nj1a

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


Extract magic values to named constants

Magic strings and numbers throughout codebase:

Shells list repeated 4x:
- start.go:729, 773, 907
- crew_helpers.go
Pattern: []string{"bash", "zsh", "sh", "fish", "tcsh", "ksh"}

Timing values:
- time.Sleep(500 * time.Millisecond) in multiple places
- WaitForCommand 15*time.Second
- WaitForShellReady 5*time.Second
- Debounce 100ms default

Other magic values:
- "gt-" session prefix
- priority = 2 default
- Mail preview length 500 chars
- Heartbeat ages 5min/15min
- Divergence thresholds 10/50 commits

Suggestion: Add to constants/constants.go:
- SupportedShells
- ShutdownNotifyDelay, ClaudeStartTimeout, ShellReadyTimeout
- SessionPrefix
- DefaultPriority
- MailPreviewMaxLength


gt done: MR bead not created

Integration test gt-7psb8 revealed that gt done says 'Work submitted to merge queue' but no MR bead is created.

Observed:
- gt done output: 'MR ID: mr-1766956116-b02fb1e5'
- bd show mr-1766956116-b02fb1e5: 'no issue found'
- gt mq list gastown: '(empty)'

Expected: MR bead should exist with issue_type=merge-request and appear in gt mq list.


Deacon convoy patrol steps

New Deacon patrol steps for convoy orchestration.

Steps:
1. check-convoy-completion
   - Watch town feed for tracked issue closures
   - Auto-close convoys when all tracked issues complete

2. resolve-external-deps
   - When external issue closes, propagate to dependents in other rigs
   - Update blocked status across project chain boundaries

3. fire-notifications
   - Convoy complete → notify Overseer inbox
   - Cross-rig dep resolved → notify affected rigs

Depends on: gt feed, bd-hj0s (convoy type)
Related: hq-7h8jx (Convoy System epic in town beads)

Implemented 3 convoy patrol steps: check-convoy-completion, resolve-external-deps, fire-notifications


Digest: mol-deacon-patrol

Patrol 5: routine


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.


Digest: mol-deacon-patrol

Patrol 7: routine


Digest: mol-deacon-patrol

Patrol cycle 23: All healthy, no incidents


Add live polling and updates

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


Patrol formulas: Inconsistent variable placeholder syntax

The patrol formulas use inconsistent syntax for variable placeholders:

## Inconsistency

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

## Expected

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

## Fix

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


Digest: mol-deacon-patrol

Patrol cycle 20: All 6 agents healthy, handoff threshold


Merge: slit-1767087730371

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


Digest: mol-deacon-patrol

Patrol cycle 2: All 6 agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol 52: All healthy


Update polecat template: Use gt done --exit

## Task

Update `templates/polecat-CLAUDE.md` to tell polecats to use `gt done --exit` instead of `gt done` + waiting.

## Changes

1. Update completion checklist:
```
OLD:
[ ] 6. Run gt done:       gt done
[ ] 7. WAIT:              Witness will kill your session

NEW:
[ ] 6. Exit session:      gt done --exit
```

2. Remove "WAIT" step - no more waiting

3. Update explanation of gt done to mention --exit flag

## Dependencies

- gt-lynar (gt done --exit feature)

Updated polecat template to use gt done --exit


Digest: mol-deacon-patrol

Patrol 13: Routine


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy


Molecule converge: iterate until AI says done

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

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

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

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

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

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


Code review formula: First complete formula implementation

Create .beads/formulas/code-review.formula.toml with 7 legs:
- correctness, performance, security, elegance, resilience, style, smells

Test end-to-end:
1. gt formula run code-review --pr=<test-pr>
2. Verify all legs spawn and complete
3. Verify synthesis produces unified review
4. Verify convoy status shows progress

This is the proof-of-concept for the whole formula system.

Formula complete: 7 review legs, synthesis step, convoy type. End-to-end testing confirmed by rictus.


Digest: mol-deacon-patrol

Patrol 4: healthy


Digest: mol-deacon-patrol

Patrol 151 complete


Digest: mol-deacon-patrol

Patrol 203: Routine checks, all systems nominal


Digest: mol-deacon-patrol

Patrol 101-120 complete: Cleaned 42 stale wisps, health pings sent to all witnesses/refineries, all agents healthy, no orphans, 1 idle dog


Digest: mol-deacon-patrol

Patrol cycle 44: All healthy


Witness sends HEALTH_OK mail to mayor on every deacon ping

## Problem

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

## Current behavior

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

This happens every patrol cycle (~30s).

## Expected behavior

Witnesses should NOT send mail responses to routine health checks.

## Fix

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

Updated witness templates to not mail on HEALTH_CHECK nudges


Merge: gt-cehl8

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


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.

Already removed - no ~/gt/molecules/ directory exists, no refs in docs


Digest: mol-deacon-patrol

Patrol 8: quiet


Digest: mol-deacon-patrol

Cycle 294: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol 18: Routine


Day 1.5: Create role beads from CLAUDE.md content

Create role beads from existing CLAUDE.md files:
- gt-mayor-role (from mayor CLAUDE.md)
- gt-witness-role (from witness CLAUDE.md)
- gt-refinery-role (from refinery CLAUDE.md)

Each role bead contains priming instructions and default_molecule.

Parent: gt-d0jqp


Cross-rig worktree support for crew

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

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

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

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

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

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

Cross-rig worktree support complete - all 4 tasks implemented.


Implement gt worktree create command

Create worktree in target rig for cross-rig work.

Usage: gt worktree <rig>

Behavior:
1. Detect current identity (gastown/crew/joe)
2. Compute worktree path: ~/gt/<rig>/crew/<source-rig>-<name>/
3. If worktree doesn't exist:
   - git worktree add <path> main
   - Set up .git config for identity preservation
4. cd to worktree (or print path for user to cd)
5. Preserve BD_ACTOR, GT_ROLE, etc.

Edge cases:
- Worktree already exists → just enter it
- Rig doesn't exist → error with helpful message
- No crew identity → error (must be crew to use this)

Implemented gt worktree command for cross-rig work


Implement gt worktree list command

List all worktrees owned by current crew member.

Usage: gt worktree list

Output:
```
Cross-rig worktrees for gastown/crew/joe:

  beads     ~/gt/beads/crew/gastown-joe/     (clean)
  mayor     ~/gt/mayor/crew/gastown-joe/     (2 uncommitted)
```

Implementation:
- Scan all rigs in ~/gt/
- Check for crew/<source-rig>-<name>/ directories
- Show git status summary for each


Implement gt worktree remove command

Remove a cross-rig worktree.

Usage: gt worktree remove <rig>

Behavior:
1. Check for uncommitted changes → warn/abort
2. git worktree remove <path>
3. Clean up directory if needed

Safety:
- Refuse if uncommitted changes (unless --force)
- Confirm before removal

Already implemented and merged in d72cb6b9


Document cross-rig worktree pattern

Add documentation for crew cross-rig work pattern.

Update:
- CLAUDE.md crew context with worktree usage
- docs/understanding-gas-town.md with role taxonomy clarification
- PRIMING.md if needed

Key points to document:
- Crew vs Dogs distinction (dogs = Deacon's infra, not user work)
- Identity preservation across rigs
- When to use worktrees vs dispatch to local workers
- Directory structure convention

Added cross-rig worktree documentation to crew.md.tmpl and created docs/understanding-gas-town.md


Merge: dag-mjw70jg8

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


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

Split handle-dirty-state into 3 focused steps: handle-uncommitted (staged/unstaged changes), handle-untracked (untracked files with decision matrix), and handle-stashes (review/clean old stashes)


ZFC #7: Make message age filtering configurable

**ZFC Violation:** internal/daemon/lifecycle.go:64-75

Go hardcodes 6-hour max message age:
```go
const MaxLifecycleMessageAge = 6 * time.Hour
```

**ZFC-compliant solution:**
- Make this configurable per message type
- Or let agents decide message relevance
- Low priority - not blocking liftoff

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


Digest: mol-deacon-patrol

Patrol cycle 8: All healthy, 4 polecats active (furiosa, nux, rictus, slit)


announce: shared bulletin board

Announcement channel with shared single-copy storage.

## Deliverables

1. Parse announce:name syntax
2. Shared storage model (like queue, but no claim):
   - Single message copy
   - Multiple readers can view
   - Informational, not work-creating
3. Configuration in ~/gt/config/announce.json
4. Read tracking (optional): who has seen it

## Key semantics
- Informational broadcast
- Missing is OK (not critical)
- Use case: "Bob refactoring logging, be aware"

## Dependencies
- Config directory (gt-i6jvc)
- queue: implementation (pattern reference)

## Acceptance
- announce:status creates single shared message
- Multiple agents can read
- No claim semantics (read-only)


Add expandQueue() to resolve queue workers from messaging.json

Add queue expansion to internal/mail/router.go.

PATTERN TO FOLLOW:
Look at expandList() at lines 63-87 as the template.

IMPLEMENTATION:
1. Add expandQueue(queueName string) (*config.QueueConfig, error)
2. Load messaging.json via config.LoadMessagingConfig
3. Look up queueName in cfg.Queues map
4. Return the QueueConfig (workers list, max_claims) or ErrUnknownQueue

FILE: internal/mail/router.go
ADD: var ErrUnknownQueue = errors.New("unknown queue") near ErrUnknownList

TESTS: Add TestExpandQueue in router_test.go

Depends on isQueueAddress being added first.

Added expandQueue() with ErrUnknownQueue and tests


Digest: mol-deacon-patrol

Cycle 199: Nominal


Merge: coma-mjwjczb0

branch: polecat/coma-mjwjczb0
target: main
source_issue: coma-mjwjczb0
rig: gastown
agent_bead: gt-gastown-polecat-coma


Mayor notification levels (Do Not Disturb mode)

## Problem

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

## Use Cases

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

## Design Considerations

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

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

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

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

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

Implemented gt dnd and gt notify commands with nudge integration


Digest: mol-deacon-patrol

Patrol #6: All quiet, 1 dog idle.


Agent scanner utility for filesystem

Filesystem scanner to discover agent directories in a rig or town.

## Deliverables

1. Function: ScanRigAgents(rigPath) -> []AgentAddr
   - Finds: witness/, refinery/, crew/*, polecats/*
   - Returns normalized addresses (e.g., "gastown/witness")

2. Function: ScanTownAgents(townPath) -> []AgentAddr
   - Iterates all rigs, calls ScanRigAgents for each
   - Returns all agent addresses in town

3. Alias resolution:
   - @rig/gastown → ScanRigAgents("gastown")
   - @town → ScanTownAgents()
   - @witnesses → filter for */witness across all rigs
   - @crew/gastown → filter crew/* in gastown

## Location
internal/discovery/scanner.go (new package)

## Acceptance
- Scanner finds all agent types
- Alias patterns resolve correctly
- Unit tests pass


Support space-separated rig/polecat syntax in gt polecat commands

## Problem
`gt polecat remove beads obsidian` fails with:
```
Error: invalid address 'beads': invalid address format: expected 'rig/polecat', got 'beads'
```

Requires slash syntax: `gt polecat remove beads/obsidian`

## Proposal
Support both syntaxes for ergonomics:
```bash
gt polecat remove beads/obsidian    # address syntax (current)
gt polecat remove beads obsidian    # positional syntax (proposed)
```

## Implementation
In polecat subcommands that take rig/polecat addresses:
- If arg contains `/`, use as-is
- If two args without `/`, join with `/`
- Apply to: remove, status, sync, reset, done

```go
func normalizePolecatAddress(args []string) string {
    if len(args) == 1 && strings.Contains(args[0], "/") {
        return args[0]
    }
    if len(args) == 2 {
        return args[0] + "/" + args[1]
    }
    // error handling...
}
```

## Rationale
- Unambiguous context - polecat commands always take rig + name
- Matches positional arg patterns in docker, kubectl, etc.
- Reduces agent friction (natural first guess is space-separated)
- Slash syntax remains valid for consistency with mail addresses


Digest: mol-deacon-patrol

Patrol 152: All healthy


Add molecule to update local go binary on push to main

When pushing to main branch, automatically rebuild and install the gt binary on the local machine so changes are immediately available.


Merge: morsov-1767106016839

branch: polecat/morsov-1767106016839
target: main
source_issue: morsov-1767106016839
rig: gastown


Witness should nuke polecats after completion, not leave idle

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

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

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

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

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

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

Implemented auto-nuke in witness handlers (e3933d7)


Digest: mol-deacon-patrol

Patrol complete: all agents healthy, no mail, no orphans


Digest: mol-deacon-patrol

Patrol cycle 16: All healthy, gastown refinery queue at 3


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy. Routine check.