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)


Move disk 2: B → A

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


Move disk 4: A → C

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


Digest: mol-deacon-patrol

Patrol complete: town quiet, all healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Hardcoded 'gastown' rig in Deacon patrol context

In prime.go, the Deacon patrol context hardcodes 'gastown' as the rig name.

**Location**: prime.go L807

```go
rigBeadsDir := filepath.Join(ctx.TownRoot, "gastown", "mayor", "rig")
```

This breaks if:
- The rig is renamed
- The town has multiple rigs
- The Deacon is deployed to a different rig

**Fix options**:
1. Detect rig from context (ctx.Rig)
2. Use town-level beads for Deacon patrol
3. Pass rig name as parameter

The Deacon is a town-level role, so option 2 may be most appropriate.


Test gate for verification


Digest: mol-deacon-patrol

Patrol 12: Routine


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 5: all clear


Schematic: Domain-Level Formula Composition

A Schematic is a coordinated set of formulas defining an entire workflow domain.

## Concept

Like an orchestra score to instrument parts - says how formulas fit together.

```toml
# shiny-engineering.schematic
[schematic]
name = "The Shiny Way"
description = "Full engineering workflow from issue to production"

[formulas]
planning = "@gastown/shiny"
development = "@gastown/polecat-work"
review = "@gastown/review"
release = "@gastown/release"

[flow]
default = "planning >> development >> review >> release"

[constraints]
all_code_reviewed = true
tests_before_deploy = true
```

## Relationship to Other Concepts

- **Schematic** (workflow dimension) = composition of Formulas
- **Campaign** (work dimension) = composition of Epics
- Schematic compiles to Campaign, like Formula compiles to Molecule

## Use Cases

1. Define "The Shiny Way" for a team/org
2. Encode compliance requirements
3. Standardize workflows across projects
4. Enable workflow reuse and sharing

## Open Questions

1. File format - TOML? YAML? Extend formula syntax?
2. Validation - how to verify schematic consistency?
3. Overrides - can project override org schematic?

## Related

- docs/formula_evolution.md
- gt-8tmz - molecule algebra


Add witness plugin hook support

Implement plugin directories for witness patrol.

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

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


Merge: valkyrie-mjw71b7u

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


Digest: mol-deacon-patrol

Patrol 18: 3 rigs healthy


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 1: No callbacks, no gates, all agents healthy, cleaned 2 orphan processes + 1 stale lock


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 135: All healthy


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


Move disk 3: C → A

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


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.


Merge: gt-odvf

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


Digest: mol-deacon-patrol

Patrol 16: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 13: Quick cycle, all quiet


Digest: mol-deacon-patrol

Patrol 12: routine


Digest: mol-deacon-patrol

Patrol 3: All healthy, routine


Resolve external dependencies

Resolve external dependencies across rigs.

When an issue in one rig closes, any dependencies in other rigs should be notified. This enables cross-rig coordination without tight coupling.

**Step 1: Check recent closures from feed**
```bash
gt feed --since 10m --plain | grep "✓"
# Look for recently closed issues
```

**Step 2: For each closed issue, check cross-rig dependents**
```bash
bd show <closed-issue>
# Look at 'blocks' field - these are issues that were waiting on this one
# If any blocked issue is in a different rig/prefix, it may now be unblocked
```

**Step 3: Update blocked status**
For blocked issues in other rigs, the closure should automatically unblock them (beads handles this). But verify:
```bash
bd blocked
# Should no longer show the previously-blocked issue if dependency is met
```

**Cross-rig scenarios:**
- bd-xxx closes → gt-yyy that depended on it is unblocked
- External issue closes → internal convoy step can proceed
- Rig A issue closes → Rig B issue waiting on it proceeds

No manual intervention needed if dependencies are properly tracked - this step just validates the propagation occurred.


Digest: mol-deacon-patrol

Patrol 20: Final before handoff, all healthy


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 20: Final patrol, all healthy, handoff


Digest: mol-deacon-patrol

Patrol 9: Quiet


Session cycling: Auto-spawn successor when context full

Enable automatic session succession for crew workers.

When a crew worker's context fills up (>80%), they should:
1. Write handoff mail to themselves
2. Signal session end
3. System auto-spawns successor session
4. Successor reads handoff, finds attached work, auto-continues

This completes the autonomous overnight work pattern from gt-9g82.

Depends on:
- Detecting context fullness (Claude Code API?)
- Session spawning mechanism (tmux/daemon)
- Handoff protocol already implemented


Move disk 2: A → C

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


Move disk 3: A → B

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


Digest: mol-deacon-patrol

Patrol #12


Digest: mol-deacon-patrol

Cycle 189: Nominal


Enhance gt status with role hierarchy view

Show identity and role hierarchy in gt status:

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

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 10: nominal


inbox-check

Process witness mail: lifecycle requests, help requests.

```bash
gt mail inbox
```

Handle by message type:
- LIFECYCLE/Shutdown: Queue for pre-kill verification
- Blocked/Help: Assess if resolvable or escalate
- HANDOFF: Load predecessor state
- Work complete: Verify issue closed, proceed to pre-kill

Record any pending actions for later steps.
Mark messages as processed when complete.


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


mol-sync-workspace: Add explicit gt prime / bd prime in assess-state


gt doctor: Check settings.json hook consistency across town

## Problem

Settings.json files in different locations can become out of sync, causing session_id
passthrough to fail for some roles but not others. This happened when:
- Town root was updated to use session-start.sh
- Rig root still had old 'gt prime' direct call
- Mayor/rig had mixed state

## Locations to Check

1. `~/gt/.claude/settings.json` (town root - Mayor uses this)
2. `~/gt/<rig>/.claude/settings.json` (rig root - polecats/crew use this)
3. `~/gt/<rig>/mayor/rig/.claude/settings.json` (mayor/rig - source of truth)

## Check Logic

For SessionStart and PreCompact hooks, verify all use `session-start.sh`:
- Must contain `bash ~/.claude/hooks/session-start.sh` (or full path)
- Warn if any use bare `gt prime` without session-start.sh wrapper

## Output

```
gt doctor
...
session-hooks: ✓ All settings.json files use session-start.sh
# or
session-hooks: ✗ ~/gt/gastown/.claude/settings.json uses bare 'gt prime' (missing session_id passthrough)
```

## Fix Suggestion

When inconsistency found, suggest:
```
Hint: Update SessionStart/PreCompact hooks to use 'bash ~/.claude/hooks/session-start.sh'
      This enables session_id passthrough for gt seance discovery.
```

## Related

- session-start.sh extracts session_id from Claude Code stdin JSON
- gt prime outputs [GAS TOWN] metadata line for seance
- gt seance discovers sessions from .events.jsonl


Digest: mol-deacon-patrol

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


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


Rotate logs and prune state

Maintain daemon logs and state files.

**Step 1: Check daemon.log size**
```bash
# Get log file size
ls -la ~/.beads/daemon*.log 2>/dev/null || ls -la ~/gt/.beads/daemon*.log 2>/dev/null
```

If daemon.log exceeds 10MB:
```bash
# Rotate with date suffix and gzip
LOGFILE="$HOME/gt/.beads/daemon.log"
if [ -f "$LOGFILE" ] && [ $(stat -f%z "$LOGFILE" 2>/dev/null || stat -c%s "$LOGFILE") -gt 10485760 ]; then
    DATE=$(date +%Y-%m-%dT%H-%M-%S)
    mv "$LOGFILE" "${LOGFILE%.log}-${DATE}.log"
    gzip "${LOGFILE%.log}-${DATE}.log"
fi
```

**Step 2: Archive old daemon logs**

Clean up daemon logs older than 7 days:
```bash
find ~/gt/.beads/ -name "daemon-*.log.gz" -mtime +7 -delete
```

**Step 3: Prune state.json of dead sessions**

The state.json tracks active sessions. Prune entries for sessions that no longer exist:
```bash
# Check for stale session entries
gt daemon status --json 2>/dev/null
```

If state.json references sessions not in tmux:
- Remove the stale entries
- The daemon's internal cleanup should handle this, but verify

**Note**: Log rotation prevents disk bloat from long-running daemons.
State pruning keeps runtime state accurate.


gt spawn --continue for resuming parked molecules

