Execute registered plugins

Execute registered plugins.

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

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

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

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

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

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


Check for more work

More branches to process?

**Entry paths:**
- Normal: After successful merge-push
- Conflict-skip: After process-branch created conflict-resolution task

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

**Track for this cycle:**
- branches_merged: count and names of successfully merged branches
- branches_conflict: count and names of branches skipped due to conflicts
- conflict_tasks: IDs of conflict-resolution tasks created

This tracking feeds into generate-summary for the patrol digest.


End-of-cycle inbox hygiene

Verify inbox hygiene before ending patrol cycle.

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

Inbox should contain ONLY:
- Unprocessed MERGE_READY messages (will process next cycle)
- Active work items

**Step 2: Archive any stale messages**

Look for messages that were processed but not archived:
- PATROL: Wake up that was acknowledged → archive
- HELP/Blocked that was handled → archive
- MERGE_READY where merge completed but archive was missed → archive

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

**Step 3: Check for orphaned MR beads**

Look for open MR beads with no corresponding branch:
```bash
bd list --type=merge-request --status=open
```

For each open MR bead:
1. Check if branch exists: `git ls-remote origin refs/heads/<branch>`
2. If branch gone, verify work is on main: `git log origin/main --oneline | grep "<source_issue>"`
3. If work on main → close MR with reason "Merged (verified on main)"
4. If work NOT on main → investigate before closing:
   - Check source_issue validity (should be gt-xxxxx, not branch name)
   - Search reflog/dangling commits if possible
   - If unverifiable, close with reason "Unverifiable - no audit trail"
   - File bead if this indicates lost work

**NEVER close an MR bead without verifying the work landed or is unrecoverable.**

**Goal**: Inbox should have ≤3 active messages at end of cycle.
Keep only: pending MRs in queue.


Burn and respawn or loop

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

Decision point at end of patrol cycle:

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

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

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

This enables infinite patrol duration via context-aware respawning.


Clean dead sessions

Clean dead sessions and orphaned state.

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

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

# Fix everything
gt doctor --fix
```

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

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


Find abandoned work

Find abandoned work.

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

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

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


End-of-cycle inbox hygiene


Check Witness and Refinery health

Check Witness and Refinery health for each rig.

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

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

**Signals to assess:**

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

**Tracking unresponsive cycles:**

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

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

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

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

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

Reset unresponsive_cycles to 0 when component responds normally.


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Mechanical rebase

Pick next branch from queue. Attempt mechanical rebase on current main.

**Step 1: Checkout and attempt rebase**
```bash
git checkout -b temp origin/<polecat-branch>
git rebase origin/main
```

**Step 2: Check rebase result**

The rebase exits with:
- Exit code 0: Success - proceed to run-tests
- Exit code 1 (conflicts): Conflict detected - proceed to Step 3

To detect conflict state after rebase fails:
```bash
# Check if we're in a conflicted rebase state
ls .git/rebase-merge 2>/dev/null && echo "CONFLICT_STATE"
```

**Step 3: Handle conflicts (if any)**

If rebase SUCCEEDED (exit code 0):
- Skip to run-tests step (continue normal merge flow)

If rebase FAILED with conflicts:

1. **Abort the rebase** (DO NOT leave repo in conflicted state):
```bash
git rebase --abort
```

2. **Record conflict metadata**:
```bash
# Capture main SHA for reference
MAIN_SHA=$(git rev-parse origin/main)
BRANCH_SHA=$(git rev-parse origin/<polecat-branch>)
```

3. **Create conflict-resolution task**:
```bash
bd create --type=task --priority=1 --title="Resolve merge conflicts: <original-issue-title>" --description="## Conflict Resolution Required

Original MR: <mr-bead-id>
Branch: <polecat-branch>
Original Issue: <issue-id>
Conflict with main at: ${MAIN_SHA}
Branch SHA: ${BRANCH_SHA}

## Instructions
1. Clone/checkout the branch
2. Rebase on current main: git rebase origin/main
3. Resolve conflicts
4. Force push: git push -f origin <branch>
5. Close this task when done

