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

## Problem

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

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

## Expected Behavior

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

## Reproduction

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

## Root Cause

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

## Fix Options

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


Digest: mol-deacon-patrol

Patrol 3: All agents healthy, no messages


gt-gastown-polecat-dag

gt-gastown-polecat-dag

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-tvwnz
role_bead: gt-polecat-role
cleanup_status: clean
active_mr: gt-vve6k
notification_level: null


Digest: mol-deacon-patrol

Patrol 10: All healthy


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

Mayor management CLI commands.

## Commands

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

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

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

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

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

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

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

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

## New File
internal/cmd/mayor.go

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

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


Digest: mol-deacon-patrol

Patrol cycle 9: All quiet.


Digest: mol-deacon-patrol

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


Polecat role references deprecated 'swarm' terminology

prompts/roles/polecat.md line 12 says:
'Part of a swarm: Other polecats may be working on related issues in parallel'

But architecture.md explicitly states:
'There are no swarm IDs - just epics with children'

The swarm concept has been replaced by streams/dependency model.
Update polecat.md to remove swarm references.


Dog agent beads with role_type=dog

## Dog Agent Beads for @group Resolution

Dogs need agent beads with `role_type=dog` for @dogs group resolution to work.

## Background

Dogs are Deacon's reusable helper workers (see patrol-system-design.md):
- Location: `deacon/dogs/<name>/`
- Scope: Town-level, cross-rig
- Managed by: Deacon
- Lifecycle: Reusable (not ephemeral like polecats)

## Deliverables

1. When `gt dog add <name>` creates a dog, also create agent bead:
   ```bash
   bd create --type=agent --title="Dog: <name>" \
     --labels="role_type:dog,rig:town,location:deacon/dogs/<name>"
   ```

2. When `gt dog remove <name>` removes a dog, close the agent bead

3. Ensure `bd list --type=agent --role_type=dog` returns all dogs

## Schema

Dog agent beads should have:
- `type: agent`
- `role_type: dog` (in labels or dedicated field)
- `rig: town` (dogs are town-level, not rig-level)
- `location: deacon/dogs/<name>`

## Dependencies
- gt dog add/remove commands (may not exist yet)
- Agent bead schema supports role_type

## Acceptance
- `bd list --type=agent --role_type=dog` returns all dogs
- Dog beads created/closed with dog lifecycle
- @dogs group resolution works in mail router


Digest: mol-deacon-patrol

Patrol 13: All healthy.


Digest: mol-deacon-patrol

Patrol 11: routine


Dynamic arm bonding in witness patrol

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 18: OK


Move disk 1: C → A

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol cycle 1: All healthy - 19 polecats, witness/refinery running, 3 MQ items, no zombies


gt-gastown-polecat-capable

gt-gastown-polecat-capable

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-rbncw
role_bead: gt-polecat-role
cleanup_status: clean
active_mr: gt-obbev
notification_level: null


Digest: mol-deacon-patrol

Patrol cycle 3: All 6 agents healthy, 2 polecats (furiosa, nux), refinery queues active (gastown:2, beads:1)


Digest: mol-deacon-patrol

Patrol 118: All healthy


Move disk 3: A → B

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol #3: Stable, no changes


Move disk 2: C → B

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


Merge: cheedo-1767079863534

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


Formula versioning and migration strategy

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

Deferred: post-launch polish


Digest: mol-deacon-patrol

Patrol #10: Halfway checkpoint


Move disk 1: A → B

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


Refinery semantic merge processing loop

Implement the Refinery semantic merge loop for processing polecat work.

## Overview

The Refinery is a fully empowered Claude Code agent that:
1. Fetches polecat branches
2. Merges to integration branch
3. Resolves conflicts semantically (re-implements if needed)
4. Runs tests
5. Escalates only when truly stuck

## Processing Loop

1. Check queue for completed tasks (polecat done, not yet merged)
2. For each task:
   - Fetch polecat branch
   - Attempt merge to integration/<swarm-id>
   - On conflict: semantic resolution (understand intent, re-implement)
   - Run tests if configured
   - On success: mark merged, file bead, notify witness
   - On failure: notify polecat (test fail) or escalate (stuck)
3. When all tasks merged: land integration to main

## Semantic Merge

When git merge fails, Refinery:
1. Reads polecat changes and beads issue
2. Understands intent
3. Re-implements on current integration branch
4. Only escalates if truly blocked

## Daemon Poking

Refinery is poked by:
- Daemon heartbeat (periodic)
- Witness notification (polecat done)
- Mayor request (check queue)

## Dependencies

Needs: gt-u1j.6 (mail), gt-u1j.3 (git), gt-u1j.14 (merge queue)

## Reference

See PGT ephemeral.py for branch operations.


Move disk 2: C → B

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


gt mq list: doesn't show submitted MRs

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

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

## Expected
gt mq list should show submitted MRs

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


Move disk 1: A → B

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


Refinery Patrol

Merge queue processor patrol loop with verification gates.


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

Patrol 6: quiet


Implement gt mq CLI commands

Add gt mq subcommands as sugar over bd:

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

All commands should work with the Beads data plane.


Swarm: report generation

Generate markdown reports for completed swarms.

## Command
```
gt swarm report <swarm-id> [--save <file>]
```

## Report Content

### Header
- Swarm ID and title
- Created/completed timestamps
- Duration
- Rig name

### Task Summary
| Task | Assignee | Status | Duration |
|------|----------|--------|----------|
| gt-xxx | Toast | merged | 15m |
| gt-yyy | Nux | merged | 22m |

### Worker Contributions
- Commits per worker
- Issues closed per worker
- Lines changed (optional)

### Timeline
- Chronological events from events.jsonl
- Key milestones (started, first merge, landing)

### Issues Encountered
- Conflicts resolved
- Failed tasks (if any)
- Escalations

## Implementation
```go
func GenerateReport(swarmID string) (*SwarmReport, error)
func (r *SwarmReport) ToMarkdown() string
```

## Storage
- Save to <rig>/.gastown/swarms/<id>/report.md
- Or user-specified path with --save

## PGT Reference
gastown-py/src/gastown/swarm/manager.py generate_report()

## Acceptance Criteria
- [ ] Markdown report generated
- [ ] Includes all sections above
- [ ] Auto-saved to swarm directory
- [ ] --save allows custom path


Move disk 2: B → A

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


Move disk 3: C → A

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


Move disk 3: B → C

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


Merge: furiosa-mjw17xzd

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 1: C → A

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


mol-deacon-patrol


Move disk 2: B → A

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


Move disk 6: B → A

Move disk 6 from peg B to peg A. (Move 160/1023)


Digest: mol-deacon-patrol

Patrol 12: Nominal


gt-gastown-polecat-morsov

gt-gastown-polecat-morsov

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


Digest: mol-deacon-patrol

Patrol 9: All clear


Digest: mol-deacon-patrol

Patrol 10: quick pass, hitting halfway point


gt-gastown-polecat-dex

gt-gastown-polecat-dex

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


Standardize bd mol vs gt mol commands

Audit all docs and templates for command usage.

Clarify:
- gt mol = Gas Town wrapper (what does it add?)
- bd mol = Beads molecule commands (authoritative)

If gt mol is thin wrapper, consider removing.


Town Doctor molecule for harness health checks

Create a Town Doctor molecule that any Gas Town agent can run to diagnose and repair harness issues.

## Concept

Instead of just `gt doctor` as a CLI command with hardcoded checks, create a **molecule** (checklist workflow) that:
- Any agent (Mayor, Witness, Polecat) can instantiate
- Walks the agent through diagnostic steps
- Agent uses judgment to fix issues found
- Works as a structured troubleshooting guide