Add `--continue` flag to gt spawn for resuming parked molecules:

```bash
gt spawn --continue gt-mol-root
```

This:
1. Finds molecule root
2. Verifies molecule is in "parked" state (in_progress, no assignee)
3. Checks external deps are now satisfied
4. Spawns polecat with molecule context
5. Polecat reads handoff mail and continues from blocked step

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

Depends on: gt-zniu (gt park)
Depends on Beads: bd-zmmy (bd ready resolution)


Merge: slit-1767138831931

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


Move disk 2: A → C

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


Move disk 1: B → C

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


Move disk 6: B → A

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


Merge: rictus-mjw3nj1a

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


Digest: mol-deacon-patrol

Patrol 3: Routine


Digest: mol-deacon-patrol

Patrol 18: All clear


Add pre-flight test check to mol-polecat-work

Add a step early in mol-polecat-work (after branch-setup, before implement) to check if tests pass on main.

## Problem
If main is broken when polecat starts, they could:
- Waste context trying to fix unrelated issues
- Not know if their changes broke things or it was pre-existing
- Get blamed for failures they didn't cause

## Proposed Step: preflight-tests

After branch-setup, before implement:

1. Checkout main temporarily
2. Run test suite
3. If tests PASS: Continue to implement
4. If tests FAIL:
   - Quick fix (<15 min): Fix it, commit to main, then continue
   - Big fix: File bead, mail Witness, proceed with own work
   - Use ZFC judgment - you're there, you decide

## Handoff Consideration
If fixing pre-existing failures consumes significant context:
- Commit the fix
- gt handoff with note: 'Fixed pre-existing test failures, continuing with assigned work'
- Fresh session picks up from implement step

## Key Principle
Scotty Test: Don't walk past a broken warp core. But also don't let someone else's mess derail your mission entirely.


Digest: mol-deacon-patrol

Patrol 3: routine, all healthy


Digest: mol-deacon-patrol

Patrol 2: all healthy, no action needed


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 19: healthy


Test shiny formula end-to-end

Test the shiny (engineer-in-box) formula:

1. **Create issue with formula**:
```bash
gt sling shiny --var feature="Add hello world endpoint" gastown
```

2. **Watch polecat execute shiny steps**:
   - design: Architecture thinking
   - implement: Write the code
   - review: Self-review
   - test: Run tests
   - submit: Create PR

3. **Verify output**:
   - Design notes in issue/commit
   - Implementation matches design
   - Tests pass
   - PR created and ready for merge

Success: A reviewed, tested PR from a single command.


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 19: all healthy


Digest: mol-deacon-patrol

Patrol 13: all healthy


Digest: mol-deacon-patrol

Patrol complete: all agents healthy, 0 inbox messages, no orphans


Check mail for MR submissions, escalations, messages.

```bash
gt mail inbox
# Process any urgent items
```

Handle shutdown requests, escalations, and status queries.

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 20: OK - Handoff threshold reached


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

P15: stable


Move disk 4: A → C

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Witness Role Definition

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

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

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

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

## Core Responsibilities

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

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

## Propulsion Principle

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

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

## Nudge Protocol

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

## Pre-Kill Verification

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

## Commands

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


Merge: furiosa-mjxap5fz

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


Digest: mol-deacon-patrol

Patrol 7: Healthy. Furiosa resolved rig mismatch.


Digest: mol-deacon-patrol

Patrol 149 complete


Digest: mol-deacon-patrol

Patrol cycle 27: All healthy, no incidents


Merge: slit-mjxof5ku

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 15: All healthy


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 18: Nominal


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: warboy-1767106060799

branch: polecat/warboy-1767106060799
target: main
source_issue: warboy-1767106060799
rig: gastown


gt-crew-gastown-joe

gt-crew-gastown-joe

role_type:
rig: null
agent_state: running
hook_bead: null
role_bead: null
cleanup_status: null


Digest: mol-deacon-patrol

Cycle 191: Nominal


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 10: All green - halfway mark


gt rig info: Show detailed rig information

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

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol OK: 8 polecats, 4 witness/refineries up


Testing: End-to-end rebase workflow validation

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

## Test Scenarios

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

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

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

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

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


Track spawned sessions in DogDispatchInfo

Minor TODO in internal/cmd/sling.go:1002:

```go
return &DogDispatchInfo{
    DogName:  targetDog.Name,
    AgentID:  agentID,
    Pane:     pane,
    Spawned:  false, // TODO: track if we spawned a new session
}, nil
```

The Spawned field is always false. Should track if DispatchToDog actually spawned a new session vs reused an existing one.

Low priority - the information could be useful for logging/debugging but doesn't affect functionality.


Digest: mol-deacon-patrol

Patrol #16


Digest: mol-deacon-patrol

Patrol cycle 11: All agents healthy


Digest: mol-deacon-patrol

Patrol 2: All healthy, fixed 1 stale lock


Digest: mol-deacon-patrol

P6: stable, beads polecats exited


Digest: mol-deacon-patrol

Patrol 15: all healthy


Session ended: gt-gastown-nux


Digest: mol-deacon-patrol

P14: stable


Digest: mol-deacon-patrol

Patrol complete: all agents healthy


Move disk 4: B → A

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


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

Patrol 10: All healthy


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.


MVP Cutover: GGT replaces PGT for batch work

When this is closed, stop using town and start using gt.

## Acceptance Criteria

1. gt spawn assigns issue to polecat and starts session
2. gt spawn --epic spawns workers for all epic children
3. gt session manages tmux lifecycle
4. gt send / gt inbox work for mail
5. Refinery processes merge queue with semantic merges
6. Integration branches created and landed correctly
7. gt stop --all halts all sessions
8. One successful test batch completed end-to-end

## What Must Work

- Spawn polecat with issue assignment
- Spawn workers for epic children
- Session start/stop/attach
- Mail send/inbox/read
- Refinery merge loop (semantic)
- Integration branch → main landing
- Witness cleanup protocol
- Emergency stop

## What Can Be Deferred

- Doctor checks (use PGT)
- TUI dashboard
- Plugin system
- Federation
- Ephemeral rigs
- Detailed landing reports

## Test Plan

1. Create epic with 2 tasks, spawn 2 workers
2. Verify polecats get assigned and sessions start
3. Simulate task completion
4. Verify Refinery merges to integration
5. Verify landing to main
6. Verify cleanup

## Validation

Run one real batch implementing GGT issues using GGT.

## Note

No "swarm IDs" - just spawn workers for epic, let merge queue coordinate.


Implement sendToAnnounce() for bulletin board delivery

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

SEMANTICS:
- ONE copy in shared location (not fan-out)
- Messages persist until retention limit reached
- No claiming, no removal on read

STORAGE:
- Location: {townRoot}/.beads/
- Metadata: announce_channel field to identify which channel

RETENTION:
- On send, count existing messages in channel
- If count >= retain_count, delete oldest
- retain_count=0 means unlimited

IMPLEMENTATION:
1. Add sendToAnnounce(msg *Message) error
2. Load AnnounceConfig from messaging.json
3. Validate sender is eligible (readers list) - optional
4. Create message bead with announce_channel metadata
5. Apply retention pruning

FILE: internal/mail/router.go
PATTERN: Similar to sendToQueue but no claiming


gt mol status: Change 'Pinned' to 'Hooked' in output

The `gt mol status` output shows "📌 Pinned: <bead-id>" for hooked beads, which is confusing now that we have distinct statuses:

- **hooked**: Work assigned to you (triggers autonomous mode)
- **pinned**: Permanent reference beads (like agent beads, role beads)

The output currently says:
```
📌 Pinned: gt-3amkz: Overhaul autonomous-mode guidance...
No molecule attached
```

Should say:
```
🪝 Hooked: gt-3amkz: Overhaul autonomous-mode guidance...
No molecule attached
```

Additional improvements:
1. Change icon from 📌 to 🪝 for hooked beads
2. Add a note clarifying that hooked work triggers autonomous mode even without an attached molecule
3. Consider adding "AUTONOMOUS MODE" banner when hooked work is found (similar to gt prime)

Files to update:
- internal/cmd/molecule_status.go (outputMoleculeStatus function around line 576)


Complete gt crew commands (list, attach, remove, refresh, status)