The MR will be re-queued for processing after conflicts are resolved."
```

4. **Skip this MR** (do NOT delete branch or close MR bead):
- Leave branch intact for conflict resolution
- Leave MR bead open (will be re-processed after resolution)
- Continue to loop-check for next branch

**CRITICAL**: Never delete a branch that has conflicts. The branch contains
the original work and must be preserved for conflict resolution.

Track: rebase result (success/conflict), conflict task ID if created.


Mechanical rebase


mol-witness-patrol

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

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

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

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

## The Christmas Ornament Shape

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


Scan merge queue

Check the beads merge queue - this is the SOURCE OF TRUTH for pending merges.

```bash
git fetch --prune origin
gt mq list <rig>
```

The beads MQ tracks all pending merge requests. Do NOT rely on `git branch -r | grep polecat`
as branches may exist without MR beads, or MR beads may exist for already-merged work.

If queue empty, skip to context-check step.

For each MR in the queue, verify the branch still exists:
```bash
git branch -r | grep <branch>
```

If branch doesn't exist for a queued MR:
- Close the MR bead: `bd close <mr-id> --reason "Branch no longer exists"`
- Remove from processing queue

Track verified MR list for this cycle.


Handle callbacks from agents

Handle callbacks from agents.

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

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

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


gt-witness-gastown

gt-witness-gastown

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

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


Witness Role Definition

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

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

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

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

## Core Responsibilities

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

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

## Propulsion Principle

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

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

## Nudge Protocol

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

## Pre-Kill Verification

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

## Commands

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


Digest: mol-deacon-patrol

Patrol cycle 80: All healthy


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 116: All healthy


Use atomic write pattern for state files

attached_args: Atomic write pattern for state files

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

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

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

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

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


Session ended: gt-gastown-crew-gus

Bulk cleanup of stale session-ended events (gt-8tc1v)


Digest: mol-deacon-patrol

Patrol 4 complete. All healthy.


Digest: mol-deacon-patrol

Patrol 2: All healthy, no issues


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

## The Insight

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

## Current State

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

Missing: **Convoy status panel**

## Proposed Enhancement

Add a convoy panel showing:

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

## Components

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

## Integration Options

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

## Why This Matters

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 25: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol cycle 4: All quiet.


Digest: mol-deacon-patrol

Patrol cycle 2: All healthy, idle town


gt hook: Cannot resolve HQ beads from polecat context

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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 95: All healthy


Merge: rictus-mjw3nj1a

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


Extract magic values to named constants

Magic strings and numbers throughout codebase:

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

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

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

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


gt done: MR bead not created

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

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

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


Deacon convoy patrol steps

New Deacon patrol steps for convoy orchestration.

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 5: routine


Layered context onboarding pattern

Pattern from handoff discussion:

## Pattern: Layered Context Onboarding

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

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

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

## Recommendation

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


Digest: mol-deacon-patrol

Patrol 7: routine


Session ended: gt-gastown-crew-joe


Digest: mol-deacon-patrol

Patrol cycle 23: All healthy, no incidents


Add live polling and updates

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


[Security] Path traversal risk in crew name handling

In crew/manager.go:39-41, crewDir() uses filepath.Join(m.rig.Path, "crew", name) where 'name' is user input. If name contains '..', it could escape the crew directory. Should validate crew names similar to rig name validation in rig/manager.go:215-219.

Fixed: added validateCrewName() to reject path traversal and invalid characters


Patrol formulas: Inconsistent variable placeholder syntax

The patrol formulas use inconsistent syntax for variable placeholders:

## Inconsistency

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

## Expected

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

## Fix

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


Digest: mol-deacon-patrol

Patrol cycle 20: All 6 agents healthy, handoff threshold


Merge: slit-1767087730371

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


Digest: mol-deacon-patrol

Patrol cycle 2: All 6 agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol 52: All healthy


Update polecat template: Use gt done --exit

## Task

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

## Changes

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

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

2. Remove "WAIT" step - no more waiting

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

## Dependencies

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

Updated polecat template to use gt done --exit


Digest: mol-deacon-patrol

Patrol 13: Routine


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy


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

## Summary

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

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

## Impact

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

## Root Cause

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

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

## Child Issues

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

## Success Criteria

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

All child issues completed: boot session fix, zombie session handling, binary age detection, status reconciliation, ensure semantics, and documentation


Molecule converge: iterate until AI says done

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

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

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

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

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

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


Code review formula: First complete formula implementation

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

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

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

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


Digest: mol-deacon-patrol

Patrol 151 complete


Digest: mol-deacon-patrol

Patrol 203: Routine checks, all systems nominal


Digest: mol-deacon-patrol

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


Session ended: gt-gastown-crew-joe


Digest: mol-deacon-patrol

Patrol cycle 44: All healthy


Witness sends HEALTH_OK mail to mayor on every deacon ping

## Problem

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

## Current behavior

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

This happens every patrol cycle (~30s).

## Expected behavior

Witnesses should NOT send mail responses to routine health checks.

## Fix

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

Updated witness templates to not mail on HEALTH_CHECK nudges


Merge: gt-cehl8

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


Session ended: gt-gastown-crew-max


Session ended: gt-gastown-crew-jack


Remove markdown molecule heresy from ~/gt/molecules/

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

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


Digest: mol-deacon-patrol

Patrol 8: quiet


Review PR #51: fix: Use hq prefix for agent beads to match town beads database

Review PR #51. Check hq prefix usage is consistent. Approve with gh pr review --approve if good.

PR reviewed - requested changes: hardcoded gt- references need updating in prime.go, daemon/lifecycle.go, doctor/agent_beads_check.go, polecat/manager.go, crew_add.go


Digest: mol-deacon-patrol

Cycle 294: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol 18: Routine


Day 1.5: Create role beads from CLAUDE.md content

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

Each role bead contains priming instructions and default_molecule.

Parent: gt-d0jqp


Cross-rig worktree support for crew

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

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

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

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

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

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

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


Implement gt worktree create command

Create worktree in target rig for cross-rig work.

Usage: gt worktree <rig>

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

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

Implemented gt worktree command for cross-rig work


Implement gt worktree list command

List all worktrees owned by current crew member.

Usage: gt worktree list

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

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

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


Implement gt worktree remove command

Remove a cross-rig worktree.

Usage: gt worktree remove <rig>

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

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

Already implemented and merged in d72cb6b9


Document cross-rig worktree pattern

Add documentation for crew cross-rig work pattern.

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

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

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


Merge: dag-mjw70jg8

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


[Git] Missing context.Context support for cancellation

The internal/git package lacks context.Context support throughout. Long-running operations like Clone, Fetch, and Push cannot be cancelled. All run() and public methods should accept context and use exec.CommandContext(). Affected files: internal/git/git.go (all methods).


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

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


ZFC #7: Make message age filtering configurable

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

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

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

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


Digest: mol-deacon-patrol

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


announce: shared bulletin board

Announcement channel with shared single-copy storage.

## Deliverables

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

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

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

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


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

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

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

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

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

TESTS: Add TestExpandQueue in router_test.go

Depends on isQueueAddress being added first.

Added expandQueue() with ErrUnknownQueue and tests


Digest: mol-deacon-patrol

Cycle 199: Nominal


Merge: coma-mjwjczb0

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


Session ended: gt-gastown-crew-joe


Mayor notification levels (Do Not Disturb mode)

## Problem

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

## Use Cases

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

## Design Considerations

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

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

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

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

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

Implemented gt dnd and gt notify commands with nudge integration


Fix PR→MR terminology in internal workflow docs

Polecats create MRs (merge requests), not PRs. Fix these references:

- docs/reference.md:326 - 'review PRs' → 'review MRs'
- docs/INSTALLING.md:187 - 'PR review' → 'MR review'

PRs are external GitHub concept. MRs are internal Gas Town workflow.

Fixed PR→MR in reference.md and INSTALLING.md


Digest: mol-deacon-patrol

Patrol #6: All quiet, 1 dog idle.


Agent scanner utility for filesystem

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

## Deliverables

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

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

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

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

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


Session ended: gt-gastown-crew-jack


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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 152: All healthy


Add molecule to update local go binary on push to main

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


Merge: morsov-1767106016839

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


Witness should nuke polecats after completion, not leave idle

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

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

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

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

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

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

Implemented auto-nuke in witness handlers (e3933d7)


Digest: mol-deacon-patrol

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


Session ended: gt-gastown-glory


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy. Routine check.


Fix namepool Save() to use write lock

attached_args: Fix namepool Save() mutex for thread safety

Fix incorrect mutex usage in namepool Save() method.

## Files to modify
- internal/polecat/namepool.go

## Problem (lines 179-194)
Save() uses RLock() but performs file I/O:
```go
func (p *NamePool) Save() error {
    p.mu.RLock()  // WRONG: file write needs write lock
    defer p.mu.RUnlock()
    // ... file operations ...
}
```

## Fix
Change to write lock:
```go
func (p *NamePool) Save() error {
    p.mu.Lock()
    defer p.mu.Unlock()
    // ... file operations ...
}
```

## Acceptance criteria
- [ ] Save() uses Lock() instead of RLock()
- [ ] go test -race ./internal/polecat/... passes
- [ ] Existing namepool tests still pass


Digest: mol-deacon-patrol

Patrol #18: Quick cycle, all quiet.


Session ended: gt-gastown-crew-max

Bulk cleanup of stale session-ended events (gt-8tc1v)


Add self-check context guidance to role CLAUDE.md files

Each role's CLAUDE.md needs guidance for context self-management:

- After each patrol cycle, self-assess context pressure
- Heuristics: feeling compressed, lots of tool calls, long session
- If triggered: initiate handoff before continuing

Roles to update:
- Mayor (~/gt/CLAUDE.md)
- Witness template
- Refinery template
- Polecat template
- Crew template
- Deacon template

This is the 'inversion of control' - agents decide when to cycle, not external monitoring.


Merge: dementus-1767140140908

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


Digest: mol-deacon-patrol

Cycle 9: quiet


Session ended: gt-gastown-crew-gus


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 7: All clear


Digest: mol-deacon-patrol

Patrol 1: All 3 rigs healthy, 17 sessions running, no issues


Add --fart as easter egg alias for bd mol bond

Add a hidden alias for the bond command:

```bash
bd mol fart mol-polecat-work --wisp
# equivalent to:
bd mol bond mol-polecat-work --wisp
```

## Context
The fart joke: instantiating a proto can produce either:
- A Mol (solid/substantial output)
- A Wisp (gas/ephemeral output)

## Implementation
- Add 'fart' as an alias in the mol subcommand
- No documentation needed (easter egg)
- Maybe a fun message: 'Bonding molecule...' or similar

Low priority, just for fun.


Remove keepalive file infrastructure

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

**Current state:**
- keepalive.TouchTownActivity() writes to activity.json on every gt/bd command
- Daemon reads activity.json to calculate exponential backoff

**New model (feed-based wake):**
- Patrol agents subscribe to `bd activity --follow`
- Any beads mutation wakes agents within ~500ms
- Daemon heartbeat is recovery-focused, not wake-focused
- Read-only commands don't need to wake the town

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

**Whitelist consideration:**
Some read-only commands might need to wake (TBD):
- gt mail inbox (checking for work?)
- None identified yet

See docs/patrol-system-design.md for full feed-based wake design.


Magic Numbers: Timing constants in session/manager.go

The session/manager.go file has several magic numbers for timing:

- Line 207: `time.Sleep(8 * time.Second)` - Claude startup wait
- Line 224: `time.Sleep(2 * time.Second)` - Beacon processing wait
- Line 259: `time.Sleep(100 * time.Millisecond)` - Graceful shutdown wait
- Line 429-432: Debounce calculation `200 + (len(message)/1024)*100` with cap at 1500

These should be named constants for clarity:

```go
const (
    ClaudeStartupDelay     = 8 * time.Second
    BeaconProcessingDelay  = 2 * time.Second
    GracefulShutdownDelay  = 100 * time.Millisecond
    DebounceBaseDelay      = 200 * time.Millisecond
    DebouncePerKB          = 100 * time.Millisecond
    DebounceMaxDelay       = 1500 * time.Millisecond
)
```

Files:
- internal/session/manager.go:207, 224, 259, 429-432

Severity: low


Digest: mol-deacon-patrol

Patrol 2: Quick pass, all healthy


Session ended: gt-gastown-crew-max


Add Boot shutdown to gt shutdown

gt shutdown should stop Boot if running. Currently Boot is only spawned by daemon but never explicitly stopped.

Added Boot shutdown to gt down command. Boot now stopped between Mayor and Deacon.


Digest: mol-deacon-patrol

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

## Infrastructure Assessment: SUFFICIENT with minor gaps

### Current Event Infrastructure

1. **townlog** (internal/townlog/logger.go)
   - CAN emit events from Go code
   - Event types: spawn, wake, nudge, handoff, done, crash, kill
   - Output: ~/gt/logs/town.log (text format)
   - Convenience functions: LogSpawn, LogWake, LogNudge, LogDone, etc.
   - Used by: session.go, stop.go, log.go

2. **bd activity** (beads CLI)
   - Shows issue/molecule state changes
   - Events from beads database mutations
   - This IS what gt feed TUI displays
   - To emit events: create/update beads issues

3. **JSONLSource** (internal/tui/feed/events.go:214-290)
   - Ready to read JSONL events from file
   - Format: {timestamp, type, actor, target, message, rig, role}
   - Currently unused (no producer writes to this)

4. **gt feed TUI** (internal/cmd/feed.go)
   - Wraps bd activity in interactive TUI
   - Agent tree + event stream panels
   - Can consume from BdActivitySource or JSONLSource

### Answers to Task Questions

Q: Does gt feed already have event infrastructure?
A: YES - reads from bd activity (beads mutations) and has JSONLSource ready

Q: Can we emit custom events from Go code?
A: YES - townlog.Logger.Log() emits events, but they go to text log not activity stream

Q: What format do events need?
A: For gt feed: JSONL with {timestamp, type, actor, target, message, rig, role}

### Gap Analysis

For MQ/Witness events to appear in gt feed, dependent tasks need to either:

**Option A** (Recommended): Extend townlog to dual-write
- Add new EventTypes (patrol_started, merge_started, etc.)
- Write to JSONL file in addition to text log
- Update gt feed to also consume from this file
- ~50-100 lines of changes

**Option B**: Use beads issues
- Create operational beads for patrol cycles, merge requests
- Their state changes appear automatically in bd activity
- More invasive, creates many ephemeral beads

### Files for Dependent Tasks

- internal/townlog/logger.go - Add event types, dual-write
- internal/tui/feed/events.go - JSONLSource already exists
- internal/cmd/feed.go - Add secondary source (if needed)


Digest: mol-deacon-patrol

Patrol 132: All healthy


Digest: mol-deacon-patrol

Patrol 61: All agents healthy, 2 convoys in progress, 1 idle dog, no incidents


Merge: morsov-mjwcd60m

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


Phase 1: Add hq- prefix agent bead ID helpers

## Goal

Add helper functions for town-level agent bead IDs using `hq-` prefix.

## Changes

### internal/beads/agent_ids.go (new file)

```go
// Town-level agent IDs (hq- prefix, stored in town beads)
func MayorBeadIDTown() string { return "hq-mayor" }
func DeaconBeadIDTown() string { return "hq-deacon" }
func DogBeadIDTown(name string) string { return fmt.Sprintf("hq-dog-%s", name) }