## Why a Molecule?

1. **Agent-driven**: The agent running it becomes "the doctor" temporarily
2. **Extensible**: Add new checks by updating the molecule, not code
3. **Contextual**: Agent can reason about issues, not just run scripts
4. **Self-healing**: Agent can fix problems it finds, not just report them

## Proposed Checks (molecule steps)

1. Verify harness structure (mayor/, .beads/, CLAUDE.md exist)
2. Validate config files (town.json, rigs.json parse correctly)
3. Check beads health (bd doctor, redirect validity)
4. Verify git state (clean working tree, proper remotes)
5. Check rig integrity (each registered rig exists, has config.json)
6. Validate agent clones (mayor/rig/, refinery/rig/ exist and are valid)
7. Check for orphaned worktrees/branches
8. Verify daemon state (if running)

## Integration

- `gt doctor` could instantiate the molecule for the current agent
- Or agent can run `bd ready` and pick up doctor tasks when prioritized
- Results logged to beads for audit trail

## Related

- gt-cr9: Harness Design & Documentation (completed)
- Molecules design in architecture.md


Move disk 1: C → A

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


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 5: 3 polecats working


Digest: mol-deacon-patrol

Patrol 243 complete: no incidents


Agent Communication Protocol

Structured mail between agents for coordination.

## Problem
Agents communicate via freeform mail. This works but lacks parseable structure for automated handling.

## Protocols

### Witness to Refinery
- POLECAT_READY: worker X completed, branch ready for merge
- REWORK_COMPLETE: worker Y finished requested rework

### Refinery to Witness
- MERGE_SUCCESS: worker X merged, can be cleaned up
- MERGE_FAILED: worker X needs rework (reason attached)
- REWORK_REQUEST: please have worker X rebase on current main

### Polecat to Witness
- WORK_COMPLETE: done with assigned issue
- NEED_HELP: stuck, requesting intervention

### Any to Deacon
- ESCALATION: problem requiring Mayor attention

## Mail Format
Subject: [PROTOCOL_TYPE] brief description
Body: Structured YAML or JSON payload

## Success Criteria
- Patrol steps parse protocol messages automatically
- Handlers exist for each protocol type
- Integration test: polecat completes -> witness notifies -> refinery merges -> witness cleans up

Consolidates gt-0qki.


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy, handoff threshold reached


Merge: nux-mjtj9d8q

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


Digest: mol-deacon-patrol

Patrol 11


plugin-run

Execute plugins from ~/gt/plugins/. Check gates, run eligible plugins.


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol cycle 1: All 3 rigs healthy. 0 messages processed. Witnesses/refineries pinged.


Digest: mol-deacon-patrol

Patrol 20: clear, handoff


Move disk 2: A → C

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


Move disk 3: C → A

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


Move disk 1: A → B

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


Session ended: gt-gastown-ace


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


survey-workers

List polecats and categorize by status.

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

Needs: load-state


Replaceable notifications via Claude Code queue

Leverage Claude Code's ability to replace queued text for notifications that supersede previous ones.

## Problem

If daemon sends 10 heartbeats while agent is busy, agent returns to see 10 stacked messages. Wasteful and noisy.

## Solution

Use Claude Code's queue replacement for:
- Heartbeat messages (only latest matters)
- Status updates that supersede previous
- Progress notifications

## Implementation

Notifications get a 'slot' identifier. New notification in same slot replaces old one:
- Slot: 'heartbeat' → only one heartbeat queued at a time
- Slot: 'status-<rig>' → latest status per rig
- No slot → stacks normally (for unique messages)

## Research Needed

- How does Claude Code expose queue replacement?
- tmux send-keys behavior with pending input
- Alternative: clear + resend pattern


Patrol agent state.json not updated on activity

Witness and Refinery state.json files show last_active from Dec 19 even though sessions have been running. The state should update each patrol cycle.

Evidence:
```
$ cat beads/witness/state.json
{"role": "witness", "last_active": "2025-12-19T17:50:00Z"}

$ cat beads/refinery/state.json
{"role": "refinery", "last_active": "2025-12-19T17:50:00Z"}
```

Expected: last_active should update each time the agent runs a patrol cycle.

Impact: Can't tell if patrol agents are actually active vs just having an open tmux session.


gt-polecat-gastown-slit

gt-polecat-gastown-slit

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-gcnnr
role_bead: null


Digest: mol-deacon-patrol

Patrol 6: nominal


Document harness concept in docs/harness.md

Create comprehensive harness documentation:
- What is a harness (installation directory)
- Recommended structure and naming
- .beads/redirect for default project
- config/ contents (rigs.json, town.json)
- Mayor home vs rig-level mayor/
- Example configurations
- Relationship to rigs


Digest: mol-deacon-patrol

Patrol 11: All healthy


gt mq integration create: create integration branch for epic

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

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

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

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

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


Harden bd daemon startup for reliable gt status

GH #25: gt status slow (39s) when bd daemon not running. Needs daemon health checks, auto-migration, better errors.


Digest: mol-deacon-patrol

Patrol 139: All healthy


Move disk 2: B → A

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


Move disk 1: B → C

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


Survey all polecats (fanout)

List polecats and bond mol-polecat-arm for each one.

```bash
# Get list of polecats
gt polecat list <rig>
```

For each polecat discovered, dynamically bond an inspection arm:

```bash
# Bond mol-polecat-arm for each polecat
for polecat in $(gt polecat list <rig> --names); do
  bd mol bond mol-polecat-arm $PATROL_WISP_ID \
    --ref arm-$polecat \
    --var polecat_name=$polecat \
    --var rig=<rig>
done
```

This creates child wisps like:
- patrol-x7k.arm-ace (5 steps)
- patrol-x7k.arm-nux (5 steps)
- patrol-x7k.arm-toast (5 steps)

Each arm runs in PARALLEL. The aggregate step will wait for all to complete.

If no polecats are found, this step completes immediately with no children.


Digest: mol-deacon-patrol

Patrol 259 complete: no incidents


Digest: mol-deacon-patrol

Patrol cycle 4: all healthy


Digest: mol-deacon-patrol

P10: stable


Digest: mol-deacon-patrol

Patrol cycle 10: All healthy


Digest: mol-deacon-patrol

Patrol cycle 10: routine, healthy - midpoint


mol-deacon-patrol


Polecat template: move startup announcement into molecule

Template has STARTUP PROTOCOL with 'Announce: beads Polecat furiosa, checking in.' This should be a startup step in the polecat molecule, not prose instruction in CLAUDE.md. The molecule drives behavior, not the template prose.


Define mol-gastown-boot proto structure

Create the proto molecule definition with all steps.

## Proto Definition

Each step has:
- Title (step name)
- Description with Action/Verify/OnStall/OnFail sections
- Dependencies (Needs: directive)

## Steps

1. ensure-daemon
   - Action: gt daemon status || gt daemon start
   - Verify: daemon PID exists and responding

2. ensure-deacon
   - Action: gt deacon start
   - Verify: session exists, not stalled, heartbeat fresh
   - OnStall: gt nudge deacon/ "Start patrol."

3. ensure-witnesses (parallel container)
   - ensure-gastown-witness
   - ensure-beads-witness
   - Verify each: session exists, not stalled

4. ensure-refineries (parallel container)
   - ensure-gastown-refinery
   - ensure-beads-refinery
   - Verify each: session exists, not stalled

5. verify-town-health
   - Action: gt status
   - Verify: all expected agents shown

## Output

Proto stored in beads as molecule type issue.


Wisp squash design: cadences, rules, templates