Add remaining crew subcommands to internal/cmd/crew.go:

1. gt crew list - List crew workspaces with status
2. gt crew at/attach - Start tmux session in crew workspace
3. gt crew remove - Remove crew workspace (with safety checks)
4. gt crew refresh - Context cycling with mail-to-self handoff
5. gt crew status - Show detailed workspace status

Build on existing crew add implementation in internal/cmd/crew.go.
Reference closed issues gt-cik.3-7 for original requirements.


Move disk 2: C → B

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


Wisp directory and format

Define and implement the .beads-wisp directory structure.

## Directory Structure

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

## Wisp File Format

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

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

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

## Key Properties

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

## Implementation

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


Merge: nux-1767073376184

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


Move disk 4: A → C

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


Digest: mol-deacon-patrol

P13: stable


OSS Launch Readiness

Track all issues blocking or affecting OSS launch quality.

P0 Blocker:
- gt-ofl2: ProcessMRFromQueue not implemented

P1 Must Fix:
- gt-vzic: README missing prerequisites (tmux)
- gt-xbfw: Missing OSS files (CONTRIBUTING, etc.)
- gt-wexr: Polecat role swarm terminology
- gt-6n13: Competing molecule mechanisms
- gt-3abj: go install may fail

P2 Should Fix:
- gt-qj12: Obsolete beads cleanup
- gt-zn9m: Error suppression patterns
- gt-9uxr: Test coverage gaps
- gt-fm75: os.Exit in library code
- gt-yewf: Mismatched startup protocols
- gt-1z4m: Undocumented gt swarm
- gt-bho9: stderr suppression
- gt-rxsh: Merge model confusion
- gt-5ipl: Witness role commands

P3 Nice to Have:
- gt-t5mz: Hardcoded values


Integration test: agent waits for CI via gate

End-to-end test of the gate workflow.

## Test Scenario
1. Agent creates gate: bd gate create --await gh:run:123 --timeout 5m --notify beads/dave
2. Agent writes handoff and exits
3. Deacon patrol checks gate condition
4. (Mock) GitHub run completes
5. Deacon notifies waiter and closes gate
6. New agent session reads mail and resumes

## Test Requirements
- Mock GitHub API responses
- Test timeout path
- Test multiple waiters
- Verify mail notifications sent

## Moved from beads
Originally bd-rl5t. Tests Deacon patrol which is in gastown.


Retry logic: exponential backoff for transient failures

Implement retry logic for transient failures.

Retryable failures:
- Push failed (network, auth transient)
- Test flaky (config: retry_flaky_tests)
- Fetch failed (network)

Retry strategy:
- Max retries: 3 (configurable)
- Backoff: 1s, 2s, 4s (exponential)
- On final failure: treat as permanent, assign back

Non-retryable failures:
- Merge conflict
- Test consistently fails
- Build error

Track retry count in MR metadata for debugging.

Reference: docs/merge-queue-design.md#failure-recovery


Agent state lifecycle incomplete for polecats

## Problem

The witness patrol formula (mol-witness-patrol.formula.toml) expects polecats to self-report states:
- running
- idle
- stuck
- done

But looking at the code, the only state transitions that actually happen are:

1. **spawning** - Set when polecat is created (polecat/manager.go:170)
2. **running** - Set when agent runs `gt prime` (prime.go:112)
3. **dead** - Set by daemon when agent goes unresponsive (daemon/lifecycle.go:647)

**Missing transitions:**
- `stuck` - No code path exists for agents to report this
- `done` - No code path exists for agents to report this
- `idle` - Only set for infrastructure agents, never for polecats

## Impact

The witness cannot rely on agent_state to detect stuck or done polecats, contradicting the ZFC principle stated in the formula.

## Found in commit

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

## Suggested fix

Add code paths for polecats to self-report:
1. `gt done` should update agent_state to "done"
2. When stuck (detected how?), agent should update to "stuck"
3. Consider if "idle" makes sense for polecats (no current work)


RPG platform design: gamification layer

Design the RPG UX metaphor - the flagship consumer experience for HOP.
Makes real work feel like a game because the game IS real work.

**Reference**: ~/gt/docs/hop/PLATFORM-OF-PLATFORMS.md (lines 188-214)

**Deliverable**: Design document defining:

1. **Core metaphor mappings**:
   - Quests = Work units (beads/issues)
   - Skills = Stats derived from work history
   - Leveling = Reputation accumulation
   - Guilds = Organizations
   - Loot = Payment/rewards

2. **Progression mechanics**:
   - XP calculation from work completions
   - Skill tree visualization
   - Level thresholds and prestige ranks
   - Achievement system

3. **Social features**:
   - Guild formation and management
   - Leaderboards (opt-in, privacy-aware)
   - Cooperative quests (swarming as raids)
   - Mentorship system

4. **Engagement hooks**:
   - Daily/weekly quest boards
   - Streak bonuses
   - Rare quest discovery
   - Boss battles (epic issues)

5. **Why it works**:
   - Progress feels real because it IS real
   - Stats are accurate because they're derived from actual work
   - Social proof from genuine collaboration

**Acceptance criteria**:
1. Design doc in ~/gt/docs/hop/RPG-PLATFORM.md
2. Core metaphor mappings defined
3. UI/UX wireframes or mockup descriptions
4. Privacy model (what's public vs. private
EOF
)


BUG: gt sling updates bead status but doesn't create .hook file

gt sling updates the bead to status=hooked but doesn't actually create the .hook file in the polecat directory.

## Symptom
- gt sling reports success
- Bead shows status=hooked, assignee set
- Polecat's .hook file doesn't exist
- gt hook shows empty

## Root Cause
gt sling updates bead state via bd commands but never writes to polecats/<name>/.hook

## Fix
After updating bead status, write the bead ID to the .hook file:
```go
hookPath := filepath.Join(polecatDir, ".hook")
os.WriteFile(hookPath, []byte(beadID), 0644)
```

## Related
This is blocking gt-zqt4d dispatch to splendid.


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 29/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.


Move disk 1: B → C

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


Digest: mol-refinery-patrol

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


Digest: mol-deacon-patrol

Patrol 26: furiosa session started, all quiet


Digest: mol-deacon-patrol

Patrol cycle 19: All 6 agents healthy


Move disk 2: B → A

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


Patrol Lifecycle Completion

Patrols complete their full cycle without wisp accumulation.

## Problem
Patrol wisps accumulate (73+ observed) because burn-or-loop step does not complete. This wastes storage and makes bd list noisy.

## Requirements
- Burn-or-loop step executes and burns completed wisps
- Fresh wisp instantiated for next patrol cycle
- Wisp GC runs periodically as safety net (orphan-check step)
- Context cycling triggers gt handoff when budget exhausted
- No wisp accumulation over time

## Success Criteria
- bd wisp list shows fewer than 5 wisps at any time
- Patrols run indefinitely without intervention
- Context cycles cleanly produce handoff mail

This is the foundation for all autonomous patrol work.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


gt swarm status fails to find issues via rig discovery

gt swarm status gt-1tpts fails with 'issue not found' but bd swarm status gt-1tpts works. The rig discovery in getAllRigs() may not be finding rigs correctly, or the bd commands are running from wrong directory.


Day 2.7: Bootstrap creates agent beads

Bootstrap commands must create agent beads for ZFC compliance.

## Problem
- `gt install` doesn't create Deacon/Mayor agent beads
- `gt rig add` doesn't create Witness/Refinery agent beads
- `gt doctor` doesn't verify agent beads exist
- Current beads were created manually (not reproducible)

## Impact
Patrol ignition (gt-qpoxz) depends on agent beads existing.
Without bootstrap creating them, fresh installs will fail.

## Required
1. gt install: Create gt-deacon and gt-mayor beads
2. gt rig add: Create gt-witness-<rig> and gt-refinery-<rig> beads
3. gt doctor: Add agent-beads-exist check
4. gt doctor --fix: Create missing agent beads


Digest: mol-deacon-patrol

Patrol #17: Health pinged all refineries.


mol-deacon-patrol


Digest: mol-deacon-patrol

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


Add unit tests for internal/mail router and mailbox

attached_args: Add unit tests for mail router and mailbox