// Role bead IDs (hq- prefix, stored in town beads)
func RoleBeadID(role string) string { return fmt.Sprintf("hq-%s-role", role) }

// Rig-level agent IDs (rig prefix, stored in rig beads)
// Keep existing: WitnessBeadID(), RefineryBeadID(), PolecatBeadID()
```

### Deprecation

Mark old functions as deprecated:
- `MayorBeadID()` → use `MayorBeadIDTown()`
- `DeaconBeadID()` → use `DeaconBeadIDTown()`

## Testing

- Unit tests for new ID functions
- Verify IDs match expected format


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol #6: All nominal


Digest: mol-deacon-patrol

Patrol cycle 58: All healthy


Protocol: Type System for Formulas

Protocols define interfaces that formulas implement - a type system for workflows.

## Concept

```toml
# reviewable.protocol
[protocol]
name = "Reviewable"

[requires]
steps = ["review"]  # Must have a step tagged "review"
outputs = ["review_decision"]  # Must produce this

[guarantees]
"review completes before any deploy step"
```

Formulas declare: `implements = ["Reviewable", "Deployable"]`

System verifies compliance statically.

## Use Cases

1. Ensure all deploy formulas have review steps
2. Define compliance requirements as protocols
3. Enable formula discovery: "Give me all Deployable formulas"
4. Validate formula composition compatibility

## Properties

- Static verification (before execution)
- Composable (protocol can extend protocol)
- Documentation value (self-describing contracts)

## Open Questions

1. Protocol syntax - embedded in formula or separate files?
2. Verification timing - cook time? load time?
3. Protocol versioning - how do protocols evolve?
4. Inheritance - can protocols extend other protocols?

## Related

- docs/formula_evolution.md - "Formula Schemas" section
- gt-8tmz - molecule algebra


Session ended: gt-gastown-crew-jack


Polecat spawn: Environment vars not exported to shell

Polecat sessions set tmux environment but don't export to shell before Claude

In session/manager.go Start():
  _ = m.tmux.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)
  _ = m.tmux.SetEnvironment(sessionID, "GT_POLECAT", polecat)
  ...
  command = "claude --dangerously-skip-permissions"

Compare to crew_lifecycle.go which exports inline:
  claudeCmd := fmt.Sprintf("export GT_ROLE=crew GT_RIG=%s GT_CREW=%s && claude ...")

Result: Claude can't detect polecat identity, falls back to 'mayor', shows wrong hook.

Fix: Export GT_ROLE=polecat GT_RIG=X GT_POLECAT=Y inline before running Claude.


Session ended: gt-gastown-crew-joe


Digest: mol-deacon-patrol

Patrol 217: All nominal


Implement sendToQueue() for queue message delivery

Add queue message delivery to internal/mail/router.go.

SEMANTICS:
- Queue messages are stored in a shared location, NOT individual inboxes
- Location: {townRoot}/.beads/ with special metadata

MESSAGE METADATA:
Add to message struct or use existing fields:
- queue_name: which queue this belongs to
- claimed_by: empty until claimed
- claimed_at: timestamp when claimed

IMPLEMENTATION:
1. Add sendToQueue(msg *Message) error
2. Validate sender is eligible (optional, or allow anyone to post)
3. Create message bead with queue_name in metadata
4. Message To field should be 'queue:{name}'

FILE: internal/mail/router.go
PATTERN: Follow sendToList() at line 567 but create ONE copy, not fan-out

Do not implement claim/release yet - just delivery.


Session ended: gt-gastown-fury


Merge: furiosa-mjw1p03l

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

Stale MR - branch has no new commits or doesn't exist


Clarify formula semantics: read-only reference, not instantiated

## Problem

An agent (likely the Deacon) read the `mol-deacon-patrol.formula.toml` file and created beads from its steps. This is wrong - formulas are reference documents describing a workflow, not templates to be instantiated into trackable work.

## What Happened

1. Formula exists at `.beads/formulas/mol-deacon-patrol.formula.toml`
2. Deacon (or predecessor agent) created an epic + 9 task beads matching the formula steps
3. These showed up in `bd ready` (separate bug filed)

## Correct Model

| Artifact | Purpose | Created How |
|----------|---------|-------------|
| Formula (.toml) | Reference doc describing workflow | Manual/design |
| Wisp | Ephemeral execution context | `bd wisp create` (no child beads) |
| Proto | Template for pour | `bd cook` from formula |

**Formulas should NOT create beads.** They're documentation. When the Deacon runs a patrol, it follows the formula instructions directly - it doesn't need beads for each step.

## Fix Needed

1. Update Deacon template to clarify: "Follow the formula instructions. Do not create beads from formula steps."
2. Audit what command created the beads - was it `bd wisp create` expanding the formula? If so, that command shouldn't create child beads.
3. Consider renaming formulas to `.md` if they're just prose instructions.

(Moved from hq-ufiy)

Invalid premise. Formulas ARE meant to create beads when poured/wisped - that's the core MEOW design. The actual bug was an agent manually creating issues from formula steps instead of using bd wisp/pour commands.


Digest: mol-deacon-patrol

Patrol 22: Rotated 10MB daemon log. All agents healthy. 3 polecats idle. No callbacks. 3 convoys in progress.


Session ended: gt-gastown-crew-gus


Session ended: gt-gastown-warboy


gt unsling uses wrong beads dir for remote agents

**Bug**: `gt unsling <target-agent>` searches the local beads directory instead of the target agent's rig beads.

**Reproduction**:
```bash
# From gastown/crew/max:
gt status  # Shows joe has hook gt-7aw1m
gt unsling gastown/crew/joe -f  # Says 'No work hooked'
```

**Root cause**: `internal/cmd/unsling.go:88` calls `findLocalBeadsDir()` which uses cwd.

**Fix**: When `targetAgent` is set, resolve the target's rig path and use `beads.New(rigPath)` instead of local beads dir.

**Reference**: `gt status` does this correctly in `discoverRigHooks()` using `beads.New(r.Path)`.


Digest: mol-deacon-patrol

Patrol cycle 10: All quiet.


Digest: mol-deacon-patrol

Patrol #17: Health pinged all refineries.


Make documentation convoy-first

Update all gt/gastown documentation to be convoy-first:

1. Reference docs: Show convoy create before sling in examples
2. CLAUDE.md / mayor priming: Convoy is the standard workflow
3. User docs: convoy list as primary dashboard view
4. Remove/update any 'just sling' examples that skip convoy

Convoy is the primary unit of work tracking. All slings should be part of a convoy.

Updated README.md, reference.md, understanding-gas-town.md, mayor.md.tmpl, and crew.md.tmpl to be convoy-first


Digest: mol-deacon-patrol

Patrol 4: All clear


Session ended: gt-gastown-crew-max


Digest: mol-deacon-patrol

Patrol 5: All healthy.


Session ended: gt-gastown-crew-jack


Day 2.5: Test daemon pokes based on agent state

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

Parent: gt-d0jqp


Digest: mol-deacon-patrol

Patrol 2: 3 rigs healthy, no incidents


Digest: mol-deacon-patrol

Patrol 12: all clear


Digest: mol-deacon-patrol

Patrol cycle 47: All healthy


Session ended: gt-gastown-ace


Digest: mol-deacon-patrol

Patrol 13: quiet


Digest: mol-deacon-patrol

Patrol 10: Routine. All 3 rigs healthy. 12 polecats. 1 MQ pending.


Session ended: gt-gastown-nightrider


Fix convoy refresh scheduling causing duplicates

model.go:191-197 schedules both fetchConvoys() and convoyRefreshTick() on every update, potentially causing duplicate refreshes. The tick should only be scheduled once initially.


Merge: furiosa-1767141944421

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


Session ended: gt-gastown-dinki


Digest: mol-deacon-patrol

Patrol 114: All healthy


Crew CLAUDE.md overwritten by polecat template

The crew worker CLAUDE.md files (crew/max, crew/joe, crew/jack) have been overwritten with the polecat-CLAUDE.md template content.

**Expected**: Crew workers should have mayor-like context (they share the rig repo, work on main branch, plan work)

**Actual**: Crew CLAUDE.md says 'Polecat ace' and includes polecat-specific instructions (don't push to main, wait for Witness to kill session, etc.)

**Impact**:
- Crew workers getting wrong identity context
- Ready Front planning guidance in gotchas section was lost
- Crew workers told not to push to main (but they should)

**Root cause**: Likely gt polecat template deployment hit crew directories

**Fix needed**:
- Restore crew CLAUDE.md template (or create one if missing)
- Ensure template deployment only targets polecats/ directories
- Add Ready Front planning section to crew template

Fixed crew CLAUDE.md files:
1. Regenerated with correct crew template (not polecat template)
2. Added CLAUDE.md to .gitignore to prevent cross-clone contamination
3. Each crew member now has their own CLAUDE.md with correct identity


gt mail archive: accept multiple message IDs

Currently `gt mail archive` only accepts one message ID. Should accept variadic args like:

```
gt mail archive hq-t9j0u hq-jdxlb hq-cfl5j hq-osed0
```

This matches the pattern of `bd close <id1> <id2> ...` which accepts multiple IDs.

Implementation: Update the cobra command to accept multiple args and loop over them.

Updated gt mail archive to accept variadic message IDs


gt polecat add should spawn with --dangerously-skip-permissions

When adding polecats via gt polecat add, the subsequent Claude session needs --dangerously-skip-permissions flag to run autonomously.

Currently:
- gt polecat add creates worktree
- tmux new-session spawns 'claude' without flags
- Polecat gets stuck at permission prompts

Needed:
- gt polecat add (or gt sling) should spawn with --dangerously-skip-permissions
- Or store a config in polecat worktree indicating autonomous mode

This is critical for swarm automation - polecats can't self-approve permissions.


Refinery emits activity events

Refinery emits events to activity stream for MQ lifecycle:

Events to emit:
- merge_started: When refinery begins processing an MR
- merged: When MR successfully merged to main
- merge_failed: When merge fails (conflict, tests, etc.)
- merge_skipped: When MR skipped (already merged, etc.)

Events should include: MR ID, worker, branch, timestamp, reason (for failures)

This replaces stats tracking in .runtime/refinery.json

Implemented all MQ lifecycle events in refinery: merge_started, merged, merge_failed, merge_skipped


Digest: mol-deacon-patrol

Patrol cycle 15: All 6 agents healthy


gt peek should support cross-rig crew paths like beads/crew/dave

## Problem

`gt peek beads/crew/dave` fails with "session not found" even when the session exists.

The command expects `<rig/polecat>` format but crew workers in other rigs use
`<rig>/crew/<name>` paths.

## Current behavior

```bash
gt peek beads/crew/dave
# Error: session not found
```

## Expected behavior

```bash
gt peek beads/crew/dave
# Should peek at the beads rig crew member dave
```

## Fix

The peek command should:
1. Parse paths with `/crew/` as crew workers, not polecats
2. Resolve cross-rig crew sessions correctly
3. Handle both `rig/polecat` and `rig/crew/name` formats

Fixed: gt peek now checks for crew/ prefix in polecatName and uses crewSessionName() to generate correct session name


Digest: mol-deacon-patrol

Patrol 10: Quiet


Digest: mol-deacon-patrol

Patrol 47: All healthy


Digest: mol-deacon-patrol

Patrol 109: All healthy


Digest: mol-deacon-patrol

Patrol cycle 14


Session ended: gt-gastown-crew-jack


Digest: mol-deacon-patrol

Patrol 10: all healthy


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy


Digest: mol-deacon-patrol

Patrol 84: All healthy


Digest: mol-deacon-patrol

Patrol 143 complete: All agents healthy


Rig management commands for town startup/shutdown

All 5 child commands implemented and verified: gt rig start/stop/status, gt crew start/stop


Merge: nightrider-mk02roxa

branch: polecat/nightrider-mk02roxa
target: main
source_issue: nightrider-mk02roxa
rig: gastown
agent_bead: gt-gastown-polecat-nightrider
retry_count: 0
last_conflict_sha: null
conflict_task_id: null

Already merged at 44e9f81d (duplicate of max's commit)


Digest: mol-deacon-patrol

Patrol 20: all healthy


Digest: mol-deacon-patrol

Patrol cycle 8


Digest: mol-deacon-patrol

Patrol cycle 15


Digest: mol-deacon-patrol

Patrol 65: Routine


Digest: mol-deacon-patrol

Patrol cycle 12: All healthy.


Digest: mol-deacon-patrol

Patrol cycle 13: All healthy.


Digest: mol-deacon-patrol

Patrol #14


Merge: furiosa-mjxap5fz

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


Remove schedule/phase terminology from code

Temporal/schedule language in identifiers is an anti-pattern.

## Found Issues

### beads repo
- `examples/multi-phase-development/` directory
  - Rename to `examples/dependency-sequenced-work/` or similar

### gastown repo
- `internal/cmd/start.go` lines 178-195
  - Uses "Phase 1:", "Phase 2:", etc. in printf output
  - Change to descriptive names: "Interrupting agents...", "Requesting handoff...", etc.

- `internal/swarm/landing.go` lines ~50-70
  - Comments say "// Phase 1: Stop all polecat sessions"
  - Change to "// Step: Stop all polecat sessions" or just remove phase labels

## Why This Matters

Phase/version language in names:
1. Implies a fixed schedule (antithetical to dependency-driven work)
2. Creates confusion with molecule "phases" (solid/liquid/gas)
3. Encourages temporal thinking that leads to backwards dependencies

## What To Keep

- Molecule phase terminology (pour/wisp/proto) - this is chemistry, not scheduling
- Version fields inside files (version: 1) - this is semantic versioning


Session ended: gt-gastown-crew-joe


Digest: mol-deacon-patrol

Patrol 4: all healthy


Plugin: Plan-to-Epic converter

## Purpose

Help users create beads epics from various planning inputs.

## Inputs
- Markdown task lists
- GitHub issues
- Linear/Jira exports
- Free-form descriptions
- Existing beads epics

## Output
- Beads epic with properly structured children
- Dependencies set for wave ordering
- Priorities assigned
- Ready for `gt spawn --epic <id>`

## Implementation Options

### Option A: CLI Tool
```bash
gt plan import --from github --repo owner/repo --label batch-candidate
gt plan import --from markdown tasks.md
gt plan structure <epic-id>  # analyze and add dependencies
```

### Option B: Plugin Agent
A plugin at `<rig>/plugins/plan-oracle/` that:
- Receives planning requests via mail
- Analyzes scope and requirements
- Creates structured beads epic
- Sets dependencies based on analysis

### Option C: Interactive Mode
```bash
gt plan create
# Walks through questions, creates epic interactively
```

## Axiom

As stated: 'The Planning phase should end in the creation of a workable Beads plan.'

This plugin bridges the gap between human planning and machine-executable work.

## Priority

P2 - Nice to have for MVP. Manual epic creation works for now.

## Note

No "swarm IDs" - output is just a beads epic with children. Workers process it independently.


Session ended: gt-gastown-chumbucket


Merge: gt-veswi

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

Merged to main at 1805d5b0 (toast-mjxm0mmo spawn alias)


Digest: mol-deacon-patrol

Patrol cycle 3: All agents healthy, no callbacks, no orphans


Clean up stale issue references in comments

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

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

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

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

## Tombstoned epic references (epic superseded):

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

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

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


Digest: mol-deacon-patrol

Patrol 7: Routine


Digest: mol-deacon-patrol

Patrol 6: quiet


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy


Session ended: gt-gastown-crew-max


Digest: mol-deacon-patrol

Patrol 10: All healthy.


Day 4.2: Implement gt polecat nuke command

Add gt polecat nuke <name> command:
- Kill the Claude session
- Delete the worktree
- Delete the branch
- Remove agent bead
- Full cleanup post-merge

Parent: gt-4a2qt


Digest: mol-deacon-patrol

Patrol 118: All healthy


Session ended: gt-gastown-crew-jack


Merge: gt-ldk8

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


Merge: morsov-mjxpeg1a

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


Digest: mol-deacon-patrol

Patrol cycle 10: All healthy.


Day 4.3: Polecat self-manages session handoffs

**REVISED**: Session cadence is polecat-managed, not mechanically forced by Witness.

Polecats decide when to cycle their own sessions:
1. Work through molecule steps sequentially in one session
2. Close each step as completed (bd close, for activity feed)
3. Self-initiate handoff when: context filling, logical chunk done, or stuck
4. Use: gt handoff -s 'Continuing molecule' -m '<context notes>'

If polecat forgets to handoff:
- Compaction will force it eventually
- Work continues from hook (molecule state preserved)
- No work is lost

Witness role changes:
- Does NOT force recycle between steps
- DOES monitor for stuck (long idle on same step)
- DOES use recycle for stuck recovery (not routine step transitions)
- DOES verify clean state before nuke

This is more ZFC-compliant: polecats report their own needs.


Show actor only when not redundant with bead ID

Currently the feed shows actor even when obvious:

  [10:17:37] ✓ gt-s6r44 completed · ... @gastown/crew/max

The actor should be omitted when:
- The bead ID already identifies the agent (gt-crew-gastown-joe)
- The action makes the actor obvious (created by = actor)

Format should be:
  {timestamp} {symbol} {issue-id} {action} · {title} [@actor if not obvious]

Part of epic gt-u7dxq

Implemented actor omission logic in view.go for redundant cases: bead ID identifies agent, or create events


Review PR #98: improve rig name validation error message


gt status is slow - needs performance optimization

Optimized from 13s to <1s: --no-daemon for bd calls, bulk agent/hook/session pre-fetching, parallel rig processing, --fast flag for skipping mail


Digest: mol-deacon-patrol

Patrol 77: Routine


Digest: mol-deacon-patrol

Patrol 16 complete


Digest: mol-deacon-patrol

Patrol cycle 2: all monitors healthy, 1 dog idle, no incidents


Review PR #91: extract town session helpers for DRY shutdown


Digest: mol-deacon-patrol

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


Remove deprecated SessionBeacon function

## Context

The StartupNudge migration (gt-7pp3l) replaced all SessionBeacon usages with StartupNudge.

## Current State

`SessionBeacon()` in `internal/session/names.go` is now dead code:
- Function definition exists at line 52
- No callers remain in the codebase

## Action

Remove the deprecated function:
```go
// SessionBeacon generates an identity beacon message for Claude Code sessions.
// ...
func SessionBeacon(address, molID string) string {
    // ...
}
```

## Risk

Low - function is unused. Verify with:
```bash
grep -r 'SessionBeacon' --include='*.go' . | grep -v 'names.go'
```

## Related

- gt-7pp3l: Migrate startup paths from SessionBeacon to StartupNudge
- gt-85whr: Agent Startup Consolidation epic (closed)

Removed SessionBeacon and documented StartupNudge format in reference.md


mol-outpost-assign: Intelligent work routing to outposts

The federation design shows outposts.yaml with a static policy section. Simple preference ordering is fine as config, but intelligent work routing should be a molecule.

Current static approach:
```yaml
policy:
  default_preference: [local, gce-burst, cloudrun-burst]