Design how wisps squash to digests: When to squash (cadences), what to include (summary templates), retention rules. Currently under-designed. Should cover patrol wisps (squash per cycle) and work wisps (squash on completion). Consider allowing formulas to define squash templates.


Digest: mol-deacon-patrol

Patrol 142: 3 polecats working, all agents healthy


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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 11: All agents healthy, cleaned 18 stale wisps


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 8: All healthy


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy


Digest: mol-deacon-patrol

Patrol complete: fixed EMERGENCY clone divergence (zoey 103 behind, refinery 40 behind), cleaned orphan processes, created patrol molecules, fixed invalid hook attachments


Move disk 3: C → A

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


Digest: mol-deacon-patrol

P18: stable


Digest: mol-deacon-patrol

Patrol cycle 16: routine


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 6: All healthy, no messages


Digest: mol-deacon-patrol

Patrol 17: routine


gt crew remove: Remove crew workspace

Implement 'gt crew remove <name> [--force]' command:
- Check for uncommitted changes, unpushed commits
- Warn and require --force if dirty
- Kill any running session
- Remove directory
- Unregister from mail


Merge: rictus-mjtlq9xg

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


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

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


Move disk 1: B → C

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol cycle 14: All 6 agents healthy


boot

Spawned. Verify the polecat starts working.

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

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

Timeout: 60s before escalation to Mayor.
Variables: {{polecat}}, {{issue}}


gt nudge should accept flexible session identifiers

Currently `gt nudge` requires the exact tmux session name (e.g., `gt-gastown-furiosa`).

It should also accept:
- `gastown/furiosa` (rig/polecat format)
- `furiosa` (polecat name, infer rig from cwd or require if ambiguous)

The session list command shows `gastown/furiosa` format, but nudge rejects it:
```
gt session list → shows 'gastown/furiosa'
gt nudge gastown/furiosa 'msg' → 'session not found'
gt nudge gt-gastown-furiosa 'msg' → works
```

Should normalize all these formats to the tmux session name internally.


implement

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

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

Depends: load-context


gt context --usage: estimate remaining context via tmux line count

## Summary

Implement `gt context --usage` to estimate remaining context capacity.

## Approach

Use tmux scrollback buffer line count as proxy for token usage:
- `tmux capture-pane -p | wc -l` gives current line count
- Heuristics (tunable per model):
  - Opus 4.5: ~1800 lines = warning threshold
  - ~2000+ lines = critical, need handoff

## Output Format
```
Context Usage: 1642 lines (~82%)
Status: WARNING - consider handoff soon
```

## Notes
- Heuristics are model-specific, need config
- Line count is proxy, not exact token count
- Good enough for autonomous patrol decisions


Swarm beads naming convention and auto-filing

Beads naming convention for swarm lifecycle events.

## Bead IDs

- swarm-started:<swarm-id>     # Filed when swarm begins
- swarm-task-merged:<swarm-id>:<task-id>  # Filed per task merge
- swarm-landed:<swarm-id>      # Filed when merged to main
- swarm-failed:<swarm-id>      # Filed on unrecoverable failure

## swarm-started Bead

Filed by: Mayor/Refinery at swarm creation
Contains:
- Swarm title and description
- List of tasks (issue IDs)
- List of workers (polecat names)
- Base commit SHA

## swarm-task-merged Bead

Filed by: Refinery after each successful merge
Contains:
- Task issue ID and title
- Polecat name
- Merge commit SHA
- Test results summary

## swarm-landed Bead

Filed by: Refinery after landing to main
Contains:
- Final merge commit SHA
- Stats: tasks completed, time taken
- List of all merged task beads
- Integration branch name (now deleted)

## swarm-failed Bead

Filed by: Refinery on unrecoverable failure
Contains:
- Failure reason
- Tasks merged vs not merged
- Recovery guidance

## Why Beads (not just mail)

- Persistent, queryable, synced to git
- Other agents can check status without mail
- Creates audit trail
- Works when agents offline


Digest: mol-deacon-patrol

Patrol 2: All healthy


Merge: toast-1767088545235

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


SessionStart hook should pass session_id to gt prime

## Context

The seance discovery system relies on session_start events emitted by gt prime.
Currently, gt prime falls back to actor-PID when CLAUDE_SESSION_ID is not set.

## Enhancement

The SessionStart hook receives session_id in its stdin JSON:
```json
{
  "session_id": "abc123",
  "transcript_path": "...",
  "source": "startup|resume|clear|compact"
}
```

The hook should parse this and pass it to gt prime via environment variable:
```bash
SESSION_ID=$(cat /dev/stdin | jq -r ".session_id")
CLAUDE_SESSION_ID=$SESSION_ID gt prime
```

## Benefits

- Accurate session tracking for seances
- Can resume exact sessions via `claude --resume <id>`
- Events correlate with Claude Code session history

## Implementation

1. Update SessionStart hook in CLAUDE.md templates
2. Have gt prime read CLAUDE_SESSION_ID env var (already done)
3. Emit proper session_id in session_start events

Related: gt-7qvd7 (seance implementation)


Digest: mol-deacon-patrol

Patrol cycle 50: All healthy


Digest: mol-deacon-patrol

Patrol 20: healthy


Work on gt-role-template: Refine witness/CLAUDE.md role t...

Work on gt-role-template: Refine witness/CLAUDE.md role template. Add clearer heartbeat protocol, mail checking procedure, nudge decision criteria, escalation thresholds. Run 'bd show gt-role-template' for details.


Deacon plugin scheduler: cron-like execution

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

## Concept

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

## Plugin Registration

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

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

## Schedule Format

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

## Execution

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

## Plugin Execution Modes

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

## State Tracking

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

## Relation to gt-axz

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


Add no-PR instructions to mol-polecat-work at two points

Update mol-polecat-work in builtin_molecules.go to explicitly forbid GitHub PRs.

## Two Points to Add Instructions

### 1. submit-work step
When polecat is ready to submit:
- Push branch to origin
- Create beads merge-request issue
- DO NOT use gh pr create or GitHub PRs

### 2. CLAUDE.md polecat context
Add to polecat role instructions:
- Never use gh pr create
- Never create GitHub pull requests
- The Refinery processes merges via beads MR issues

## Why Two Points
- Molecule step description guides the workflow
- CLAUDE.md reinforces at context level
- Belt and suspenders approach

## Implementation
1. Update PolecatWorkMolecule() submit-work step description
2. Update prompts/roles/polecat.md with explicit prohibition

Related: gt-44wh (general no-PR bug)


Digest: mol-deacon-patrol

Patrol 14: all healthy


Move disk 2: C → B

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


Refinery Role Definition

You are the Refinery - merge queue processor for your rig. You process
completed polecat work, merging it to main one branch at a time with
sequential rebasing.

Your mission: Process the merge queue sequentially, rebasing each branch
atop the current baseline before merging.

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

default_molecule: mol-refinery-patrol
capabilities:
  - merge_queue_processing
  - sequential_rebase
  - conflict_resolution
  - verification_gates

## The Engineer Mindset

You are Scotty in the engine room. The merge queue is your warp core.

The Beads Promise: Work is never lost. If you discover ANY problem:
1. Fix it now (preferred if quick), OR
2. File a bead and proceed (tracked for cleanup crew)

There is NO third option. Never "disavow" by noting something exists and moving on.

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

## Propulsion Principle

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

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

## Sequential Rebase Protocol

WRONG (parallel merge - causes conflicts):
  main then branch-A (old main) + branch-B (old main) = CONFLICTS

RIGHT (sequential rebase):
  main then merge A (rebased on main) then merge B (rebased on main+A)

After every merge, main moves. Next branch MUST rebase on new baseline.

## Verification Gate