Add tests for mail routing and mailbox functionality.

## Files to create
- internal/mail/router_test.go
- internal/mail/mailbox_test.go

## Test cases for router
1. Route() resolves addresses correctly
2. Route() handles rig/role format
3. Route() handles rig/crew/name format
4. Invalid addresses return error

## Test cases for mailbox
1. Send() writes message to mailbox
2. Inbox() lists messages
3. Read() retrieves message by ID
4. Delete() removes message
5. Messages persist correctly

## Acceptance criteria
- [ ] router_test.go with 4+ tests
- [ ] mailbox_test.go with 5+ tests
- [ ] Tests pass: go test ./internal/mail/...
- [ ] Coverage > 60%


Digest: mol-deacon-patrol

Patrol 12: clear


GT_ROLE env var not set correctly for crew workers


Move disk 1: B → C

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


Silent error handling with _ = err patterns

Multiple locations intentionally ignore errors with comments like 'Ignore errors'. While some are valid (best-effort operations), others should be audited:

- witness/manager.go:542 - Ignores cmd.Run() error
- refinery/manager.go:411, 438, 509 - Ignores loadState and git pull errors
- swarm/manager.go:47 - Ignores getGitHead error
- polecat/manager.go:69, 284 - Ignores pool.Load and DeleteBranch errors
- swarm/integration.go:101, 137 - Ignores git pull and push errors

Each should be evaluated: log it, handle it, or confirm ignoring is intentional.


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 4: All clear


gt hook: Shows wrong agent identity when run from different rig's crew directory

## Problem

Running `gt hook` from another rig's crew directory shows the wrong agent.

```bash
cd ~/gt/beads/crew/dave
gt hook
# Shows: gastown/crew/joe (wrong - should be beads/crew/dave)
```

## Expected

`gt hook` should detect agent identity from cwd, showing the hook for the
agent whose directory you're in.

## Related

- gt-yud21: gt peek cross-rig crew path support
- gt-hldpv: gt sling "." resolution

## Root cause

Likely the agent identity detection in hook.go doesn't handle cross-rig
crew paths correctly.


gt doctor: add bd daemon status check

Add check for daemon running. Add check for database fingerprint. --fix should be able to migrate (bd migrate --update-repo-id) and restart daemon.


Merge: toast-1767079830359

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


Digest: mol-deacon-patrol

Patrol 15: Routine


Digest: mol-deacon-patrol

Patrol 16: OK


Move disk 3: A → B

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


Move mol run semantics from bd into gt spawn

Currently gt spawn shells out to bd mol run for the pour+assign+pin combo. This blurs the architectural boundary between bd (data layer) and gt (orchestration layer).

## Current State
- bd mol run = bd pour + bd update --status=in_progress + bd pin --for me
- gt spawn calls: exec.Command("bd", "mol", "run", ...)

## Proposed Change
Move the combo logic into gt spawn directly:
1. gt spawn calls bd pour (create issues from template)
2. gt spawn calls bd update --status=in_progress (claim work)
3. gt spawn calls bd pin (set pinned flag)
4. gt spawn does session/tmux orchestration

This keeps bd as pure data operations and gt as the orchestration layer.

## Why
- Cleaner separation of concerns
- bd mol run feels like orchestration but it's in the data layer
- gt should own the "start a workflow" semantics

## Coordination
beads side will deprecate bd mol run once gt no longer depends on it.


Digest: mol-deacon-patrol

Patrol cycle 15: routine


Digest: mol-deacon-patrol

Patrol cycle 2: all quiet, agents healthy


Digest: mol-deacon-patrol

Cycle 20: Final health check - all healthy


Move disk 5: C → A

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


SSHOutpost: Full Gas Town clone on remote VM

## Overview

Implement SSHOutpost for running workers on remote VMs via SSH.

## Model

Remote VM has a full Gas Town clone. SSHOutpost:
- Connects via SSH
- Spawns tmux sessions on remote
- Uses remote git clone for code/beads
- Syncs via git push/pull

## Implementation

```go
type SSHOutpost struct {
    name       string
    host       string
    user       string
    keyPath    string
    townPath   string  // e.g., /home/steve/ai
    maxWorkers int
    conn       *ssh.Client
}

func NewSSHOutpost(config OutpostConfig) (*SSHOutpost, error)

func (o *SSHOutpost) Spawn(issue string, cfg WorkerConfig) (Worker, error) {
    // SSH: create tmux session on remote
    // SSH: start claude in session
    // Return SSHWorker
}

func (o *SSHOutpost) Ping() error {
    // Test SSH connectivity
}
```

## SSHWorker

```go
type SSHWorker struct {
    outpost *SSHOutpost
    id      string
    session string
    issue   string
}

func (w *SSHWorker) Attach() error {
    // SSH + tmux attach (opens terminal)
}

func (w *SSHWorker) Logs() (io.Reader, error) {
    // SSH: tmux capture-pane
}
```

## Prerequisites on Remote VM

1. Gas Town clone at townPath
2. Claude Code installed
3. Git credentials configured
4. SSH key access

## Integration with gt-f9x.7-8

This builds on the Connection interface from gt-f9x.7/8. SSHOutpost uses SSHConnection internally for remote operations.

Depends on: gt-9a2.1 (interfaces), gt-f9x.7 (Connection interface)


Merge: capable-mjw47ef9

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


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

Patrol 16


Move disk 1: A → B

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


Test polecat lifecycle end-to-end

Test the full polecat lifecycle:

1. **Spawn**: Sling a test issue to a polecat
```bash
bd create --title="Test issue for polecat" --type=task
gt sling gt-<id> gastown
```

2. **Execute**: Watch polecat work
```bash
tmux attach -t gt-gastown-<name>
```

3. **Complete**: Polecat should:
   - Close the issue: `bd close gt-<id>`
   - Commit work: `git commit && git push`
   - Send POLECAT_DONE mail to witness

4. **Cleanup**: Witness should:
   - Receive POLECAT_DONE
   - Verify git state clean
   - Kill session and remove worktree

Success: Issue closed, PR merged, polecat cleaned up.


Move disk 2: C → B

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


gt crew add: Agent bead uses hardcoded gt- prefix instead of rig prefix

When running 'gt crew add <name> --rig beads', the command tries to create an agent bead with ID 'gt-crew-beads-<name>' but beads rig uses 'bd' prefix.

Error: issue ID 'gt-crew-beads-grip' does not match configured prefix 'bd'

The agent bead ID should use the target rig's prefix, not hardcode 'gt-'.


Merge: rictus-mjw3nj1a

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


Verify initial state

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


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.


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

Work on gt-role-template: Refine witness/CLAUDE.md role template. Run 'bd show gt-role-template' to see the full issue.


Design: Polecat Beads write access

Design for granting polecats direct beads write access.

## Background

With Beads v0.30.0 tombstone-based rearchitecture, we have solid multi-agent support. Reversing the original read-only decision.

## Benefits

- Simplifies architecture (no mail-based issue filing proxy)
- Empowers polecats to file discovered work
- Beads handles work-disavowal

## Complications

For OSS projects where you cannot commit to project .beads/, need per-rig beads repo configuration.

## Subtasks (implementation)

- gt-zx3: Per-rig beads configuration schema
- gt-e1y: Worker prompting updates for beads access
- gt-cjb: Witness proxy removal
- gt-082: Beads sync in decommission checklist

**Design complete.** Each subtask has full specification in its description.


Check Witness and Refinery health

Check Witness and Refinery health for each rig.

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

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

**Signals to assess:**

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

**Tracking unresponsive cycles:**

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

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

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

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

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

Reset unresponsive_cycles to 0 when component responds normally.


Digest: mol-deacon-patrol

Patrol 16 complete


Move disk 1: A → B

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


Move disk 3: A → B

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


gt-deacon

Deacon (daemon beacon) - receives mechanical heartbeats, runs town plugins and monitoring.

role_type: deacon
rig: null
agent_state: idle
hook_bead: null
role_bead: gt-deacon-role


Digest: mol-deacon-patrol

Patrol cycle 45: All healthy


Digest: mol-deacon-patrol

Patrol cycle 16: All healthy - 8 polecats running (max, jack, dementus, capable, toast, dag + crew). Handing off after 6 cycles.