```

Cases requiring cognition:
- "This is a long-running research task, route to VM not CloudRun"
- "This touches sensitive code, keep local"
- "These 5 issues are related, batch them to same outpost"
- "CloudRun cost is high today, prefer local even if slower"

## Molecule: outpost-assign
Intelligent work-to-outpost routing.

## Step: classify-work
Analyze the issue/work item:
- Expected duration (quick fix vs multi-hour)
- Resource requirements
- Sensitivity/security tier
- Related work (same epic?)

## Step: check-capacity
Query outpost status:
- Current load on each
- Cost accrued today
- Health status

## Step: select-outpost
Choose optimal outpost based on:
- Work classification
- Capacity/cost
- Policy constraints
Needs: classify-work, check-capacity

## Step: emit-assignment
Record decision in beads for audit.
Needs: select-outpost

## Notes
- This molecule is invoked by Mayor/Witness when spawning
- Simple cases can short-circuit to static policy
- Full analysis only for ambiguous cases


Digest: mol-deacon-patrol

Patrol cycle 50: All healthy


#channel resolution for real-time broadcast

Wire tmux scanner into nudge system for #channel addresses.

## Deliverables

1. Parse #channel syntax in nudge:
   - #rig/gastown → nudge all running gastown agents
   - #town → nudge all running agents
   - #witnesses → nudge all running witnesses

2. Broadcast logic:
   - Resolve #channel to running sessions
   - Nudge each session
   - Ephemeral (no storage)

## Dependencies
- Tmux session scanner (gt-???)

## Acceptance
- #rig/gastown nudges all running gastown agents
- Ephemeral, no message storage
- Graceful handling of no-sessions


Digest: mol-deacon-patrol

Patrol cycle 35: All healthy, no incidents


Session ended: gt-gastown-vuvalini


Refactor patrol context functions to reduce duplication

In prime.go, three patrol context functions are nearly identical (~100 lines each):
- outputDeaconPatrolContext() - L797-940
- outputWitnessPatrolContext() - L942-1106
- outputRefineryPatrolContext() - L1108-1272

They all:
1. Check for existing patrol molecule
2. Auto-spawn if none exists
3. Display patrol work loop instructions

**Suggested refactor**:
Extract common logic into a helper:
```go
func outputPatrolContext(ctx RoleContext, patrolName string, assignee string) {
    // shared logic
}
```

Then each role-specific function just calls the helper with appropriate parameters.


Session ended: gt-gastown-crew-jack


Rig identity bead schema and creation

dispatched_by: mayor

Define and implement rig identity beads (type=rig).

Schema:
- id: gt-rig-<name>
- type: rig
- name: <rig-name>
- repo: <git-url>
- prefix: <beads-prefix>
- labels: (for operational state)

Implementation:
- Add type=rig to beads schema
- Create rig bead during 'gt rig add'
- Query with 'bd list --type=rig'

This is foundational - other work depends on it.


gt polecat nuke: Refuse if unpushed commits or open MR

Agent prompts can be ignored. Code cannot.

`gt polecat nuke` should REFUSE to delete a polecat if:
1. Worktree has unpushed commits
2. Polecat has open MR beads
3. Polecat has work on hook

This is enforcement in code, not just instructions. The command itself should be safe.

Use existing `computeCleanupStatus()` in done.go as reference.

Implemented safety checks for gt polecat nuke: unpushed commits, open MR beads, work on hook


Session ended: gt-gastown-crew-gus


Digest: mol-deacon-patrol

Patrol #10: Milestone - all agents healthy. 1 dog idle. Gastown MQ 1 pending.


BUG: gt swarm create uses non-existent --mol-type flag on bd update

gt swarm create fails because it tries to use --mol-type=swarm with bd update, but that flag doesn't exist.

## Location
internal/cmd/swarm.go lines 241, 252, 661-662

## Problem
- `bd list --mol-type=swarm` works (flag exists)
- `bd create --mol-type=swarm` works (flag exists)
- `bd update --mol-type=swarm` FAILS (flag doesn't exist)

## Fix Options
1. Add --mol-type flag to bd update command (beads change)
2. Use labels instead of mol-type for swarm marking
3. Only set mol-type during bd create, not update

## Reported By
gus during gt-d46 swarm attempt

Fixed: removed --mol-type from bd update call, only set during create


Digest: mol-deacon-patrol

Patrol cycle 2: All 6 agents healthy, 3 polecats active (furiosa, nux, obsidian), beads refinery has 1 pending


Daemon sends heartbeat to Mayor instead of Deacon


Merge: gt-caih

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


Day 4.4: Witness calls nuke after MERGED signal

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

Parent: gt-4a2qt


BranchPushedToRemote: Fetch remote tracking ref if not present locally

BranchPushedToRemote uses RemoteBranchExists (git ls-remote) to check if remote branch exists, but then compares with local origin/branch ref which may not exist if we just pushed.

## Repro
1. Push a new branch: git push -u origin branch-name
2. The local tracking ref origin/branch-name may not exist yet
3. BranchPushedToRemote errors: 'unknown revision origin/branch..HEAD'

## Fix
In BranchPushedToRemote, after confirming remote branch exists, run git fetch to ensure we have the local ref before comparing.

## Discovered
While implementing gt-bca67 (require pushed branch before MR creation)

Added git fetch before rev-list comparison to ensure local tracking ref exists


Merge: nux-mk3ex9vy

branch: polecat/nux-mk3ex9vy
target: main
source_issue: nux-mk3ex9vy
rig: gastown
agent_bead: gt-gastown-polecat-nux
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Digest: mol-deacon-patrol

Patrol 73: Routine


Session ended: gt-gastown-crew-max


Merge: keeper-mjxpe1ku

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


Merge: furiosa-1767138824776

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


Standardize agent bead naming: prefix-rig-role-name

## The Problem

Agent bead IDs use INCONSISTENT naming patterns:

| Current (WRONG) | Should Be (prefix-rig-role-name) |
|-----------------|----------------------------------|
| gt-witness-gastown | gt-gastown-witness |
| gt-refinery-gastown | gt-gastown-refinery |
| gt-crew-gastown-max | gt-gastown-crew-max |
| gt-polecat-gastown-Toast | gt-gastown-polecat-Toast |

Town-level agents (no rig) are OK:
- gt-mayor ✓
- gt-deacon ✓

## The Convention

```
prefix-rig-role-name