The handle-failures step is a verification gate:
- Tests PASSED: Gate satisfied, proceed to merge
- Tests FAILED (branch caused): Abort, notify polecat, skip branch
- Tests FAILED (pre-existing): MUST fix OR file bead - cannot proceed without

## Commands

### Patrol
- gt mol status - Check attached patrol
- bd ready / bd show / bd close - Step management
- bd mol spawn <mol> --wisp - Spawn patrol wisp

### Git Operations
- git fetch origin - Fetch all remote branches
- git branch -r | grep polecat - List polecat branches
- git rebase origin/main - Rebase on current main
- git push origin main - Push merged changes

### Communication
- gt mail inbox - Check for messages
- gt mail send <addr> -s "Subject" -m "Message" - Notify workers


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol #5: Stable


Move disk 3: A → B

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


Digest: mol-deacon-patrol

Patrol 10: quiet


Merge: toast-1767081120579

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


Move disk 3: B → C

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


Work request: gt-976 crew lifecycle support

Hey Max, filed gt-976 for you - adding crew lifecycle support to Deacon.

Currently crew is 'human-managed' and can't request automated refresh. Would be useful for molecules that need fresh sessions mid-workflow.

Key changes:
- getManager(RoleCrew) → return deacon/ instead of human
- Teach Deacon crew session patterns
- Test with gt nudge

Priority 2, no rush but would unblock molecule automation for crew.

- Dave (beads/crew/dave)


Witness daemon: heartbeat loop, spawn ephemeral agent

Background daemon for agent lifecycle and monitoring.

## Core Responsibilities

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

## Session Lifecycle (Witness Protection)

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

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

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

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

## Interface

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

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

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

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

## Heartbeat Loop

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


mol-polecat-arm

Single polecat inspection and action cycle.

This molecule is bonded dynamically by mol-witness-patrol's survey-workers step.
Each polecat being monitored gets one arm.

## Variables

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

## Steps

### capture
Capture recent tmux output for this polecat.

```bash
tmux capture-pane -t gt-{{rig}}-{{polecat_name}} -p | tail -50
```

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

### assess
Categorize polecat state.

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

Calculate: minutes since last activity.
Needs: capture

### load-history
Read nudge history for this polecat from patrol state.

```
nudge_count = state.nudges[{{polecat_name}}].count
last_nudge_time = state.nudges[{{polecat_name}}].timestamp
```

Needs: assess

### decide
Apply the nudge matrix to determine action.

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

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

Record decision and rationale.
Needs: load-history

### execute
Take the decided action.

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

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

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

**none**: No action needed.

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

## Output

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

This data feeds back to the patrol's aggregate step.

Labels: [template, christmas-ornament, polecat-arm]


Merge: slit-mjvtz18y

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


gt feed --follow: Town-level activity stream

Town-native command for aggregated activity feed.

Wraps bd activity --town with Gas Town conveniences:
- gt feed --follow         # Stream all rig activity
- gt feed --rig gastown    # Filter to specific rig
- gt feed --convoy hq-xxx  # Filter to convoy's tracked issues

Essential for Mayor/Deacon visibility into cross-rig work.

Depends on: bd-dx6e (bd activity --town)
Related: hq-7h8jx (Convoy System epic in town beads)


Move disk 1: A → B

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


Prompt templates: role contexts, nudge messages

Prompt templates for role contexts and messages.

## Template Types

### Role CLAUDE.md Templates

For gt prime and CLAUDE.md generation:
- Mayor template
- Witness template
- Refinery template
- Polecat template

### Message Templates

For notifications and nudges:
- Spawn assignment
- Witness nudge
- Escalation to Mayor
- Session handoff

## Implementation

```go
//go:embed templates/*.md.tmpl
var templateFS embed.FS

type Templates struct {
    fs embed.FS
}

func NewTemplates() *Templates
func (t *Templates) RenderRole(role string, data RoleData) (string, error)
func (t *Templates) RenderMessage(name string, data any) (string, error)
```

## Template Data

```go
type RoleData struct {
    Role      string
    RigName   string
    TownRoot  string
    Polecats  []string
    Commands  []CommandHelp
}

type SpawnData struct {
    Issue       string
    Title       string
    Priority    int
    Description string
}

type NudgeData struct {
    Polecat    string
    Reason     string
    NudgeCount int
    MaxNudges  int
}
```

## Template Location

Embedded in binary via go:embed:
```
internal/templates/
├── roles/
│   ├── mayor.md.tmpl
│   ├── witness.md.tmpl
│   ├── refinery.md.tmpl
│   └── polecat.md.tmpl
└── messages/
    ├── spawn.md.tmpl
    ├── nudge.md.tmpl
    └── escalation.md.tmpl
```

## Usage

gt prime uses role templates.
gt spawn uses spawn template.
Witness uses nudge/escalation templates.


Move disk 3: C → A

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


TODO: Detect cycles in molecule dependency graph

molecule.go:302 has a TODO to detect cycles in the dependency graph. Currently, cyclical dependencies could cause issues.


Merge: gt-veswi

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 1: C → A

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


Move disk 2: B → A

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


mol-deacon-patrol


gt spawn should auto-start refinery/witness if not running

When spawning a polecat, the infrastructure (refinery, witness) should already be running.

## Current Behavior
spawn.go only:1. Assigns issue to polecat2. Sends work mail3. Starts polecat session

The refinery and witness must be started separately.

## Expected Behavior (per user feedback)
When spawning a polecat, if the rig's refinery or witness is not running, auto-start them.

## Options

### Option A: spawn auto-starts infrastructure
Check if refinery/witness running before spawn, start if not.

### Option B: gt swarm start <rig> command
Explicit command that:
1. Starts refinery
2. Starts witness
3. Optionally spawns polecats on bd ready issues

### Option C: gt rig start <rig>
Similar to Option B but as rig lifecycle command.

## Related
- gt-n7z7: refinery --foreground race condition bug
- gt-u1j.18: witness CLI commands


Move disk 1: B → A

Move disk 1 from peg B to peg A.


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


Move disk 1: B → C

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


Patrol step: check parked molecules for unblock

Add patrol step to Deacon for checking parked molecules:

```yaml
- step: check-parked-molecules
  action: |
    For each molecule with:
      - status: in_progress
      - assignee: null
      - has step with external: blocked_by
    Check if external deps are now satisfied.
    If yes: spawn polecat to resume the molecule.
```

This automates the resume process - no manual intervention needed when
upstream dependencies ship.

Part of cross-project dependency system.
See: docs/cross-project-deps.md

Depends on: gt-in3x (spawn --continue)
Priority: P3 (future automation, not required for launch)


Outpost error handling: Retry logic and resilience

## Overview

Error handling and retry logic for outpost operations.

## Error Types

```go
var (
    ErrOutpostUnreachable = errors.New("outpost unreachable")
    ErrWorkerSpawnFailed  = errors.New("worker spawn failed")
    ErrWorkerTimeout      = errors.New("worker timed out")
    ErrCostCapExceeded    = errors.New("cost cap exceeded")
    ErrAllOutpostsBusy    = errors.New("all outposts at capacity")
)
```

## Retry Policy

```go
type RetryPolicy struct {
    MaxAttempts     int
    InitialBackoff  time.Duration
    MaxBackoff      time.Duration
    BackoffFactor   float64
    RetryableErrors []error
}

func DefaultRetryPolicy() *RetryPolicy {
    return &RetryPolicy{
        MaxAttempts:    3,
        InitialBackoff: 1 * time.Second,
        MaxBackoff:     30 * time.Second,
        BackoffFactor:  2.0,
        RetryableErrors: []error{
            ErrOutpostUnreachable,
            ErrWorkerSpawnFailed,
        },
    }
}
```