test pin fix


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.


Refinery Patrol Cycle


Digest: mol-deacon-patrol

Patrol cycle 8: all healthy


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 20: all healthy, doctor pass, handoff cycle


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol cycle 18: All healthy.


Migrate startup paths from SessionBeacon to StartupNudge

## Problem
StartupNudge function exists (gt-bgfqy) but no code uses it.
All startup paths still call session.SessionBeacon() + 'gt prime' separately.

SessionBeacon format: [GAS TOWN] address • molID • timestamp
StartupNudge format: [GAS TOWN] recipient <- sender • timestamp • topic

The key difference is SENDER - needed for seance discovery ('who started this session?').

## Files to Update
- internal/cmd/crew_lifecycle.go (lines 354-371, 525-538)
- internal/cmd/start.go (lines 757, 805-810, 946-949)
- internal/cmd/deacon.go (line 307)
- internal/cmd/witness.go (line 350)
- internal/cmd/up.go (lines 288, 335, 559, 660)
- internal/cmd/mayor.go (line 151)
- internal/session/manager.go (lines 205, 215)

## Pattern
Replace:
  beacon := session.SessionBeacon(address, molID)
  t.NudgeSession(sessionID, beacon)
  t.NudgeSession(sessionID, "gt prime")

With:
  cfg := session.StartupNudgeConfig{Recipient: address, Sender: sender, Topic: topic, MolID: molID}
  session.StartupNudge(t, sessionID, cfg)
  // Note: StartupNudge is the session title, still need separate 'gt prime' for priming

## Related
- gt-85whr (parent epic)
- gt-j0546 (did RuntimeConfig refactor, not StartupNudge)


Digest: mol-deacon-patrol

Cycle 16


Add GitHub CI workflow for PRs

Gas Town has no CI. Add .github/workflows/ci.yml that runs tests and linter on PRs. Reference beads repo for example.


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 6: OK


Digest: mol-deacon-patrol

Patrol 132: All healthy


Polecat: Conflict resolution workflow

New workflow for polecats handling conflict-resolution tasks.

## Task Recognition
- Task title starts with "Resolve merge conflicts:"
- Task has metadata: original MR, branch, conflict SHA

## Workflow (UPDATED - uses merge-slot)
1. Read task metadata
2. **Acquire merge slot** (gt-4u49x) - wait if held
3. Fetch the branch: `git fetch origin <branch>`
4. Checkout: `git checkout -b temp-resolve origin/<branch>`
5. Attempt rebase: `git rebase origin/main`
6. Resolve conflicts (Claude judgment)
7. Run tests
8. **Push directly to main** (not force-push to branch)
9. Close original MR bead (not just conflict task)
10. **Release merge slot**
11. Close conflict-resolution task

## Key Changes from Original
- Acquire/release merge slot (serialization)
- Push to main directly (skip queue re-entry)
- Close original MR bead (proper attribution)

## Considerations
- May need to read original issue for context
- May need to read MR description for intent
- If resolution is complex, can ask for human help (escalate)

## Dependencies
- gt-4u49x: Merge-slot gate (serialization)
- gt-hibbj: Non-blocking refinery delegation


Move disk 1: B → C

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


Daemon: integration test with real lifecycle

Need an end-to-end test that:
1. Starts daemon
2. Starts a test agent session
3. Sends lifecycle request to daemon
4. Verifies session was killed and restarted
5. Cleans up

Could use a mock 'agent' that's just a shell script.


Direct landing integration: gt land uses MR or bypasses

Integrate direct landing with merge queue.

'gt land --direct' should:
1. Check if MR exists for the polecat's work
2. If MR exists: process it directly (skip queue)
3. If no MR: create temporary MR, process, close

Options:
- --direct: bypass queue (existing)
- --via-queue: ensure goes through queue (new)
- --force: skip safety checks (existing)

This ensures direct landing still creates proper records.

Reference: docs/merge-queue-design.md#direct-landing-bypass-queue


Move disk 1: C → A

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


Move disk 2: A → B

Move disk 2 from peg A to peg B.


Move disk 4: B → A

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


Merge: furiosa-1767073359963

attached_args: Code review this merge request

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

REVIEW REJECTED by rictus: Commits claim await-signal but no such code exists. Feature removals conflict with rictus branch quality-level work. Needs clarification and reconciliation.


Digest: mol-deacon-patrol

Patrol cycle 5: All 6 agents healthy, gastown queue cleared


Digest: mol-deacon-patrol

Patrol 6: All healthy


Idle polecats are a Gas Town bug - investigate and fix

## Bug: Idle Polecats

Polecats are completing work and sitting idle instead of being cleaned up.

## Root Cause Analysis

### Current State
- 5 gastown polecats: sessions active, NO hook, finished work, submitted MRs
- Witness has **50 unread messages** including POLECAT_DONE and MERGED signals
- Witness is idle saying "All 6 polecats idle. System cycling efficiently."
- Polecats at Claude prompt waiting → burning money

### Protocol Flow (Design)
1. Polecat runs `gt done` → sends POLECAT_DONE to Witness, creates MR bead
2. Refinery processes MR bead, merges, sends MERGED to Witness
3. Witness receives MERGED, verifies clean state, nukes polecat

### What's Broken
**Witness is not processing its mail inbox.**

The Witness Claude agent is supposed to patrol: check inbox, process protocol messages, nuke completed polecats. But it's sitting idle at a prompt instead.

Symptoms:
- Polecats finish work → sit at prompt waiting for death
- MERGED signals pile up in Witness inbox (unprocessed)
- Sessions burn money while waiting
- No cleanup happens

### Design Philosophy Violation

From `propulsion-principle.md`:
> Gas Town is a steam engine. Agents are pistons that MUST fire.

Idle polecats violate this - they're stalled pistons. The design says polecats should be ephemeral: spawn → work → die. No idle state.

## Recommendations

### Option 1: Self-Terminating Polecats (Recommended)
After `gt done`, polecat should exit Claude session immediately. No waiting for Witness.
- Add `--exit` flag to `gt done` that runs `/exit` after submitting MR
- Witness nukes worktree later when processing MERGED (session already gone)

**Pros**: No idle sessions, no burning money
**Cons**: Minor race condition if nuke runs while session exiting

### Option 2: Witness Polling Daemon
Replace Claude-based Witness with a daemon that polls MR queue and nukes polecats.
- Not dependent on Claude session patrol loops
- More reliable but loses Claude intelligence

### Option 3: Fix Witness Patrol
Make Witness actually patrol continuously instead of stopping.
- Strengthen template to emphasize continuous mail processing
- Risk: Claude agents still forget/ignore instructions

## Immediate Fix

For now: Mayor or user must manually nudge Witness or nuke idle polecats.

```bash
# Check idle polecats
gt polecat list gastown

# Manual nuke (if verified clean)
gt polecat nuke gastown/dementus
```

## Related Issues
- Witness patrol loop reliability
- gt done should self-terminate
- Protocol message handling automation


session stop: --force flag is defined but not used


CLI: rig commands (add, list, show, remove)

GGT needs rig management commands.

Missing Commands:
- gt rig add <git-url> [--name NAME] - Add rig to workspace
- gt rig list - List all rigs with status
- gt rig show <rig> - Show detailed rig info
- gt rig remove <rig> - Remove a rig

PGT Reference: gastown-py/src/gastown/cli/rig_cmd.py

Current State:
- gt init creates rig structure but no ongoing management
- Rig discovery in internal/rig/manager.go but not exposed via CLI


Merge: dementus-1767079823043

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


Digest: mol-deacon-patrol

Patrol cycle 9: All quiet.


Digest: mol-deacon-patrol

Patrol #1: No issues found. All 6 agents healthy. No orphans.


Move disk 2: C → B

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


Move disk 3: A → B

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


Digest: mol-deacon-patrol

Patrol 14: All healthy, no messages


Digest: mol-deacon-patrol

Patrol 211: All nominal


Merge: gt-svdsy

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


Digest: mol-deacon-patrol

Patrol 104: All agents healthy, no incidents


Messaging infrastructure: lists, queues, channels

Multi-recipient and broadcast messaging for Gas Town.

## Phases