Where:
- prefix: always 'gt'
- rig: rig name (absent for town-level agents)
- role: witness|refinery|crew|polecat|mayor|deacon
- name: agent name (absent for singleton roles like witness/refinery)
```

Examples:
- `gt-gastown-witness` (rig=gastown, role=witness, no name)
- `gt-gastown-crew-max` (rig=gastown, role=crew, name=max)
- `gt-beads-polecat-Toast` (rig=beads, role=polecat, name=Toast)
- `gt-mayor` (no rig, role=mayor, no name)

## Files to Update

### Agent bead ID generation
- internal/cmd/status.go (lines 316-335)
- internal/daemon/lifecycle.go (lines 546-579)
- internal/cmd/crew_add.go
- internal/polecat/manager.go
- internal/rig/manager.go
- internal/doctor/agent_beads_check.go
- internal/cmd/prime.go
- internal/session/names.go (session names vs bead IDs)

### Commands to verify
- gt status - displays agent beads
- gt doctor - creates missing agent beads
- gt rig add - creates witness/refinery beads
- gt crew add - creates crew beads
- gt sling - routes by agent ID
- gt mol status - looks up agent by ID

## Migration

1. Update all ID generation code
2. Create new agent beads with correct IDs
3. Migrate hook/role slots to new beads
4. Update any mail addresses
5. Delete old incorrectly-named beads

## Also from this session

Role bead slot cleanup was done - CreateAgentBead now calls bd slot set.
But legacy description parsing still exists in daemon/lifecycle.go.

## Reference
- ~/gt/docs/agent-as-bead.md
- Session 2025-12-29: Fixed role bead patterns (gt-crew-role etc)

Completed: standardized agent bead naming to prefix-rig-role-name


Merge: rictus-1767073382273

attached_args: Code review this merge request

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

REJECTED: Fix already on main (81b250ee). Branch is stale - merging would revert 10e79789 (swarm worker tracking fix) and other important commits. No action needed.


Digest: mol-refinery-patrol

Patrol: Closed 21 merge requests that were already merged to main. All tests passed. Queue now empty.


Digest: mol-deacon-patrol

Patrol 16: routine


Digest: mol-deacon-patrol

Cycle 20: Final health check - all healthy


Merge: goose-mk02qu5g

branch: polecat/goose-mk02qu5g
target: main
source_issue: goose-mk02qu5g
rig: gastown
agent_bead: gt-gastown-polecat-goose
retry_count: 0
last_conflict_sha: null
conflict_task_id: null

Already merged (duplicate of toecutter's commit)


Digest: mol-deacon-patrol

Patrol 20: All healthy, handoff threshold


Add GUPP to non-polecat roles (Mayor, Deacon, Witness, Refinery)

GUPP (propulsion nudge after beacon) is only implemented for polecats in session/manager.go.

Other roles have different startup flows but could benefit from similar auto-propulsion:
- Mayor: mayor/manager.go or wherever mayor session starts
- Deacon: deacon startup flow
- Witness: witness startup flow
- Refinery: refinery startup flow

Each role may need role-specific propulsion message.

(Refiled from bd-8hea)

Added role-specific PropulsionNudge to Mayor, Deacon, Witness, and Refinery startup flows


ZFC: Auto-close convoys when tracked issues close via bd close

When bd close closes an issue, check if this issue was tracked by any convoy. If all tracked issues in a convoy are now closed, auto-close the convoy.

## Background
PR #236 attempted to fix stale convoys by calling gt convoy check in the refinery merge handler. This is a ZFC violation - it couples the refinery to convoy semantics and uses the wrong trigger point.

## Proper ZFC approach
The closure event should propagate at the source:
1. bd close closes an issue
2. Check if this issue is tracked by any open convoy
3. For each convoy tracking this issue, check if all tracked issues are now closed
4. If so, auto-close the convoy

## Implementation notes
- Add convoy-check logic to bd close command
- The deacon patrol step check-convoy-completion remains as backup

## Related
- PR #236 (closed - ZFC violation)
- Deacon patrol step: check-convoy-completion