## Retry Implementation

```go
func (m *OutpostManager) SpawnWithRetry(issue string, cfg WorkerConfig) (Worker, error) {
    var lastErr error
    backoff := m.retryPolicy.InitialBackoff

    for attempt := 0; attempt < m.retryPolicy.MaxAttempts; attempt++ {
        outpost := m.policy.SelectOutpost(issue, m.outposts)
        if outpost == nil {
            return nil, ErrAllOutpostsBusy
        }

        worker, err := outpost.Spawn(issue, cfg)
        if err == nil {
            return worker, nil
        }

        if !m.isRetryable(err) {
            return nil, err
        }

        lastErr = err
        time.Sleep(backoff)
        backoff = min(backoff * m.retryPolicy.BackoffFactor, m.retryPolicy.MaxBackoff)
    }

    return nil, fmt.Errorf("spawn failed after %d attempts: %w",
        m.retryPolicy.MaxAttempts, lastErr)
}
```

## Outpost Health Tracking

```go
type OutpostHealth struct {
    LastPing      time.Time
    LastError     error
    FailureCount  int
    CircuitBreaker bool  // If true, skip this outpost
}

func (m *OutpostManager) updateHealth(name string, err error) {
    // Track failures, open circuit breaker after N failures
    // Auto-reset after successful ping
}
```

## Config

```yaml
policy:
  retry:
    max_attempts: 3
    initial_backoff: 1s
    max_backoff: 30s

  circuit_breaker:
    failure_threshold: 5
    reset_timeout: 1m
```

## Files

- `internal/outpost/retry.go`
- `internal/outpost/health.go`

## Dependencies

Depends on: gt-9a2.3 (OutpostManager)
Can be done after basic outpost implementations work.


Move disk 3: C → A

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


Merge: gt-caih

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


Formula schema: Define formula.toml structure

Define the formula file format in .beads/formulas/:
- formula name and description
- input parameters (pr, branch, files)
- legs array with name, focus, output
- synthesis config
- dependencies between legs

Reference: gt-ubqeg.1 epic description for schema ideas.
Create example formula: code-review.formula.toml


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

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


Witness Patrol

Per-rig worker monitor patrol loop with progressive nudging.


Digest: mol-deacon-patrol

Patrol 14: healthy


Digest: mol-deacon-patrol

Patrol 14: quick pass


Harness Design & Documentation

The harness (Gas Town installation directory) needs design cleanup, documentation, and tooling.

## Current Problems

1. **Shared harness confusion**: ~/ai is shared by PGT and GGT with overlapping structures
   - PGT uses ~/ai/mayor/ as town-level Mayor home
   - GGT Mayor works in ~/ai/mayor/rigs/gastown/
   - ~/ai/gastown/ has both .gastown/ (PGT) and mayor/ (git clone)

2. **Beads redirect**: ~/ai/.beads/redirect → mayor/rigs/gastown/.beads
   - This is specific to GGT's decentralized structure
   - Should be documented as an example

3. **architecture.md**: Verify rig-level mayor/rig/ is shown correctly

4. **No harness creation tooling**: Users must manually set up

## Proposed Work

- Document what a harness IS (installation directory)
- Create harness creation command or template repo
- Update architecture.md if needed
- Create example harness configuration for docs
- Resolve PGT/GGT sharing issue


Digest: mol-deacon-patrol

Patrol 7


Merge: gt-h6eq.4

branch: polecat/valkyrie
target: main
source_issue: gt-h6eq.4
rig: gastown


Clean up stale issue references in comments

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

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

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

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

## Tombstoned epic references (epic superseded):

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

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

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


Merge: capable-1767081117001

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


Digest: mol-deacon-patrol

Patrol 32: all quiet


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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 10: Quiet, 8 sessions healthy


Digest: mol-deacon-patrol

Patrol 8: All agents healthy


Digest: mol-deacon-patrol

Patrol 12: clear


Clarify GIT_AUTHOR_EMAIL handling for agents

When setting GIT_AUTHOR_NAME per agent (gt-6r18e.1), also need to decide GIT_AUTHOR_EMAIL:

Option A (proposed): Keep overseer's git email
- GIT_AUTHOR_EMAIL = steve.yegge@gmail.com (from git config)
- This anchors ownership to the human
- Agents are tools of the overseer

Option B: Construct agent email
- GIT_AUTHOR_EMAIL = gastown-crew-joe@gastown.local
- Fully separates agent identity
- May cause issues with GitHub/Bitbucket attribution

Recommendation: Option A - keeps human ownership clear while GIT_AUTHOR_NAME shows which agent did the work.


Merge: valkyrie-mjw71b7u

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 2: archived stale Mayor handoffs, all agents healthy


Digest: mol-deacon-patrol

Patrol 8


Digest: mol-deacon-patrol

Patrol 6: Routine


Fix deprecated strings.Title in formula.go

formula.go uses deprecated strings.Title (Go 1.18+). Should use cases.Title(language.English).String() from golang.org/x/text/cases.


Move disk 2: C → B

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


Plugin: merge-oracle (merge queue analysis)

Example plugin that analyzes changesets before Refinery processes them. Builds overlap graph, classifies disjointness (parallel-safe vs needs-sequencing), uses LLM for semantic complexity, identifies high-risk patterns. Based on merge-orchestration proposal. See docs/architecture.md.


Extract interfaces for Git and Tmux to enable testing

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

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

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 17


Implement bd mol bond --ephemeral flag

Add --ephemeral flag to bd mol bond command to support ephemeral molecule bonding.

## Context
Phase 1.2 of Wisp Molecule Integration (gt-3x0z.2) discovered that this flag doesn't exist.

## Requirements

1. Add --ephemeral flag to mol bond command
2. When --ephemeral is set:
   - Mark spawned issues with wisp=true
   - Optionally write to separate .beads-ephemeral/ storage (Phase 2)

## Architecture Reference
See gastown architecture.md lines 487-491 for the full ephemeral storage design.

## Related
- gt-3x0z.2: Configure bd for ephemeral molecule bonding (closed - blocked on this)


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 15: all healthy


Merge: furiosa-1767141944421

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


Evaluate pending async gates

Evaluate pending async gates.

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

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

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

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

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

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

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


Move disk 1: C → A

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


Move disk 2: B → A

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 37: all quiet


Digest: mol-deacon-patrol

Patrol 3: All healthy, routine


Add nudge channels for real-time fan-out messaging

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

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

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

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

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

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

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

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


gt status: check daemon health first, attempt restart

If daemon not running, attempt to start it. If start fails, show warning but don't block status display. Currently falls back to slow direct mode silently.


Digest: mol-deacon-patrol

Patrol cycle 53: All healthy


Move disk 3: B → C

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


Digest: mol-deacon-patrol

Patrol complete


Merge: toast-mjw7062w

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


gt-gastown-polecat-testcat4

gt-gastown-polecat-testcat4

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


Merge: gt-yd98

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


Move disk 1: C → A

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 16


Digest: mol-deacon-patrol

Patrol 16: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol 42: All healthy, 6 agents pinged, no incidents


Digest: mol-deacon-patrol

Patrol cycle 36: All healthy, no incidents


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

Cycle 7


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Merge: gt-rixa

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


mol-deacon-patrol


Create StartupNudge function with seance metadata

## Location
internal/session/startup.go (new file) or internal/agent/startup.go

## Interface
```go
type StartupNudgeConfig struct {
    Recipient   string  // gastown/crew/gus, deacon, gastown/witness
    Sender      string  // mayor, deacon, self (for handoff)
    Topic       string  // mol-id, "cold-start", "handoff", "assigned"
    MolID       string  // Optional: specific molecule being worked
}

func StartupNudge(t *tmux.Tmux, session string, cfg StartupNudgeConfig) error
```