**Phase 1 - Foundation**: Config directory (gt-i6jvc)
**Phase 1 - Core**: list:, queue:, @group (requires agent-as-bead for @group)
**Phase 2 - Channels**: announce:, #channel, gt channel publish

## Addressing Syntax

| Prefix | Resolution | Storage | Claim? |
|--------|------------|---------|--------|
| `@group` | Dynamic (bead queries) | Fan-out (N copies) | No |
| `list:name` | Static config | Fan-out (N copies) | No |
| `queue:name` | Static config | Shared (1 copy) | Yes |
| `announce:name` | Static config | Shared (1 copy) | No |
| `#channel` | Dynamic (tmux) | None (ephemeral) | No |

## Alignment with Agent-as-Bead

@group resolution now uses agent bead queries:
- @rig/gastown → bd list --type=agent --rig=gastown
- @witnesses → bd list --type=agent --role_type=witness

This replaces the originally planned filesystem scanner (gt-xo05b, now closed).

## Independent Work

Config-based features (list:, queue:, announce:) can proceed without agent identity.
Only @group requires the agent schema from Pillar 1.


mol-deacon-patrol


Move disk 2: C → B

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


Update lifecycle mail targets to deacon/

Update Mayor, Witness, and Crew handoff code to send lifecycle requests to deacon/ instead of daemon/. Update internal/cmd/handoff.go and related code.


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol: fixed stale mol spawn prompts, cleaned 36 orphaned wisps, all agents healthy


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy. 3 rigs.


Move disk 2: A → C

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


Move disk 4: B → A

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


Add compaction recovery protocol to role templates

After context compaction (summarization), agents may be disoriented.

Add guidance to recognize and recover:
- 'If you feel you've lost earlier context or are disoriented, run: gt prime'
- 'This re-injects your role, current work, and pending messages'
- 'It's safe to prime multiple times - it just outputs context'

This is the fallback path when self-check is missed and compaction happens.
Compaction isn't catastrophic if priming is robust.


Move disk 3: A → B

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


Move disk 4: C → B

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


Test merge request

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


Digest: mol-deacon-patrol

Patrol 4: 9 sessions healthy


Move disk 3: A → B

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


Digest: mol-deacon-patrol

Patrol 20: All healthy, cycling session


Digest: mol-deacon-patrol

Patrol 20: Final patrol, all healthy, handoff triggered


Implement gt hooks command

New command to show all hooks across a rig.

Usage: gt hooks [rig]

Output shows:
- All polecats and their hook status
- Witness hook status
- Refinery hook status
- Crew member hook status
- Progress bars for attached molecules


Digest: mol-deacon-patrol

Patrol 113: All healthy


Digest: mol-deacon-patrol

Patrol 33: all quiet


Digest: mol-deacon-patrol

Patrol 161: All agents healthy, no incidents, 1 dog idle


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 2: All agents healthy, routine check


Digest: mol-deacon-patrol

Patrol #13: Stable


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.


Merge: nux-1767080427756

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


Digest: mol-deacon-patrol

Patrol 10: All healthy


Add GH deployment artifacts (homebrew, npm)

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

Reference Beads implementation for patterns.


Digest: mol-deacon-patrol

Patrol 9: healthy


Activity feed from wisp state: gt patrol status

Enable mayor and gt tool to quickly see what patrol agents are doing.

## Problem

The mayor and gt tool cannot quickly see what the deacon (or other patrol agents) are doing.
Need a way to extract an activity feed from the current wisp state.

## Desired Commands

- gt patrol status: Show current patrol state (step, timing, cycle count)
- gt patrol history: Show recent patrol cycles (from digests)
- gt patrol feed: Live tail of patrol activity

## Data Sources

- .beads-wisp/issues.jsonl: Current wisp with step progress
- .beads/issues.jsonl: Digests from squashed patrols
- heartbeat.json: Last activity timestamp

## Use Cases

1. Mayor checking deacon: Is the deacon doing anything?
2. Debugging hangs: What step is it stuck on?
3. Operator monitoring: Dashboard of patrol health
4. Summaries for handoffs: Auto-generate patrol digest

## Related

- gt-id36: Deacon Kernel
- gt-3x0z: Wisp Molecule Integration


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 6: healthy


Merge: slit-mjui7j71

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


Update swarm terminology to streams

Gas Town moved from batch swarms to continuous streaming of polecats. Update:
- Docs and designs
- Code comments
- CLI flags (remove --swarm if present, or reframe)
- Variable/function names where appropriate

Streams reflect the reality: polecats flow continuously, not in discrete batches.


Extract SupportedShells constant to constants package

Extract repeated shell list to a single constant.

## Files to modify
- internal/constants/constants.go (add constant)
- internal/cmd/start.go (use constant at lines 729, 773, 907)
- internal/cmd/crew_helpers.go (use constant)

## Implementation
Add to constants.go:
```go
var SupportedShells = []string{"bash", "zsh", "sh", "fish", "tcsh", "ksh"}
```

Replace all inline []string{"bash", "zsh"...} with constants.SupportedShells.

## Acceptance criteria
- [ ] SupportedShells added to internal/constants/constants.go
- [ ] All 4 occurrences in start.go and crew_helpers.go replaced
- [ ] grep -r '"bash", "zsh"' returns no matches in internal/cmd/
- [ ] go build ./... passes
- [ ] go test ./... passes


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 15: OK


Move disk 1: C → A

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


Clean dead sessions

Clean dead sessions.

Garbage collect terminated sessions:
- Remove stale polecat directories
- Clean up wisp session artifacts
- Prune old logs and temp files
- Archive completed molecule state

```bash
gt gc --sessions
gt gc --wisps --age=1h
```

Preserve audit trail. Only clean sessions confirmed dead.


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)


Digest: mol-deacon-patrol

Patrol cycle 5: All quiet.


Digest: mol-deacon-patrol

Patrol cycle 48: All healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## 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.


Direct test

Testing direct bd create


Digest: mol-deacon-patrol

Patrol cycle 9: All healthy.


Witness/Refinery startup: Enforce patrol molecule attachment

Witness and Refinery CLAUDE.md says to:
1. Check for attached molecule on startup
2. If not attached, spawn patrol wisp

But sessions are just reacting to mail without patrol structure.

Current state:
- gt-8ynws (Witness Patrol) exists but not attached
- gt-t5i07 (Refinery Patrol) exists but not attached
- Sessions are running without structured patrol loops

Fix options:
1. Add SessionStart hook to enforce patrol attachment
2. Make 'gt start' attach patrol molecules when spawning witness/refinery
3. Add reminder in CLAUDE.md startup banner that's more emphatic


E2E Swarm Test Epic


Digest: mol-deacon-patrol

Cycle 8


Digest: mol-deacon-patrol

Cycle 15


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 6: All healthy


Digest: mol-deacon-patrol

Patrol 11: healthy


Digest: mol-deacon-patrol

Patrol 2: Quick pass, all healthy


gt-gastown-polecat-nux

gt-gastown-polecat-nux

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-s94gq
role_bead: gt-polecat-role
cleanup_status: has_uncommitted
active_mr: gt-qk7p7
notification_level: null


Liftoff implementation plan in Beads

## Context

Session on 2025-12-27 produced three key docs:
- `~/gt/docs/agent-as-bead.md` - Agents ARE beads (identity, hook slots, CV chain roots)
- `~/gt/docs/zfc-violations-audit.md` - Where Go infers instead of trusting agents
- `~/gt/docs/liftoff-plan.md` - 4.5 day plan to self-sustaining Gas Town

## Work Required

### Phase 1: Audit existing beads ✅
- Review all open beads in gt- prefix
- Close obsolete/stale issues
- Update any that need refinement
- Note which existing beads align with liftoff plan

### Phase 2: File new beads ✅
Translate liftoff-plan.md into beads with proper dependencies.

Three pillars:
1. **Pillar 1: Agent Identity** (gt-d0jqp) - schema, slot commands, migration
2. **Pillar 2: Patrol Ignition** (gt-hwka3) - witness/refinery formula wiring
3. **Pillar 3: Polecat Lifecycle** (gt-4a2qt) - recycle/nuke commands, session-per-step

### Phase 3: Review ✅
Human reviews the plan.

## Deliverable

A complete dependency graph in beads that can be:
1. Queried with `bd ready` to find available work
2. Slung to polecats in dependency order
3. Tracked to completion

## References

- ~/gt/docs/liftoff-plan.md - 4.5 day plan
- ~/gt/docs/agent-as-bead.md - Agent identity design
- ~/gt/docs/zfc-violations-audit.md - ZFC violations addressed


Digest: mol-deacon-patrol

Patrol 10: All healthy


Merge: furiosa-1767087671424

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


Digest: mol-deacon-patrol

Patrol 19: healthy


Digest: mol-deacon-patrol

Patrol cycle 2: all healthy, 2 health acks


Digest: mol-deacon-patrol

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol #3: Stable, no changes


Witness: detect polecat completion and trigger merge

## Problem
When polecat pushes completed work, witness needs to detect it and signal refinery.

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

```toml
[[step]]
id = "check-ready-branches"
title = "Check for branches ready to merge"
description = """
1. List polecat branches: git branch -r | grep origin/polecat/
2. For each branch ahead of main:
   - Check if polecat session is done (no session or at handoff prompt)
   - Check if bead is closed: bd show <bead-id>
3. For ready branches, mail refinery:
   gt mail send <rig>/refinery -s "MERGE_READY: polecat/<name>" -m "Branch ready for merge"
"""
depends_on = ["survey-polecats"]
```

## Alternative: Polecat signals explicitly
Add to polecat workflow (end of work):
```
gt mail send <rig>/refinery -s "MERGE_READY" -m "polecat/<name> ready"
gt mail send <rig>/witness -s "WORK_COMPLETE" -m "<bead-id> done"
```

## Why This Works
- Witness/polecat agents make decisions
- Mail is the coordination primitive
- No daemon code needed

## Files
- formulas/mol-witness-patrol.formula.toml
- formulas/mol-polecat-work.formula.toml (add completion signal)


Digest: mol-deacon-patrol

Patrol 4: Nominal


Digest: mol-deacon-patrol

Patrol complete: no work, gastown refinery came online, town healthy


Move disk 1: B → C

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


Move disk 1: B → C

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


Move disk 3: C → A

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


Digest: mol-deacon-patrol

Patrol 4: Quiet


Polecat state tracking: Add mr_submitted and merged states

Track polecat lifecycle state separate from session state.

## New States

| State | Meaning |
|-------|---------|
| active | Working on assigned issue |
| mr_submitted | MR submitted, waiting for merge |
| idle | No current work, session may be alive |
| merged | Work successfully merged by Refinery |
| retired | Session killed, worktree removed |

## Implementation

1. Add state field to polecat tracking (state.json or beads)
2. `gt polecat update <name> --state=<state>`
3. `gt polecat list` shows state column
4. State transitions:
   - active → mr_submitted (on gt mq submit)
   - mr_submitted → merged (on Refinery notification)
   - merged → retired (on worktree cleanup)

## Acceptance
- Polecat state tracked and queryable
- State transitions happen at correct lifecycle points
- `gt polecat list` shows current state


Digest: mol-deacon-patrol

Patrol complete: all agents healthy, no orphans, 0 inbox messages


Session ended: gt-refinery


Digest: mol-deacon-patrol

Patrol 20: routine, handing off


Move disk 3: A → B

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


Digest: mol-deacon-patrol

Patrol 17: All healthy


Digest: mol-deacon-patrol

Patrol complete: routine cycle


implement

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

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

Depends: load-context


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Merge: rictus-mjuic92c

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


Digest: mol-deacon-patrol

Cycle 19


Add tests for gt crew restart --all

Add integration tests for the crew restart flow:

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

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

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


Digest: mol-deacon-patrol

Patrol 10: All healthy


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


Workspace doctor checks: Config, state, mail, Mayor, rigs

Workspace-level doctor checks.

## Checks

### ConfigExists
- Verify config/ directory exists
- Verify config/town.json exists
- Fix: Cannot auto-fix (need gt install)

### ConfigValid
- Parse town.json
- Verify required fields (type, version, name)
- Verify type == "town"
- Fix: Cannot auto-fix

### RigsRegistryValid
- Parse config/rigs.json
- Verify each registered rig directory exists
- Warn on missing rigs
- Fix: Remove missing rigs from registry

### MayorExists
- Verify mayor/ directory exists
- Verify mayor/CLAUDE.md exists
- Fix: Create from template

### MayorMailboxExists
- Verify mayor/mail/ directory exists
- Verify mayor/mail/inbox.jsonl exists (can be empty)
- Fix: Create directory and empty file

### MayorStateValid
- Parse mayor/state.json if exists
- Verify valid JSON
- Fix: Reset to default state

## Implementation

```go
var WorkspaceChecks = []Check{
    &ConfigExistsCheck{},
    &ConfigValidCheck{},
    &RigsRegistryValidCheck{},
    &MayorExistsCheck{},
    &MayorMailboxExistsCheck{},
    &MayorStateValidCheck{},
}
```


Move disk 3: B → C

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


Digest: mol-deacon-patrol

Patrol 136: All healthy


Add 'gt rig start <rig>' to start witness and refinery together

After a town restart, need a convenient way to start both witness and refinery for a rig.

Current workflow requires two commands:
  gt witness start <rig>
  gt refinery start <rig>

Desired:
  gt rig start <rig>  # starts both witness and refinery

Should also support:
  gt rig stop <rig>   # stops both
  gt rig restart <rig> # restarts both


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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 5: 9 sessions healthy


Move disk 5: A → B

Move disk 5 from peg A to peg B. (Move 304/1023)


Digest: mol-deacon-patrol

Patrol 12: 3 rigs healthy


Connection interface: Protocol for local/remote ops

Abstract interface for local vs remote (SSH) operations.

## Concept

Enable Gas Town to manage rigs on remote machines via SSH. The Connection interface abstracts whether operations happen locally or remotely.

## Interface

```go
type Connection interface {
    // Identification
    Name() string
    IsLocal() bool

    // File operations
    ReadFile(path string) ([]byte, error)
    WriteFile(path string, data []byte, perm os.FileMode) error
    MkdirAll(path string, perm os.FileMode) error
    Remove(path string) error
    Stat(path string) (os.FileInfo, error)
    Glob(pattern string) ([]string, error)

    // Command execution
    Exec(cmd string, args ...string) ([]byte, error)
    ExecDir(dir, cmd string, args ...string) ([]byte, error)

    // Tmux (for session management)
    TmuxNewSession(name, dir string) error
    TmuxKillSession(name string) error
    TmuxSendKeys(session, keys string) error
    TmuxCapturePane(session string, lines int) (string, error)
}
```

## Implementations

- LocalConnection (gt-f9x.8): Direct file/exec operations
- SSHConnection (future): Operations via SSH

## Usage

```go
func NewRigManager(conn Connection, ...) *RigManager

// Operations work the same regardless of connection type
rm.DiscoverRigs()  // uses conn.Glob, conn.ReadFile
```

## Design Notes

- Connection obtained from MachineRegistry (gt-f9x.9)
- Default is always local
- SSH connection requires machine config (host, key, user)


attached_args: Refactor runStart into focused helper functions

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

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

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

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

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


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: A → B

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


Digest: mol-deacon-patrol

Patrol 14: healthy


Design molecule parameterization

Enable protos to accept parameters for customization.

## Use Cases

1. rig-spinup needs rig name: `gt sling rig-spinup --param rig=newproject`
2. agent-restart needs agent: `gt sling agent-restart --param agent=gastown/witness`
3. code-review needs scope: `gt sling code-review --param scope=src/auth/`

## Proposed Syntax

### In Proto

```markdown
## Step: create-rig-structure
mkdir -p ~/gt/${rig}/refinery ~/gt/${rig}/witness
```

### In Sling

```bash
gt sling rig-spinup mayor/ --param rig=newproject --wisp
```

### In Bonded Molecule

Interpolation happens at bond time. Step descriptions have concrete values.

## Implementation

1. Proto declares params in frontmatter: `params: [rig]`
2. gt sling validates required params provided
3. bd mol bond receives params, interpolates descriptions
4. Bonded molecule has concrete step text

## Edge Cases

- Missing required param → error
- Unused param → warning
- Param in step title → interpolate there too


Test: Polecat lifecycle validation (auto-close)