## Nudge Format
```
[GAS TOWN] gastown/crew/gus ← deacon • 2025-12-30T15:42 • assigned:gt-abc12
```

This becomes the session title in Claude Codes `/resume` picker.

## Implementation
1. Build the formatted message from config
2. Call t.NudgeSession(session, message) for reliable delivery
3. Return error if session doesnt exist or nudge fails

## Key Insight
The message content doesnt trigger GUPP - CLAUDE.md and hooks handle that.
The metadata makes sessions identifiable in `/resume`.


gt-gastown-polecat-organic

gt-gastown-polecat-organic

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: null
role_bead: gt-polecat-role
cleanup_status: has_stash
active_mr: gt-scdyn
notification_level: null


Digest: mol-deacon-patrol

Patrol 15: Routine


Test message

Test body


gt mol status: role detection fails from polecat directory

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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 90: All healthy


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

Patrol 11: 8 sessions OK


Digest: mol-deacon-patrol

Patrol 7: Quick cycle, all quiet


Merge: morsov-1767074381346

attached_args: Code review this merge request

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


Witness: bond mol-polecat-arm when discovering polecat

When witness discovers a polecat during healthCheck(), bond a mol-polecat-arm child.

## Changes to witness/manager.go

In healthCheck() when iterating polecats:
1. Check if arm already exists for this polecat (arm-{name})
2. If not, call: gt mol bond mol-polecat-arm --parent=$PATROL_ID --ref=arm-{name} --var polecat_name={name} --var rig={rig}
3. Track arm issue ID in handoff state

## Arm Lifecycle

- Created when polecat first seen
- Updated as inspection happens (nudges, state changes)
- Closed when polecat cleaned up

## Deduplication

Check handoffState.WorkerStates[name].ArmID before creating.
Needs: gt-59zd.3


Move disk 2: C → B

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


Convert MR queue to wisp storage

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

## Design (Simplified)

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

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

### Code Changes

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 5: stable


Move disk 1: B → C

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


gt mail send to self: Auto-detect from cwd for handoff mail

When sending mail to yourself (common for handoffs), gt mail send from an agent directory should auto-detect both sender and recipient. Example: gt mail send -s 'HANDOFF' -m '...' from mayor/rig should send to mayor/.


Digest: mol-deacon-patrol

Patrol 41: All healthy, 3 rigs, 3W/3R pinged, no incidents


Digest: mol-deacon-patrol

Cycle 184: All systems nominal


Digest: mol-deacon-patrol

Patrol 8: all clear, handing off for fresh context


Add molecules.jsonl as separate catalog file for template molecules


Digest: mol-deacon-patrol

Patrol 4: Core healthy, no changes


Digest: mol-deacon-patrol

Patrol 10: Halfway check, all healthy


Digest: mol-deacon-patrol

Patrol 5: All agents healthy, routine


Digest: mol-deacon-patrol

Patrol cycle 16: All 6 agents healthy


mol-deacon-patrol


Machine registry: Store and manage machine configs

Registry for managing remote machines in federation.

## Data Model

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

## Interface

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

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

## Storage

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

## Connection Factory

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


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.


Digest: mol-deacon-patrol

Patrol 2: All clear


gt spawn: Enter key needs debounce delay after paste

## Problem

When spawning polecats via `gt spawn`, instructions are pasted into tmux but workers often sit idle at prompt because the Enter key arrives before the paste is fully processed.

## Observed Behavior

- Instructions pasted via tmux send-keys
- Enter key sent immediately after
- Worker session shows prompt with no input (paste not submitted)
- Requires manual intervention to nudge workers

## Expected Behavior

- Paste completes fully
- Enter key submits the pasted instructions
- Worker begins executing immediately

## Root Cause

Likely a race condition between paste buffer processing and keypress handling. Need either:
1. Debounce delay before sending Enter
2. Longer delay (Tmax) to ensure paste completes
3. Alternative submission mechanism

## Impact

- Swarm of 10 workers had multiple stalls at startup
- Required manual tmux send-keys to unstick them
- Defeats purpose of automated spawning

## References

- Observed during Mad Max swarm (Dec 18, 2025)
- Affects gt spawn command in internal/cmd/spawn.go


Digest: mol-deacon-patrol

Patrol complete: routine cycle


Digest: mol-deacon-patrol

Patrol complete: beads witness+refinery came online, both rigs healthy


Merge: valkyrie-mjtn0kda

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 17: Mayor OK, 11 sessions


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 78: All healthy


Digest: mol-deacon-patrol

Patrol 17: Quiet


Digest: mol-deacon-patrol

Patrol 7: All healthy


Per-epic config overrides: custom merge settings

Allow per-epic merge configuration overrides.

Epic can specify merge_config in its description:
  merge_config:
    run_tests: true
    test_command: 'go test -race ./...'
    on_conflict: assign_back

When processing MRs for an epic:
1. Load rig-level merge_queue config
2. Check if epic has merge_config
3. Merge epic config over rig config
4. Use merged config for processing

Use cases:
- Risky refactors: more thorough testing
- Urgent fixes: skip some checks
- Experimental work: different test suite

Reference: docs/merge-queue-design.md#per-epic-overrides


Digest: mol-deacon-patrol

Patrol 14: clear


Fix TestHasPolecat test failure


Unified Beads Namespace - prefix-based routing across town

Vision: Run bd commands from anywhere in town, with prefix-based routing.

Current state:
- Town beads at ~/gt/.beads/ with hq-* prefix
- Rig beads at ~/gt/<rig>/mayor/rig/.beads/ with rig-specific prefixes (gt-, bd-, wy-, etc.)
- Redirects allow agents to use specific beads location
- No automatic prefix-based routing

Desired state:
- bd show gt-xyz from ANYWHERE in town → routes to gastown beads
- bd show hq-abc from ANYWHERE in town → routes to town beads
- bd show wy-def from ANYWHERE in town → routes to wyvern beads
- Prefix determines beads location automatically

Implementation options:
1. Registry file at town root mapping prefix → beads location
2. bd wrapper/hook that reads prefix and routes
3. Unified store with namespace prefixes (more invasive)

Related work:
- gt-0pdhj: Remove hardcoded gastown dependencies
- Template fixes needed for deacon, witness, refinery CLAUDE.md


Move disk 1: C → A

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


Merge: nux-1767083432904

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


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 10: healthy


Move disk 3: C → A

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


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


Witness swarm landing protocol

Witness responsibilities for swarm landing cleanup.

## Trigger

Witness receives "swarm-landed" mail from Refinery containing:
- swarm_id
- merge_commit
- action: "cleanup"

## Landing Protocol

### Phase 1: Preflight
Verify all polecat sessions stopped:
- Check tmux for active sessions
- Kill any remaining sessions
- Wait for graceful shutdown

### Phase 2: Git Audit
For each polecat in swarm:
- Check for uncommitted changes
- Check for unpushed commits
- Check for stashes
- Classify as "beads-only" (safe) or "code at risk"
- If code at risk: escalate, abort landing

### Phase 3: Cleanup
For each polecat:
- Clear state entry (mark as idle)
- Delete inbox (or archive)
- Delete worker branch (local + remote)

### Phase 4: Final Report
- Update swarm state to "landed"
- File landing report bead
- Mail Mayor with summary

## Code at Risk Handling

If git audit finds code at risk:
1. Abort cleanup for that polecat
2. Mail Mayor with details
3. Human intervention required

## Reference

PGT: swarm/landing.py (6-phase protocol), swarm/git_audit.py


Digest: mol-deacon-patrol

Patrol 85: All healthy


Digest: mol-deacon-patrol

Patrol cycle 9: routine, healthy


Move disk 1: B → C

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


Merge: gt-jhr85

branch: polecat/slit-mjxlyyte
target: main
source_issue: gt-jhr85
rig: gastown
agent_bead: gt-mayor


Digest: mol-deacon-patrol

Patrol 35: all quiet


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


bd list --parent: filter by parent issue

Add --parent flag to bd list to filter issues by parent.

Example:
```bash
bd list --parent=gt-h5n --status=open
```

Would show all open children of gt-h5n.

Useful for:
- Checking epic progress
- Finding swarmable work within an epic
- Molecule step listing


gt doctor: Check and fix beads routing configuration

## Summary

`gt doctor` should check that all rigs with beads have proper routing entries
in `~/gt/.beads/routes.jsonl`, and offer to fix any missing entries.

## Checks to Add

### Check: routes.jsonl exists
- Verify `~/gt/.beads/routes.jsonl` exists
- If missing, create with entries for all known rigs

### Check: All rigs have routing entries
For each rig in town:
1. Find the rig's beads prefix (from config.yaml or sample issue)
2. Check if routes.jsonl has an entry for that prefix
3. If missing, report and offer to add

### Check: Routes point to valid locations
For each route in routes.jsonl:
1. Verify the path exists and has a .beads directory
2. Verify the .beads directory has a beads.db
3. If invalid, report and offer to remove

## Fix Actions

- `--fix` should automatically add missing routes
- `--fix` should remove invalid routes (or prompt)
- Should handle redirect files when validating paths

## Example Output

```
Checking beads routing...
  [!] Rig 'myproject' (prefix: mp-) has no routing entry
      Run: gt doctor --fix to add routing

Routes health:
  [OK] gt- -> gastown/mayor/rig
  [OK] bd- -> beads/mayor/rig
  [!]  mp- -> myproject/mayor/rig (MISSING)
```


ensure-beads-witness

Start the beads rig Witness.

## Action
```bash
gt witness start beads
```

## Verify
1. Session exists: `tmux has-session -t beads-witness 2>/dev/null`
2. Not stalled: `gt peek beads/witness` does NOT show "> Try" prompt
3. Heartbeat fresh: Last patrol cycle < 5 min ago

## OnStall
```bash
gt nudge beads/witness "Start patrol."
sleep 30
# Re-verify
```

## OnFail
Log error. Rig polecats will be unmonitored until Witness recovers.


Digest: mol-deacon-patrol

Patrol cycle 38: All healthy, no incidents


Activity stream infrastructure check

Verify activity stream infrastructure exists and is sufficient for MQ/witness events.

Check:
- Does gt feed already have event infrastructure?
- Can we emit custom events from Go code?
- What format do events need?

If infrastructure exists, close this. If not, implement minimal event emission.


Move disk 2: C → B

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


Merge polecat/rictus: Add molecule phase lifecycle diagram

Branch: polecat/rictus

Adds molecule phase lifecycle diagram to architecture.md showing Proto → Mol/Wisp → Digest state transitions with the 'states of matter' metaphor. Also documents when to use Mol (durable) vs Wisp (ephemeral).

Closes: gt-c6zs


Digest: mol-deacon-patrol

Patrol 18: Nominal


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol cycle 80: All healthy


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 211: All nominal


Digest: mol-deacon-patrol

Patrol 16: healthy


Digest: mol-deacon-patrol

Patrol #3: All healthy, 1 dog idle. No messages.


Digest: mol-deacon-patrol

Patrol cycle 17: All healthy.


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol cycle 11: routine


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.


Digest: mol-deacon-patrol

Patrol 20: all healthy, doctor pass, handoff cycle


Move disk 4: C → B

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


Move disk 3: A → B

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


Move disk 3: A → B

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


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol cycle 1: All 6 agents healthy, no issues, inbox clean


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Deacon: Hierarchical health-check orchestrator

Replace daemon heartbeats with Deacon - an AI agent that keeps Gas Town running.

## Core Concept

The Deacon is a **Claude agent** (not just a Go process) that:
- Lives at town root in gt-deacon session
- Has its own mailbox (deacon/ identity in town beads)
- Is poked by a minimal Go daemon every ~60s (if idle)
- Monitors Mayor and Witnesses proactively
- Handles lifecycle requests (restart/cycle) from Mayor, Witnesses, AND Crew

## Architecture

```
Minimal Go Daemon (just watches Deacon)
         |
         v
     Deacon (Claude agent)
         |
    +----+----+
    v         v
  Mayor    Witnesses --> Polecats (Witness-managed)
    |         |
    +----+----+
         |
      Crew (lifecycle only, not monitored)
```

## Deacon Responsibilities

**Proactive monitoring:**
- Mayor health (tmux session, keepalive freshness)
- Witness health (tmux sessions, keepalive freshness)

**Reactive lifecycle:**
- Process restart/cycle requests from Mayor, Witnesses, Crew
- Kill session, create new, prime, verify startup

**Escalation:**
- Mail human (configurable) if issues can't be resolved

## Key Files

- ~/gt/DEACON.md - Role context
- ~/gt/deacon/ - State directory
  - heartbeat.json - Written each wake cycle (daemon checks this)
  - state.json - Health tracking, last scan results
- ~/gt/.beads/ - Town beads with deacon/ mail identity

## Wake Cycle

1. Write heartbeat (prevents daemon from poking)
2. Check mail (lifecycle requests)
3. Quick health scan (Mayor, Witnesses)
4. Process lifecycle requests
5. Remediate unhealthy agents
6. Update state

## Session Patterns

- Deacon: gt-deacon
- Mayor: gt-mayor
- Witness: gt-<rig>-witness
- Crew: gt-<rig>-<name> (e.g., gt-gastown-max)

## Relation to Policy Beads

Future: Deacon behavior configurable via policy beads (gt-3zw).
Initial implementation uses sensible defaults.


Session test no rig


Document Boot vs Deacon lifecycle and fix design confusion

## Problem

The Boot/Deacon relationship is confusing and possibly over-engineered:

### Current Design
```
Daemon (Go process, 3-min heartbeat)
    │
    └─► Boot (ephemeral triage dog)
            │
            └─► Decides: start/wake/nudge/interrupt Deacon?
                    │
                    └─► Deacon (persistent patrol agent)
                            │
                            └─► health-scan: restart witness/refinery
```

### Questions

1. **Why two agents?** Boot exists to avoid waking Deacon unnecessarily in idle towns. But is this complexity worth it?

2. **Session ownership**: Boot should run in `gt-deacon-boot`, Deacon in `gt-deacon`. But current behavior is confused.

3. **Handoff**: When Boot starts Deacon, what happens to Boot? Does it exit? Hand off?

4. **Fallback**: Daemon has `checkDeaconHeartbeat()` as belt-and-suspenders. When does this fire vs Boot?

## Options

### Option A: Keep Boot/Deacon separation (fix implementation)
- Boot is ephemeral, spawns fresh each heartbeat
- Boot runs in `gt-deacon-boot`, exits after triage
- Deacon runs in `gt-deacon`, persistent patrol
- Clear session boundaries, clear lifecycle

### Option B: Merge Boot into Deacon
- Single `gt-deacon` session
- Deacon handles its own 'should I be awake?' logic
- Simpler, fewer moving parts
- Trade-off: Deacon consumes context even when idle

### Option C: Replace with simpler watchdog
- Daemon directly monitors witness/refinery
- No Boot, no Deacon AI agents for health checks
- Just Go code: if session dead, restart it
- AI agents only for complex decisions (escalations)

## Recommendation