Simple test task: Read this issue, print 'Lifecycle test passed', then close this issue with bd close. No code changes needed.


Clean up hook-related gitignore and live files

- Remove hook-*.json from .beads/.gitignore
- Delete /Users/stevey/gt/deacon/.beads/hook-deacon.json
- Convert gt-wisp-0gu to pinned bead if needed


Move disk 1: A → B

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


Move disk 2: B → A

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


Batch Work System: Integration branch, merge queue, landing

## Overview

This epic tracks batch work coordination in GGT. Key insight: **work is a stream, not discrete swarms**.

There are no "swarm IDs" - the epic IS the grouping, the merge queue IS the coordination. "Swarming an epic" is colloquial for spawning multiple workers on its children.

## Architecture

- **Epics** group related work
- **Issues** are individual tasks
- **Dependencies** encode ordering (multi-wave emerges automatically)
- **Merge queue** coordinates completed work
- **Workers** process issues independently

See Key Decision #11 in docs/architecture.md: "Work is a Stream (No Swarm IDs)"

## What This Epic Covers

1. Integration branch management for batch merges
2. Refinery semantic merge processing
3. Witness landing protocol (cleanup)
4. Report generation (epic-based, not swarm-ID-based)
5. Git safety auditing
6. Work reconciliation

## What Was Removed

- Swarm IDs (sw-1, sw-2, etc.)
- Per-swarm directories (.gastown/swarms/<id>/)
- Swarm manifest/state/events files
- swarm-started/swarm-landed beads

These were redundant - beads already provides hierarchy, status, dependencies, and history.

## References

- Architecture: docs/architecture.md (Key Decision #11, Multi-Wave Work Processing)
- PGT: swarm/manager.py, swarm/landing.py (behavioral reference, but ignore swarm ID patterns)


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

Cycle 297: All healthy, refinery busy


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

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


mol-deacon-patrol


Phase 1: Core messaging primitives (@group, list:, queue:)

## Scope

Core messaging infrastructure that enables multi-recipient and work-queue patterns.

### Deliverables

1. **Config directory structure** - ~/gt/config/ with lists.json, queues.json
2. **@group dynamic resolution** - Filesystem scan for agent directories
   - @rig/gastown → scan gastown/ for agents
   - @town → scan all rigs
   - @witnesses, @crew/gastown, etc.
3. **list:name static lookup** - Fan-out to N copies (each recipient gets work item)
4. **queue:name with claim** - Shared storage, atomic claim via bd update --claim
5. **Fan-out at send time** - gt mail send handles expansion

### Key semantics
- @group and list: both fan out (N copies, N obligations)
- queue: shared copy, first-to-claim wins
- All resolve at send time, not receive time


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 8: all quiet


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)


Merge: dementus-1767081113622

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


Digest: mol-deacon-patrol

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


Phase 5: Integration and Demo

$(cat /tmp/phase5.md)


Move disk 1: A → B

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


HOP Foundation: Entity Identity & Federation

Foundation work for HOP graph architecture. Enables agent provenance tracking, cross-workspace federation, and delegation semantics. See ~/gt/docs/hop/GRAPH-ARCHITECTURE.md for full design.


Digest: mol-deacon-patrol

Patrol 5 complete. All healthy.


Digest: mol-deacon-patrol

Patrol complete: checked inbox, closed convoy hq-qrfz4, all agents healthy, no orphans


Move disk 1: C → A

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


Move disk 2: C → B

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


Design org formula hierarchy pattern

Design how organizational formula hierarchies work.

## Pattern

    company-base.formula.yaml (org-wide policies)
      └── team-frontend.formula.yaml (extends company-base)
           └── project-dashboard.formula.yaml (extends team-frontend)

## Key Questions

1. How are org formulas discovered? (search path? explicit import?)
2. How do aspects merge across levels?
3. Can child override parent aspects?
4. How to handle aspect conflicts?

## Proposed Design

- Formulas use extends: just like today
- Aspect lists merge (child appends to parent)
- Child can exclude parent aspects via "exclude-aspects: [name]"
- Search path: local -> rig -> org (configurable)

## Deliverables

1. Document pattern in docs/formula-inheritance.md
2. Define conflict resolution rules
3. Identify implementation tasks


Digest: mol-deacon-patrol

Patrol cycle 6: Routine.


Move disk 1: B → C

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


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.

```bash
# For each rig with polecats
for rig in gastown beads; do
    gt polecats $rig
    # For each working polecat, check if Claude is ready
    # Use tmux capture-pane to look for "> " prompt
done
```

For each ready polecat that hasn't been triggered yet:
1. Send "Begin." to trigger UserPromptSubmit hook
2. The hook injects mail, polecat sees its assignment
3. Mark polecat as triggered in state

Use WaitForClaudeReady from tmux package (polls for "> " prompt).
Timeout: 60 seconds per polecat. If not ready, try again next cycle.


Check own context limit

Check own context limit.

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

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

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

This enables the Deacon to burn and respawn cleanly.


Digest: mol-deacon-patrol

Patrol 6: 9 sessions healthy


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


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


Add org formula examples and tests

Create example organizational formula hierarchy and tests.

## Examples

Create in .beads/formulas/:
- acme-base.formula.yaml: Company-wide (security-audit aspect)
- acme-frontend.formula.yaml: extends acme-base, adds accessibility-audit
- acme-backend.formula.yaml: extends acme-base, adds sql-injection-scan

## Tests

1. Three-level inheritance resolves correctly
2. Aspect merge order is correct
3. exclude-aspects removes parent aspect
4. Cooking org formula produces expected steps
5. Error on missing parent formula


Witness: auto-nuke polecats after merge

## Problem
Polecats linger after merge. Manual cleanup required.

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

```toml
[[step]]
id = "cleanup-merged-polecats"
title = "Remove polecats after merge"
description = """
1. Check inbox for MERGED messages from refinery: gt mail inbox
2. For each MERGED notification:
   - Extract polecat name from message
   - Verify branch is actually gone: git branch -r | grep polecat/<name>
   - Kill session if running: tmux kill-session -t gt-<rig>-<polecat>
   - Remove worktree: gt polecat remove <rig>/<polecat> --force
   - Delete the MERGED mail
3. Log cleanup in state.json
"""
depends_on = ["check-ready-branches"]
```

## Why This Works
- Witness agent receives MERGED signal from refinery (mail)
- Agent verifies before acting (checks branch really gone)
- Agent runs gt/tmux commands
- No daemon code

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


Digest: mol-deacon-patrol

Patrol 7: All healthy


Digest: mol-deacon-patrol

Patrol OK: town quiet


Digest: mol-deacon-patrol

P15: stable


Digest: mol-deacon-patrol

Patrol 17


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 11: All healthy


Digest: mol-deacon-patrol

Patrol 78: Routine


Digest: mol-deacon-patrol

Patrol 2: All healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 17: All clear


mol-deacon-patrol


Move disk 1: A → B

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


gt up: set BD_ACTOR env var when spawning agents

When gt spawns agents (polecats, crew, patrol roles), it should set BD_ACTOR env var so that bd commands (like `bd hook`) know the agent identity.

Currently gt sets GT_ROLE but bd can't check that (no coupling to gt). bd already checks BD_ACTOR, so gt just needs to set it.

Places to update:
- `gt up` for polecats/crew
- Deacon, Witness, Refinery spawning
- Any other agent spawn points

Related: closed bd-fej5 in beads repo as obsolete (fix belongs here).


Move disk 3: C → A

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


Test message

Testing GGT mail via beads


Move disk 3: B → C

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


Digest: mol-deacon-patrol

Patrol 90: All healthy


Move disk 2: B → A

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


Add isQueueAddress() and parseQueueName() helpers to router.go

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

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

IMPLEMENTATION:
1. Add isQueueAddress(address string) bool - returns true if address starts with 'queue:'
2. Add parseQueueName(address string) string - extracts queue name after 'queue:'

FILE: internal/mail/router.go
TESTS: Add tests in internal/mail/router_test.go following the pattern of TestIsListAddress/TestParseListName

This is a small, focused task. Do not implement sendToQueue or claiming - just the address detection.


Session test with rig


Digest: mol-deacon-patrol

P18: stable