Option A with clear documentation. The separation has merit for cost control in idle towns. But the implementation needs fixing.


Digest: mol-deacon-patrol

Patrol 128: All healthy


Digest: mol-deacon-patrol

Patrol 5: Routine


Digest: mol-deacon-patrol

Patrol 10


142 instances of error suppression with _ = pattern

Code has 142 instances of '_ = ' error suppression in non-test code.
Examples:
- internal/polecat/manager.go: _ = pool.Load() - ignores state loading
- internal/daemon/notification.go: _ = os.WriteFile() - ignores file write
- internal/mail/router.go: _ = r.notifyRecipient() - notification ignored

These create silent failures and hard-to-debug issues.

Options:
1. Document intentional suppressions with comments
2. Handle errors properly where appropriate
3. At minimum, log suppressed errors at debug level


Move disk 1: C → A

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


Move disk 1: A → B

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


Move disk 2: C → B

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


Move disk 4: B → A

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


mol-deacon-patrol


Selection operators: glob, filter, children

Implement selection operators for targeting:
- step(id) - specific step
- glob(pattern) - pattern match (*.implement)
- filter(predicate) - status/output predicates
- children(step), descendants(step) - tree traversal

Used by advice, expansion, and aspects for targeting.


Move disk 1: A → B

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


Refinery-Witness communication protocol

Define mail protocol between Refinery and Witness:

FROM Witness → Refinery:
- 'Polecat ready': polecat X completed work, ready for merge
- 'Rework complete': polecat Y finished requested rework

FROM Refinery → Witness:
- 'Merge success': polecat X merged, can be cleaned up
- 'Merge failed': polecat X needs rework on <reason>
- 'Rework request': please have a polecat rebase X on current main

Implement as structured mail with parseable format.


Digest: mol-deacon-patrol

Patrol 8: All green


Deacon patrol wisps should use town beads, not gastown rig beads

## Problem

The deacon is a town-level role but stores patrol wisps in gastown/mayor/rig/.beads/ (see internal/cmd/prime.go:691). This fails for users who don't have the gastown rig installed.

## Correct Architecture

Deacon -> ~/gt/.beads-wisp/ (town-level, no rig dependency)

Town-level ephemeral work (deacon patrols) should use town wisp storage, just like rig-level ephemeral work (witness/refinery patrols) uses rig wisp storage.

## Implementation Tasks

### 1. Town Setup (gt install / gt town init)

- Create ~/gt/.beads-wisp/ directory during town initialization
- Initialize as git repo (for local commits, not synced)
- Add config.yaml with wisp: true
- Ensure .beads-wisp/ is gitignored at town level

Files:
- internal/cmd/install.go (or equivalent town init)
- internal/town/manager.go (if exists)

### 2. Rig Setup (gt rig init)

Already creates <rig>/.beads-wisp/ - verify this is working:
- internal/rig/manager.go:375 (beadsDir := filepath.Join(rigPath, ".beads-wisp"))
- internal/rig/manager.go:394 (ensureGitignoreEntry)

### 3. Deacon Code Fixes

Update deacon to use town wisp storage:
- internal/cmd/prime.go:691 - change rigBeadsDir to townWispDir
- internal/cmd/sling.go - route deacon wisps to town level
- internal/daemon/daemon.go - any deacon-specific wisp handling

### 4. gt doctor Checks

Add/update doctor checks for wisp directories:
- internal/doctor/wisp_check.go - already checks rig wisps
- Add TownWispCheck to verify ~/gt/.beads-wisp/ exists
- Add TownWispGitCheck to verify it is a valid git repo
- Update existing checks to handle both town and rig levels

Files:
- internal/doctor/wisp_check.go (extend for town level)
- internal/doctor/checks.go (register new checks)

### 5. Documentation

- docs/beads-data-plane.md - already updated with three-tier architecture
- Verify wisp-architecture.md reflects town-level wisps

## Testing

1. Fresh gt install should create ~/gt/.beads-wisp/
2. gt doctor should pass with no rig installed
3. Deacon patrol should work without gastown rig
4. gt sling patrol deacon/ --wisp should route to town wisps


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 46: All healthy


Merge: slit-mjw3n5iw

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


Merge: rictus-mjtlq9xg

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


Digest: mol-deacon-patrol

Patrol 20: All healthy, handoff threshold


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.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-refinery-patrol

Patrol: Queue empty. Updated workflow docs with MR verification requirements. Closed 5 unverifiable orphaned MRs.


Add logging for silently ignored errors

attached_args: Add logging for silently ignored errors

Add logging for silently ignored errors.

## Problem
Many places use `_ =` pattern to ignore errors without any logging, making debugging difficult.

## Files to modify
- internal/cmd/start.go (lines 167, 322-323, 429, 747-753, 886-888)
- internal/cmd/polecat.go (search for `_ =`)
- internal/session/manager.go (lines 140-154)
- internal/refinery/manager.go (line 399)
- internal/keepalive/keepalive.go (document as intentional)

## Implementation options

### Option A: Add comments explaining safety
```go
_ = m.saveState(ref) // Non-fatal: state will be recreated on next run
```

### Option B: Log warnings (preferred for important operations)
```go
if err := m.saveState(ref); err != nil {
    log.Printf("warning: failed to save state: %v", err)
}
```

## Guidelines
- Use logging for: state saves, config writes, cleanup operations
- Use comments for: truly benign operations (e.g., closing already closed file)
- keepalive is intentionally best-effort - add package-level comment

## Acceptance criteria
- [ ] All `_ =` in start.go have comment OR logging
- [ ] All `_ =` in session/manager.go have comment OR logging
- [ ] refinery/manager.go:399 has logging
- [ ] keepalive package has doc comment explaining best-effort design
- [ ] grep '`_ =`' shows all have justification
- [ ] go build ./... passes


bd list: Add type aliases (mr→merge-request)

The --type flag requires exact matches. Add aliases for convenience:

- mr → merge-request
- feat → feature
- mol → molecule

**Context**: Refinery cleanup missed 6 open MRs because `--type=mr` returned nothing while `--type=merge-request` found them.

**Implementation**: In the type filter parsing, normalize aliases before matching.


Plugin/molecule catalog integration design

Two currently independent systems:
1. Disk-based plugins (~~/gt/plugins/) - Deacon patrol extensions
2. Molecule catalog (protos in beads) - bd pour/wisp/bond

Investigate integration points:
- User-contributed molecules bonded to catalog
- Dynamic molecule attachment during execution (e.g., 'attach security sniffer because we noticed condition X')
- How plugins could contribute protos
- How protos could trigger plugins

Not blocking launch. Future design investigation.


Move disk 2: B → A

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


mol-deacon-patrol


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 20: OK - Handoff threshold reached


Move disk 2: A → C

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


Merge: morsov-dogs

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


Merge: valkyrie-1767074338488

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


Cross-rig agent identity detection

## Problem

Several gt commands fail to correctly detect agent identity when operating
across rigs. Running commands from beads/crew/dave shows gastown/crew/joe
identity, or fails to resolve paths.

## Root Cause

Agent identity detection in gt commands assumes single-rig context. Cross-rig
crew paths like `beads/crew/dave` are not handled correctly.

## Scope

- gt hook - shows wrong identity from other rig crew dir
- gt peek - fails to resolve cross-rig crew paths
- gt sling - "." target not resolved to current agent

## Fix Strategy

Centralize agent identity detection to handle:
1. Current rig detection from cwd
2. Cross-rig path parsing (rig/crew/name vs rig/polecats/name)
3. "." resolution to current agent identity


Digest: mol-deacon-patrol

Patrol 6: all healthy


Move disk 1: B → C

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