Witness Arm Bonding

# Witness Patrol Redesign

> **Status**: Design pivoted from Christmas Ornament to linear patrol (Dec 2024)

## Original Problem

Witness needs to monitor and intervene on multiple polecats. Original design proposed "Christmas Ornament" pattern with dynamic arms per polecat and fanout gates.

## Design Pivot: Why Christmas Ornament Was Wrong

The Christmas Ornament pattern (dynamic mol-polecat-arm per worker) felt un-Gas-Town:

1. **Explicit state tracking**: Nudge counts, timestamps, per-polecat state
2. **Complex machinery**: Dynamic bonding, fanout gates, aggregation
3. **Against philosophy**: Gas Town prefers discovery over tracking, events over state

**Key insight**: With step-based polecat sessions (`gt mol step done` restarts session each step), polecats are either working a step or starting a step. "Nudge counts across sessions" becomes less meaningful.

## New Design: Linear Patrol + Task Tool Parallelism + Cleanup Wisps

### Patrol Shape (Deacon-style)

```
inbox-check -> process-cleanups -> check-refinery -> survey-workers -> context-check -> loop
```

No dynamic arms. No fanout gates. Linear and simple.

### Key Changes

| Aspect | Old (Christmas Ornament) | New (Linear Patrol) |
|--------|--------------------------|---------------------|
| Per-polecat inspection | mol-polecat-arm bonded dynamically | Task tool subagents within survey-workers |
| State tracking | Persistent nudge counts in handoff bead | Fresh observation each cycle (discover from beads timestamps) |
| Cleanup queue | Explicit list in patrol state | Cleanup wisps (finalizer pattern) |
| Parallelism | Molecule arms (fanout gate) | Task tool subagents |
| Aggregation | waits_for: all-children | Task tool returns |

### The Finalizer Pattern (Cleanup Wisps)

When POLECAT_DONE arrives, Witness creates a cleanup wisp:
```bash
bd create --wisp --title "cleanup:ace" --labels cleanup,polecat:ace
```

The wisp's existence IS the pending cleanup. Witness processes these in `process-cleanups` step:
- Verify git clean, issue closed, commits exist
- Kill session, remove worktree
- Burn the wisp

Failed cleanups? Leave wisp, retry next cycle. GC-style finalization.

### Task Tool Parallelism

Instead of molecule arms, use Claude's Task tool for parallel polecat inspection:

```markdown
## survey-workers step

For each polecat, launch a Task tool subagent:
- Capture tmux state
- Assess working/idle/error/done
- Check beads for step progress
- Decide and execute action (nudge/escalate/none)

Task tool handles parallelism. No molecule machinery needed.
```

## Implementation

- [x] Draft mol-witness-patrol-v2.formula.toml (linear patrol)
- [ ] Test new patrol formula
- [ ] Deprecate mol-polecat-arm
- [ ] Remove fanout gate dependency

## Files

- `.beads/formulas/mol-witness-patrol-v2.formula.toml` - New linear patrol
- `.beads/formulas/mol-witness-patrol.formula.toml` - Old Christmas Ornament (to deprecate)

## Success Criteria

- Witness patrols work with 3+ polecats using Task tool parallelism
- Cleanup wisps correctly track pending cleanups
- No persistent nudge state - fresh observation each cycle
- Simpler, more Gas Town-y design


Digest: mol-deacon-patrol

Patrol 14: healthy


Patrol System: Agent lifecycle loops with attachments

Enable Gas Town agents to run continuous patrols, survive crashes, and hand off work across sessions.

## Core Concepts
- **Attachments**: Molecules bound to agent's pinned bead until complete
- **Patrols**: Cyclic molecules that loop (deacon, witness, refinery)
- **Quiescent**: Agents that sleep until triggered (witness, refinery)

## Design Doc
See docs/patrol-system-design.md

## Phases
Phase 1: Foundation (attachment field, daemon detection, mol-deacon-patrol)
Phase 2: Quiescent Agents (wake triggers, witness/refinery patrols)
Phase 3: Callbacks and Plugins (mail protocol, plugin runner)
Phase 4: Polish (gt patrol status, metrics, tuning)

## Key Decisions
- Attachment as field on pinned bead (not edge type, for now)
- Mail-based orchestration for all callbacks
- Queue replacement for heartbeat delivery (not pile-up)
- Burn and respawn for patrol loops (not in-place reset)


Digest: mol-deacon-patrol

Patrol 20: Routine - handoff threshold reached


gt-gastown-polecat-keeper

gt-gastown-polecat-keeper

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


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-5glf
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


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


Resource Beads: Leases, locks, and quotas

Resource beads represent reserved resources. Types: vm, lock, slot, quota. Fields: holder, expires, renewable. Daemon monitors for expiry and manages contention.


Phase 3.2: mol-polecat-work squash step

Add summary+squash as final steps in mol-polecat-work.

## Current Steps

1. read-assignment
2. understand-task
3. implement-solution
4. verify-tests
5. commit-work
6. signal-done

## Updated Steps

1. read-assignment
2. understand-task
3. implement-solution
4. verify-tests
5. commit-work
6. **generate-summary** ← NEW
7. **squash-molecule** ← NEW
8. signal-done

## Step Definitions

### generate-summary
Agent writes a concise summary following the template.
Save to a local variable or temp file.

### squash-molecule
Run: bd squash $MOLECULE_ROOT --summary "$SUMMARY"
This creates digest in main beads, cleans ephemeral.

## Update Location

This requires updating the mol-polecat-work definition in beads molecule catalog.


BUG: gt done doesn't push branch to origin - work lost when worktree deleted

## Problem

`gt done` creates a merge-request record in beads but **never pushes the branch to origin**.

When polecats are cleaned up (worktrees deleted), the branch is lost forever. The MR record exists but there's no actual branch to merge.

## Evidence

12 MQ items had `ready` status but no corresponding branches on origin. All polecat worktrees were deleted, losing all work.

## Impact

**CRITICAL**: All polecat work is silently lost unless polecats manually push (which they don't know to do).

## Fix

In `done.go`, before creating the MR:
1. `git push origin <branch>` to push the branch to remote
2. Only create MR record if push succeeds

## Location
`mayor/rig/internal/cmd/done.go:124-135`


Digest: mol-deacon-patrol

Patrol 11: all healthy


Digest: mol-deacon-patrol

Patrol complete: checked inbox (0 msgs), health check passed (all rigs healthy), cleaned 3 stale locks


Hook system for event extensibility

GGT needs hook system for extensibility like PGT.

## Event Types
```go
type Event string
const (
    EventPreSessionStart  Event = "pre-session-start"
    EventPostSessionStart Event = "post-session-start"
    EventPreShutdown      Event = "pre-shutdown"
    EventPostShutdown     Event = "post-shutdown"
    EventOnPaneOutput     Event = "on-pane-output"
    EventSessionIdle      Event = "session-idle"
    EventMailReceived     Event = "mail-received"
    EventWorkAssigned     Event = "work-assigned"
)
```

## Hook Configuration
File: .claude/hooks.json or .gastown/hooks.json
```json
{
  "hooks": {
    "pre-shutdown": [
      {"type": "command", "cmd": "./scripts/pre-shutdown.sh"}
    ],
    "on-pane-output": [
      {"type": "command", "cmd": "./scripts/activity-monitor.sh"}
    ]
  }
}
```

## Hook Types
1. **Command**: Execute external script
2. **Built-in**: Internal Go functions (pre-shutdown checks)

## Hook Interface
```go
type HookRunner struct {
    config *HookConfig
}

type HookResult struct {
    Success bool
    Message string
    Block   bool  // For pre-* hooks: should operation be blocked?
}

func (r *HookRunner) Fire(event Event, ctx *HookContext) []HookResult
```

## CLI Commands
```
gt hooks list [<event>]    # List registered hooks
gt hooks fire <event>      # Manually fire for testing
gt hooks test [--all]      # Validate hook config
```

## Integration Points
- internal/session/manager.go: Fire pre/post session hooks
- internal/mail/router.go: Fire mail-received hook

## New Package
internal/hooks/
├── types.go    # Event, HookConfig, HookResult
├── runner.go   # HookRunner, Fire()
└── builtin.go  # Built-in hooks (pre-shutdown checks)

## PGT Reference
gastown-py/src/gastown/hooks/

## Acceptance Criteria
- [ ] Hook config loading from JSON
- [ ] Command hooks execute subprocess
- [ ] Pre-shutdown hook integration with session stop
- [ ] CLI for listing and testing hooks


gt mq list: show queue with status/priority/age

Implement 'gt mq list' command to display the merge queue.

Output format:
ID          STATUS       PRIORITY  BRANCH                    WORKER  AGE
gt-mr-001   ready        P0        polecat/Nux/gt-xyz        Nux     5m
gt-mr-002   in_progress  P1        polecat/Toast/gt-abc      Toast   12m
gt-mr-003   blocked      P1        polecat/Capable/gt-def    Capable 8m
            (waiting on gt-mr-001)

Options:
- --ready: show only ready-to-merge (no blockers, not in progress)
- --status STATUS: filter by status
- --worker WORKER: filter by worker
- --epic EPIC: show MRs targeting integration/EPIC

Under the hood: bd list --type=merge-request with filters.

Reference: docs/merge-queue-design.md#gt-mq-list


Create molecules catalog directory structure

Establish the proto catalog at ~/gt/molecules/.

## Structure

```
~/gt/molecules/
├── README.md           # Catalog overview
├── lifecycle/
│   ├── gastown-boot/
│   │   └── PROTO.md    # Proto definition in markdown
│   ├── rig-spinup/
│   ├── rig-spindown/
│   └── agent-restart/
├── patrol/
│   ├── deacon-patrol/
│   ├── witness-patrol/
│   └── refinery-patrol/
└── work/
    ├── polecat-work/
    ├── code-review/
    └── feature/
```

## PROTO.md Format

```markdown
---
type: lifecycle
parallel: [ensure-witnesses, ensure-refineries]
ephemeral: true
---

# mol-gastown-boot

Town bootstrap molecule.

## Step: ensure-daemon
...
```

## Catalog Loading

`gt sling gastown-boot` should find the proto by:
1. Check beads for existing proto issue
2. If not found, scan ~/gt/molecules/lifecycle/gastown-boot/
3. Auto-create proto issue from PROTO.md

This enables file-based proto development with beads tracking.


Review: Refinery patrol template changes (gt-qz2l)

Polecat dementus implemented refinery template changes: banners, wisp-based execution, propulsion protocol. Review for correctness and consistency with witness/deacon patterns.


Recovery: Detect orphaned merged polecats

Safety net for when Refinery misses sending lifecycle notification.

## Detection Points

**Witness polecat-scan**:
- For each polecat in `mr_submitted` state:
  - Check MR status: `gt mq status <mr-id>`
  - If MR is closed/merged but polecat state is still mr_submitted:
    - Update polecat state to `merged`
    - Log recovery action

**Deacon orphan-check**:
- Query all closed MRs
- Cross-reference with polecat states
- If merged MR but polecat not in merged/retired state:
  - Send correction to Witness
  - Log for metrics (indicates Refinery notification missed)

## Acceptance
- Orphaned polecats detected and corrected
- Recovery is logged for monitoring
- No work lost due to missed notifications


Polecat template not found for non-gastown rigs

When adding a polecat to beads rig, warning shows:
  Warning: polecat template not found at /Users/stevey/gt/beads/mayor/rig/templates/polecat-CLAUDE.md

The template lookup should check the rig's template location, or fall back to a town-level default.


Day 5.0: gt status shows pinned role beads and slots

Enhance gt status to display:
- All pinned role beads (mayor, witness, refinery, polecats)
- Their current hook slot contents (what molecule/bead is attached)
- Agent state if available

This gives a single-command view of who's working on what across the town.

Example output:
```
gt status

Town: gastown
Daemon: running (pid 1234)

Agents:
  mayor/           gt-liftoff (pinned)     idle
  witness/gastown  gt-wisp-abc (patrol)    running
  refinery/gastown (empty)                 idle
  polecat/nux      gt-xyz (in_progress)    working
  polecat/rictus   (empty)                 idle
```


Add charmbracelet TUI dependencies (bubbletea, bubbles)

Add charmbracelet TUI framework dependencies.

## Dependencies to add
```
go get github.com/charmbracelet/bubbletea
go get github.com/charmbracelet/bubbles
```

## Already have
- github.com/charmbracelet/lipgloss (styling)

## Verify
- go mod tidy
- go build ./...

Quick task, just adding deps.


Digest: mol-deacon-patrol

Patrol 17: Quiet


Digest: mol-deacon-patrol

Patrol 19: 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


Test Patrol Parent

[RESURRECTED] This issue was deleted but recreated as a tombstone to preserve hierarchical structure.

Original description:
Test parent for Christmas Ornament pattern


Audit hardcoded 'gastown' references in codebase

## Problem

Gas Town should work for ANY rig - not assume 'gastown' (our OSS project) is installed. Found during audit:

### Known Issue (Closed - gt-ci84)
- Deacon patrol wisps were incorrectly using `gastown/mayor/rig/.beads/` instead of town-level beads
- Status: Fixed (implemented town-level wisp storage)

### Remaining Issues

1. **log.go:272** - Fallback path heuristic:
   ```go
   possibleRoots := []string{
       home + "/gt",
       home + "/gastown",  // <-- Assumes user might have gastown as town
   }
   ```
   Should be removed or use a config-based approach.

2. **Help text examples** - Many commands use 'gastown' as the example rig:
   - `gt sling gt-abc gastown`
   - `gt witness start gastown`
   - etc.
   Consider using a generic name like 'myproject' or '<rig>'

3. **Polecat name pool** - 'gastown' is in the Mad Max themed name list.
   This is acceptable (just a name, not a path assumption).

## Tasks
1. Remove `home + "/gastown"` fallback from log.go
2. Consider updating help examples to use generic rig names
3. Full code audit to ensure no other hardcoded assumptions

## Context
Gas Town is the orchestration framework. 'gastown' is just our OSS project that happens to use it. Users installing Gas Town for their own projects should never see anything that assumes 'gastown' rig exists.


Merge polecat/rictus: Add molecule phase lifecycle diagram

Branch: polecat/rictus

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

Closes: gt-c6zs


Digest: mol-deacon-patrol

Patrol 19: Mayor OK, 11 sessions


Create session name helper functions in internal/session

attached_args: Session name helper functions

Create helper functions for consistent session name construction.

## Files to modify
- internal/session/names.go (NEW)

## Implementation
Create new file with these functions:
```go
package session

import "fmt"

const Prefix = "gt-"

func MayorSessionName() string { return Prefix + "mayor" }
func DeaconSessionName() string { return Prefix + "deacon" }
func WitnessSessionName(rig string) string { return fmt.Sprintf("%s%s-witness", Prefix, rig) }
func RefinerySessionName(rig string) string { return fmt.Sprintf("%s%s-refinery", Prefix, rig) }
func CrewSessionName(rig, name string) string { return fmt.Sprintf("%s%s-crew-%s", Prefix, rig, name) }
func PolecatSessionName(rig, name string) string { return fmt.Sprintf("%s%s-%s", Prefix, rig, name) }
```

## Acceptance criteria
- [ ] New file internal/session/names.go created
- [ ] All 6 helper functions implemented
- [ ] Unit tests in internal/session/names_test.go
- [ ] go build ./... passes
- [ ] go test ./internal/session/... passes


Digest: mol-deacon-patrol

Patrol 12: all healthy


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

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

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

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

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

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

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


Merge: gt-a95

branch: polecat/Ace
target: main
source_issue: gt-a95
rig: gastown


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


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.


Digest: mol-deacon-patrol

Patrol 15: Quiet


Digest: mol-deacon-patrol

Patrol 20: All healthy. Handoff after 20 cycles.


Digest: mol-deacon-patrol

Patrol 19: Routine


gt crew add: Create crew workspace

Implement 'gt crew add <name> [--rig <rig>]' command:
- Clone repo into <rig>/crew/<name>/
- Create feature branch (optional, or stay on main)
- Register for mail delivery
- Initialize CLAUDE.md with crew worker prompting
- Do NOT register with witness (user-managed)


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

Patrol 20: All healthy


Merge: toast-1767074299802

attached_args: Code review this merge request

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


CRITICAL: ProcessMRFromQueue not implemented - Refinery merge logic stubbed

File: internal/refinery/engineer.go:384
The ProcessMRFromQueue() function returns hardcoded failure with TODO comment.
This is a core refinery function that cannot process merges in current state.
Must implement actual merge logic before OSS launch.


Digest: mol-deacon-patrol

Patrol 17: Routine


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.


Digest: mol-deacon-patrol

Patrol cycle 5: all healthy


Sling reports 'already pinned' but mol status shows empty hook

During swarm operations, gt sling reported beads were 'already pinned' but gt mol status showed nothing on the hook.

**Observed:**
```
$ gt sling bd-9btu beads/Nux
Error: bead bd-9btu is already pinned to gt-beads-nux

$ gt mol status beads/Nux
Nothing on hook - no work slung
```

**Expected:**
If a bead is pinned, mol status should show it. If mol status shows empty, sling should work.

**Workaround:**
Used --force flag to re-sling, which worked.

**Root cause hypothesis:**
Agent bead state may be stored in town beads but polecat's local view doesn't see it, or the pin record exists but session state is stale.


MQ dashboard widget: queue status in TUI

Add merge queue status widget to the Bubbletea TUI dashboard.

Display:
┌─────────────────────────────────────────────────┐
│              MERGE QUEUE STATUS                  │
├─────────────────────────────────────────────────┤
│ Pending: 3   In Progress: 1   Merged (24h): 12  │
├─────────────────────────────────────────────────┤
│ QUEUE:                                          │
│   ► gt-mr-004  P0  Nux/gt-xyz     Processing... │
│     gt-mr-005  P1  Toast/gt-abc   Ready         │
│     gt-mr-006  P1  Capable/gt-def Blocked (005) │
└─────────────────────────────────────────────────┘

Interactive features:
- Navigate queue entries
- View MR details
- Retry/reject from dashboard

Depends on: gt-u1j.2 (Bubbletea TUI dashboard)

Reference: docs/merge-queue-design.md#dashboard


Review: Deacon town-level wisp storage (gt-ci84)

Polecat slit implemented town-level wisp storage for deacon patrol. Review the changes to ensure deacon wisps are correctly stored in ~/gt/.beads-wisp/ instead of gastown rig beads.


Digest: mol-deacon-patrol

Patrol 10: routine, halfway


gt mail read: Support numeric indices for message ID

Allow 'gt mail read 1' to read the first message in inbox.

Current behavior requires full message ID like 'msg-abc123'.
Should support:
- Numeric index: 'gt mail read 1' reads first/newest message
- Partial ID match: 'gt mail read abc' matches 'msg-abc123'

This is a UX improvement - agents frequently type 'gt mail read 1'.


Digest: mol-deacon-patrol

Patrol 6: All healthy


Digest: mol-deacon-patrol

Patrol 8: All healthy


gt-mayor

gt-mayor

role_type: mayor
rig: null
agent_state: stopped
hook_bead: null
role_bead: gt-mayor-role
cleanup_status: null


Day 1.4: Create agent beads for core roles

Create agent beads with deterministic IDs:
- gt-mayor (Mayor coordinator)
- gt-witness (per-rig polecat monitor)
- gt-refinery (per-rig merge processor)

Each with role_type, rig, and initial state.

Parent: gt-d0jqp


Auto-handoff: self-cycling with guaranteed work pickup

## Summary

A mechanism for agents to self-cycle: send handoff mail, request Deacon to kill the process, and automatically restart to pick up the work.

## Use Case

User says: `auto-handoff: gt-bug3`

The agent:
1. Sends handoff mail documenting current state
2. Requests Deacon to terminate the session
3. Deacon restarts the agent in background
4. New session picks up the handoff and continues working

When the user returns to terminal, the old session is gone but work continues in background. User can reattach.

## Key Requirements

- **Guaranteed pickup**: Something in the hook and/or handoff must ensure the new session picks up the work (not just a passive "check inbox")
- **Background execution**: Work continues without user presence
- **Reattachability**: User can reconnect to see progress

## Design Questions

1. Can molecules help coordinate this? (e.g., molecule binds the handoff + auto-restart)
2. What hook handles the pickup guarantee?
3. How does Deacon know to restart vs just kill?
4. How does user reattach to a background agent?

## Related

- Molecules system
- Deacon lifecycle management
- Handoff hooks


Document crew worker patrol integration

Document how mol-ready-work integrates with crew worker workflow. Cover: starting the patrol, patrol vs normal operation, backlog configuration, handoff mechanics, discovered work handling. Update CLAUDE.md with patrol section.


Swarm learning: Beads database locality gap

## PGT Bug (GGT Design Already Correct)

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

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

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


Fix TestHasPolecat test failure in internal/session

TestHasPolecat in internal/session/manager_test.go fails because it expects
specific polecats (Toast, Cheedo) to exist in the test environment.

Error:
```
manager_test.go:46: expected hasPolecat(Toast) = true
manager_test.go:49: expected hasPolecat(Cheedo) = true
```

Fix: Either create test fixtures or mock the filesystem check.


Digest: mol-deacon-patrol

Patrol cycle 17: nominal


Digest: mol-deacon-patrol

Patrol #2: Routine - all 6 agents healthy


Digest: mol-deacon-patrol

Patrol cycle 20: final cycle before handoff


Bubbletea TUI dashboard

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


mol-witness-patrol

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

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

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

## The Christmas Ornament Shape

This molecule uses dynamic bonding to create inspection arms per-polecat:

```
                    ★ mol-witness-patrol (trunk)
                   /|\
            ┌─────┘ │ └─────┐
         PREFLIGHT DISCOVERY CLEANUP
            │       │        │
        ┌───┴───┐ ┌─┴─┐  ┌───┴───┐
        │inbox  │ │sur│  │aggreg │
        │refnry │ │vey│  │save   │
        │load   │ └─┬─┘  │summary│
        └───────┘   │    │contxt │
                    │    │loop   │
          ┌─────────┼─────────┐ └───────┘
          │         │         │
          ●         ●         ●     mol-polecat-arm (dynamic)
         ace       nux      toast
          │         │         │
       ┌──┴──┐   ┌──┴──┐   ┌──┴──┐
       │cap  │   │cap  │   │cap  │
       │ass  │   │ass  │   │ass  │
       │dec  │   │dec  │   │dec  │
       │exec │   │exec │   │exec │
       └──┬──┘   └──┬──┘   └──┬──┘
          │         │         │
          └─────────┴─────────┘
                    │
                 ⬣ base (cleanup)
```

## Phases

### PREFLIGHT (fixed steps)
1. inbox-check - Process lifecycle requests, help messages
2. check-refinery - Ensure MQ is alive and processing
3. load-state - Read persistent state (nudge counts, etc.)

### DISCOVERY (spawns dynamic arms)
4. survey-workers - List polecats, bond mol-polecat-arm per polecat
5. run-plugins - Bond mol-plugin-runner for each witness plugin

### CLEANUP (gate + fixed steps)
6. aggregate - GATE: WaitsFor all arms + plugins to complete
7. save-state - Persist nudge counts, action log
8. generate-summary - Create digest content
9. context-check - Check if context is high
10. burn-or-loop - Squash/burn wisp, then loop or exit

## Dynamic Arms

Each polecat gets mol-polecat-arm bonded as a wisp child:
- capture - Capture tmux output
- assess - Categorize state (working/idle/error/done)
- load-history - Get nudge counts for this polecat
- decide - Apply nudge matrix
- execute - Take action (nudge/kill/escalate/none)

Arms run in PARALLEL. The aggregate step waits for all to complete.

## Activity Feed

This design enables real-time visibility:

```
[14:32:08] + patrol-x7k.arm-ace bonded (5 steps)
[14:32:09] → patrol-x7k.arm-ace.capture in_progress
[14:32:10] ✓ patrol-x7k.arm-ace.capture completed
[14:32:14] ✓ patrol-x7k.arm-ace.decide completed (action: nudge-1)
[14:32:17] ✓ patrol-x7k.arm-ace COMPLETE
```

## Storage

- Wisp storage: .beads-wisp/ (ephemeral, gitignored)
- Persistent state: witness handoff bead (nudge counts, etc.)
- Digests: Squashed summaries in permanent beads

## Dependencies

- bd-xo1o: Dynamic Molecule Bonding epic (in beads rig)
  - bd mol bond with variable substitution
  - WaitsFor directive for fanout gates
  - Activity feed query

Labels: [template, christmas-ornament]


Test message

Testing GGT mail system


Digest: mol-deacon-patrol

Patrol 16: Quiet


Test Task 2: Add comment to version.go


Digest: mol-deacon-patrol

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


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

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


Digest: mol-deacon-patrol

Patrol 10: all clear


Digest: mol-deacon-patrol

Patrol cycle 13: nominal


Digest: mol-deacon-patrol

Patrol 8: all quiet


Rig management: discover, load, create rigs

Rig discovery, loading, and creation.

## Interface

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

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

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

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

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

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

## Discovery Logic

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

## Rig Creation

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

## Rig Structure

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


Digest: mol-deacon-patrol

Patrol 5: Routine


Digest: mol-deacon-patrol

Patrol 18


Refinery needs manual restart/handoff mechanism

Refinery sessions can get stuck or need restart. Currently requires manual intervention. Need: 1) gt refinery restart command, 2) Refinery self-handoff on context fill, 3) Auto-recovery from stuck states.


Digest: mol-deacon-patrol

Patrol 1: All healthy, no mail, no action needed


Build rig/worker tree view component

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


Digest: mol-deacon-patrol

Patrol 9: all clear


Digest: mol-deacon-patrol

Patrol #19


Digest: mol-deacon-patrol

Patrol 19: all healthy


ensure-witnesses

Parallel container: Start all rig witnesses.

## Execution
Children execute in parallel. Container completes when all children complete.

## Children
- ensure-gastown-witness
- ensure-beads-witness

## Verify
All child witness steps pass verification.


Digest: mol-deacon-patrol

Patrol 10: All healthy


Digest: mol-deacon-patrol

Patrol 17: nominal


Unify tmux session lifecycle: prefer exec-over-shell pattern

## Context

When `gt crew at` is run from INSIDE the target session, it uses `execClaude()` which
replaces the shell with Claude directly. This is actually preferable behavior:
- Cleaner exit (no intermediate shell prompt)
- More reliable for programmatic worker recycling
- Better UX for humans

But currently this only happens accidentally when you run `gt crew at` while already
in the session at a shell prompt.

## Current behavior

1. Session created: `tmux new-session` starts with shell
2. Claude started via `send-keys` → shell spawns claude as child
3. Exit claude → return to shell → exit shell → session ends

With exec path (only if already in session):
1. `execClaude()` replaces shell with claude
2. Exit claude → session ends (no intermediate shell)

## Desired behavior

Consider making exec-the-shell the DEFAULT for all crew/persistent sessions:
- Spawn session with shell
- Wait for ready
- Use `respawn-pane -k` with claude command (kills shell, starts claude directly)

This gives the cleaner lifecycle without requiring the user to be inside the session.

## Related

Part of tmux control plane unification - ability to manage workers from any session.


Digest: mol-deacon-patrol

Cycle 9: quiet


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

## Problem

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

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

## Expected Behavior

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

## Reproduction

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

## Root Cause

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

## Fix Options

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


Digest: mol-deacon-patrol

Patrol: 4 msgs (2 blocked on bd mol current, 2 handoffs). 11 polecats, 18 sessions. Swarm in progress.


gt spawn should use bd mol run for molecule attachment

Simplify Gas Town to use bd mol run for work tracking.

## Key Insight
Two distinct mechanisms, not duplicative:

| Mechanism | Purpose | Query |
|-----------|---------|-------|
| **Pinned molecule** (bd mol run) | What am I working on? | `bd list --pinned --assignee=me` |
| **Handoff mail** | Context notes for restart | `gt mail read` (self-addressed) |

The handoff is just **mail to yourself** - optional context notes.
The molecule is **the actual work** - required state.

## Current State (Overengineered)
Gas Town has custom attachment system:
- Permanent "Foo Handoff" pinned beads per identity
- AttachMolecule(pinnedBeadID, moleculeID)
- Attachment fields parsed from description
- Separate from beads pinning

## New Model (Simplified)
Use bd mol run directly:

```bash
# Spawn polecat with molecule
bd mol run mol-polecat-work --var issue=gt-xyz
# This: spawns, assigns to caller, pins root, sets in_progress
```

Query current work:
```bash
bd list --pinned --assignee=gastown/furiosa --status=in_progress
```

Handoff context (when needed):
```bash
gt mail send gastown/furiosa -s "Context notes" -m "Was on step 4..."
```

## Changes Required

### Remove from Gas Town
- AttachMolecule() / DetachMolecule()
- AttachmentFields struct and parsing
- GetAttachment() / SetAttachmentFields()
- Permanent pinned handoff beads per identity
- Daemon attachment detection (checkDeaconAttachment)

### Update gt spawn
```go
// Old: custom molecule instantiation + attachment
// New: just call bd mol run
cmd := exec.Command("bd", "mol", "run", protoID, "--var", "issue="+issueID)
```

### Update gt prime / agent context
```go
// Old: find handoff bead, parse attachment
// New: query for pinned molecule
cmd := exec.Command("bd", "list", "--pinned", "--assignee="+identity, "--status=in_progress", "--json")
```

### Update documentation
- Remove handoff bead attachment docs
- Clarify: handoff = mail, molecule = work
- Update CLAUDE.md templates

## Benefits
1. One system for work tracking (beads)
2. Simpler Gas Town code
3. bd mol squash works naturally
4. Handoff is just mail (already works)

## Related
- gt-3x0z: Wisp Molecule Integration
- gt-rana: Patrol System
- gt-lek6: gt rig reset --stale
- gt-ay1r: gt molecule current


gt nudge: support no-arg invocation with default message

Currently gt nudge requires a message argument:

```
gt nudge <rig/polecat> <message>
```

Would be nice to support:
```
gt nudge <rig/polecat>
```

With a sensible default message like 'nudge' or 'continue' or checking for pending work automatically.


gt spawn --create should auto-add polecat if missing

## Problem

`gt spawn gastown --issue gt-xxx --create` fails if no polecats exist.

## Current Behavior

```
Error: auto-select polecat: no available polecats in rig 'gastown'
```

## Expected Behavior

`--create` should:
1. Create a new polecat if none exist
2. Or create the specified polecat if `gt spawn gastown/NewName --create`

## Workaround

Must manually run `gt polecat add gastown Name` first.

## Principle

Agent UX should be forgiving - if I say spawn with --create, make it work.


Digest: mol-deacon-patrol

Patrol 16: Nominal


Digest: mol-deacon-patrol

Patrol 1: All agents healthy. Clone divergence (zoey/jack) noted for witnesses.


Day 1.5: Create role beads from CLAUDE.md content

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

Each role bead contains priming instructions and default_molecule.

Parent: gt-d0jqp


Digest: mol-deacon-patrol

Patrol 19: Quiet


gt status should show runtime state, not just structure

## Problem
`gt status` shows structural info (which crews exist) but not runtime reality (which sessions are running).

## Current Output
- Shows 'Crews: [dave emma zoey]' but doesn't indicate dave is crashed
- Missing Deacon from output entirely
- Hooks shown but unclear if agents are alive

## Expected
- Show which tmux sessions are actually running
- Indicate crashed/missing sessions with warning
- Include all roles (Mayor, Deacon, Witnesses, Refineries, Crews)
- Distinguish between:
  - Structure: what COULD run
  - Runtime: what IS running

## Example Better Output
```
Agents
   mayor          ✓ running (gt-mayor)
   deacon         ✓ running (gt-deacon)

Rigs
   beads
      witness     ✓ running
      refinery    ✓ running
      crew/dave   ✗ CRASHED (session missing)
      crew/emma   ✓ running
   gastown
      witness     ✓ running
      refinery    ✓ running
      crew/max    ✗ CRASHED (session missing)
```


Doctor framework: Check interface, Result types, Report

Framework for gt doctor health checks.

## Check Interface

```go
type Check interface {
    Name() string
    Description() string
    Run(ctx *CheckContext) *CheckResult
    Fix(ctx *CheckContext) error  // optional auto-fix
    CanFix() bool
}

type CheckContext struct {
    TownRoot string
    RigName  string  // empty for town-level checks
    Verbose  bool
}

type CheckResult struct {
    Status  CheckStatus
    Message string
    Details []string  // additional info
    FixHint string    // suggestion if not auto-fixable
}

type CheckStatus int
const (
    StatusOK CheckStatus = iota
    StatusWarning
    StatusError
)
```

## Report

```go
type Report struct {
    Timestamp time.Time
    Checks    []CheckResult
    Summary   ReportSummary
}

type ReportSummary struct {
    Total    int
    OK       int
    Warnings int
    Errors   int
}

func (r *Report) Print(w io.Writer, verbose bool)
```

## Doctor Runner

```go
type Doctor struct {
    checks []Check
}

func NewDoctor() *Doctor
func (d *Doctor) Register(check Check)
func (d *Doctor) Run(ctx *CheckContext) *Report
func (d *Doctor) Fix(ctx *CheckContext) *Report  // run with auto-fix
```

## Built-in Checks

Town-level (gt-f9x.5):
- ConfigExists, ConfigValid
- StateExists, StateValid
- MayorMailboxExists
- RigsRegistryValid

Rig-level (gt-f9x.6):
- RigCloneExists
- GitExcludeConfigured
- WitnessExists, RefineryExists
- PolecatClonesValid


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


Digest: mol-deacon-patrol

Patrol cycle 7: routine, healthy


Digest: mol-deacon-patrol

Patrol 17: OK


Digest: mol-deacon-patrol

Patrol 15: all healthy


Remove dead code: splitLines first loop, unused methods.

## Dead code locations

### 1. internal/cmd/polecat.go (lines 1093-1106)
splitLines function has unreachable first loop:
```go
func splitLines(s string) []string {
    var lines []string
    for _, line := range filepath.SplitList(s) {  // DEAD: wrong function
        ...
    }
    lines = nil  // Discards above
    for _, line := range strings.Split(s, "\n") {  // This is what runs
        lines = append(lines, line)
    }
    return lines
}
```
**Fix:** Remove first loop and reset.

### 2. internal/townlog/logger.go (lines 277-279)
```go
func (e Event) JSON() ([]byte, error) {
    return json.Marshal(e)
}
```
**Fix:** Remove unused method.

### 3. internal/lock/lock.go (line 27)
```go
ErrStaleLock = errors.New("stale lock detected")
```
**Fix:** Remove unused error variable.

### 4. internal/witness/types.go (line 19)
```go
StatePaused State = "paused"
```
**Fix:** Remove unused state constant.

### 5. internal/refinery/manager.go (lines 527-538)
```go
func (m *Manager) getTestCommand() string { ... }
```
**Fix:** Remove unused method.

## Acceptance criteria
- [ ] polecat.go: Dead loop removed from splitLines
- [ ] townlog/logger.go: Event.JSON() method removed
- [ ] lock/lock.go: ErrStaleLock removed
- [ ] witness/types.go: StatePaused removed
- [ ] refinery/manager.go: getTestCommand removed
- [ ] go build ./... passes
- [ ] go test ./... passes


Crew Role Definition

You are a Crew Worker - a human-managed persistent workspace within a rig.

Unlike polecats which are witness-managed and transient, crew workers are:
- Persistent: Not auto-garbage-collected
- User-managed: Overseer controls lifecycle
- Long-lived identities: Keep your name across sessions
- Gas Town integrated: Mail, handoff mechanics work

default_molecule: null
capabilities:
  - autonomous_work
  - beads_access
  - git_operations
  - mail_communication

## Core Responsibilities

1. Execute assigned work autonomously
2. Track progress via beads (bd commands)
3. Communicate via mail when blocked or complete
4. Maintain clean git state
5. Hand off context when cycling sessions

## Propulsion Principle

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

Hook has work -> Run it. Hook empty -> Check mail. Nothing -> Wait for overseer.

## Session End Protocol

- git status, git add, bd sync, git commit, git push
- gt handoff - hand off to fresh session

## Key Commands

- gt mol status - Check your hook
- bd ready - Find next step
- bd close <id> - Mark work complete
- gt mail inbox - Check messages
- gt handoff - Cycle to fresh session


Digest: mol-deacon-patrol

Patrol 18: All healthy.


implement

Implement the solution for gt-qwyu. 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


Digest: mol-deacon-patrol

Patrol 5: All healthy


Fix blocking bugs (gt-dsfi, gt-n7z7, gm-c6b)

Fix bugs blocking Witness functionality:

1. gt-dsfi: handoff deadlock
   - Polecats hang when trying to exit
   - Blocks shutdown request handler

2. gt-n7z7: refinery foreground race condition
   - Sometimes detects parent as already running
   - Blocks reliable Refinery startup

3. gm-c6b: mail coordination
   - Cross-rig mail should use town-level database
   - Affects Witness <-> Mayor communication

These should be fixed early as they'll block integration testing.

Fixed gt-dsfi and gt-n7z7. Issue gm-c6b not found in database.


Day 2.2: Remove PID/tmux state inference

Remove ZFC violations where Go infers state from signals:
- No more PID file checks
- No more tmux session parsing
- No more branch pattern analysis

Daemon becomes pure transport layer.

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

Parent: gt-d0jqp

Removed PID/tmux state inference from refinery Status(), witness Status(), daemon ensureDeaconRunning(), and daemon pokeDeacon(). Daemon now trusts agent bead state per ZFC. Removed 78 lines of inference code.


Digest: mol-deacon-patrol

Patrol cycle 16: routine


Remove legacy .beads-wisp/ infrastructure

The wisp simplification (gt-fgms + bd-bkul) changed wisps to be just a flag on issues in the main .beads/ database. JSONL export filters Wisp=true issues. No separate directory needed.

But legacy .beads-wisp/ infrastructure still exists and should be removed:

## Gas Town (gt) cleanup:
- `internal/rig/manager.go`: Remove `initWispBeads()` call from `AddRig()`
- `internal/wisp/io.go`: Delete entire file (old abstraction layer)
- `internal/cmd/install.go`: Remove any .beads-wisp setup
- `docs/wisp-architecture.md`: Update to reflect 'just a flag' model

## Beads (bd) cleanup:
- `cmd/bd/doctor/wisp_check.go`: Remove WispExistsCheck, WispGitCheck, WispSizeCheck (check .beads-wisp dirs)
- Keep WispOrphansCheck and WispStaleCheck but rewrite to query main DB for Wisp=true issues

## Filesystem cleanup:
- Delete ~/gt/.beads-wisp/
- Delete ~/gt/gastown/.beads-wisp/
- Delete all per-rig .beads-wisp/ directories
- Remove .beads-wisp from .gitignore entries

## Verify:
- `gt mail send --wisp` still works (creates issue with Wisp=true in main DB)
- `bd sync` still filters wisps from JSONL
- `bd mol squash/burn` still work on Wisp=true issues


CLI: mail commands (send, inbox, read)

CLI: mail commands wrapping bd mail.

## Status

Current implementation works with JSONL files. Refactor to wrap bd mail CLI.

## Commands

### gt mail inbox
```
gt mail inbox [--unread] [--json]
```
Wraps: `bd mail inbox [--json]`

### gt mail read
```
gt mail read <id>
```
Wraps: `bd mail read <id> && bd mail ack <id>`
Note: bd mail read + ack marks as read.

### gt mail send
```
gt mail send <address> -s "Subject" -m "Body" [--notify]
```
Wraps: `bd mail send <recipient> -s "Subject" -m "Body"`
If --notify: inject tmux notification after send.

### gt mail delete
```
gt mail delete <id>
```
Wraps: `bd mail ack <id>` (closes the message issue)

## Address Translation

Same as gt-u1j.6:
- `mayor/` → `mayor`
- `<rig>/refinery` → `<rig>-refinery`
- `<rig>/<polecat>` → `<rig>-<polecat>`

## Dependencies

- gt-u1j.6: Mail system backend


Digest: mol-deacon-patrol

Patrol 6: all clear, agents healthy


Digest: mol-deacon-patrol

Patrol 14: Green


Digest: mol-deacon-patrol

P16: stable


Digest: mol-deacon-patrol

Patrol 20: all healthy, handoff threshold reached


Remove spawn - use pour/wisp only (see bd-8y9t)

Remove bd mol spawn entirely from vocabulary.

Replace all references with:
- bd pour <proto> - Create persistent mol (liquid)
- bd wisp <proto> - Create ephemeral wisp (vapor)

'spawn' doesn't fit the chemistry metaphor. Two phase transitions (pour/wisp) are clearer than one command with flags.

See bd-XXX for Beads-side removal.


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.


Digest: mol-deacon-patrol

Patrol 15: all healthy, doctor pass


Polecat template: condense Work Protocol section

The Work Protocol section summarizes the entire mol-polecat-work molecule. This is too verbose and will go stale as the molecule evolves. Condense to essential guidance only, let the molecule itself provide the steps.


Digest: mol-deacon-patrol

Patrol 11: Quiet


load-context

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

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


Add parallel step support to molecules

Enable steps to run in parallel within a molecule.

## Current State

Molecules have linear step dependencies via "Needs:" directive.
Steps run sequentially.

## Proposed Change

Add parallel grouping:

```markdown
## Step: ensure-witnesses
Parallel: true

### Sub-steps
- ensure-gastown-witness
- ensure-beads-witness
```

Or via frontmatter:

```yaml
---
parallel: [ensure-witnesses, ensure-refineries]
---
```

Steps in parallel group:
- Start simultaneously
- Parent step closes when all children complete
- Failures in one dont block others

## Implementation

1. Parse parallel directive in proto
2. When bonding, create child steps with same dependency
3. Executor spawns parallel children concurrently
4. Track completion, close parent when all done

## For Mayor Bootstrap

Mayor can check all witnesses in parallel, then all refineries,
rather than sequentially. Faster boot time.


Digest: mol-deacon-patrol

Patrol 11: routine


Digest: mol-deacon-patrol

Patrol 17: All healthy.


Swarm state persistence: manifest + state + events

Upgrade swarm persistence to match PGT pattern.

## Current State
Single .gastown/swarms.json with all swarms.

## Target State (per-swarm)
```
.gastown/swarms/
└── <swarm-id>/
    ├── manifest.json  # Immutable config
    ├── state.json     # Mutable progress
    ├── events.jsonl   # Audit log
    └── report.md      # Generated report
```

## File Schemas

### manifest.json (immutable after creation)
```json
{
  "id": "sw-1",
  "title": "Epic description",
  "epic_id": "gt-abc",
  "rig": "gastown",
  "base_commit": "abc123",
  "integration_branch": "swarm/sw-1",
  "target_branch": "main",
  "workers": ["Toast", "Nux"],
  "tasks": [{"id": "gt-xyz", "title": "..."}],
  "created_at": "2024-01-01T00:00:00Z"
}
```

### state.json (mutable)
```json
{
  "state": "active",
  "task_states": {
    "gt-xyz": {"state": "merged", "assignee": "Toast"}
  },
  "updated_at": "2024-01-01T01:00:00Z",
  "error": null
}
```

### events.jsonl (append-only audit)
```jsonl
{"event": "created", "ts": "...", "data": {...}}
{"event": "task_assigned", "ts": "...", "data": {...}}
{"event": "task_merged", "ts": "...", "data": {...}}
```

## Benefits
- Audit trail via events.jsonl
- Manifest immutability prevents corruption
- Cleaner separation of concerns
- Per-swarm isolation

## Migration
Keep backward compat with swarms.json during transition.

## Files to Modify
- internal/swarm/manager.go: Refactor persistence
- internal/cmd/swarm.go: SwarmStore → directory-based

## Acceptance Criteria
- [ ] Per-swarm directory structure
- [ ] Events logged to JSONL
- [ ] Manifest immutable after creation
- [ ] List command aggregates from directories


MVP Takeoff: Polecats just work

## Goal
Get to the point where we can sling any issue to a polecat with a formula and it "just works" end-to-end.

## Success Criteria
1. `gt daemon start` brings up the engine
2. Deacon patrols: inbox, health checks, cleanup
3. Witnesses patrol: monitor polecats, verify completion, cleanup
4. Refineries patrol: process merge queue
5. Polecat lifecycle: spawn → work → complete → cleanup
6. Shiny formula: design → implement → review → test → submit

## What This Enables
- "Engineer in a box" - take any issue, expand via shiny, get a reviewed/tested PR
- Reliable multi-agent coordination
- Self-healing infrastructure (patrols fix problems)

## Blocked By
- gt-ronyn (deacon murder bug) - FIXED
- Basic patrol formulas - DONE (mol-*-patrol.formula.toml exist)

## Children
See linked tasks below.


Digest: mol-deacon-patrol

Patrol 8: all clear


Digest: mol-deacon-patrol

Patrol 10: routine


gt feed: Activity feed command with tmux-aware modes

## Context

`bd activity` exists and works well for streaming beads mutation events. However:
- It's not discoverable via `gt` (the agent coordination CLI)
- No tmux-aware behavior for when Gas Town is running in tmux
- The planned TUI (gt-rivr) was tombstoned - need a simpler approach

## Requirements

### Without tmux (standalone mode)
- `gt feed` streams activity to stdout (like `bd activity --follow`)
- Supports filtering by rig, time window, event type
- Works in any terminal

### With tmux (integrated mode)
- Could open/attach to a dedicated activity pane
- Or provide a way to send feed to a specific pane
- Integrate with existing gt tmux session management

## Design Questions

1. **Command name**: `gt feed` vs `gt activity` vs `gt watch`?
2. **Tmux integration**: Dedicated pane? Split? Popup?
3. **Cross-rig aggregation**: Merge events from multiple rig daemons?
4. **Filtering UX**: By rig, by molecule, by event type?

## Implementation Options

**Phase 1: Simple wrapper**
- `gt feed` shells out to `bd activity --follow`
- Add `--rig` flag for filtering
- Works identically with/without tmux

**Phase 2: Tmux-aware**
- Detect if running in gt tmux session
- Offer to open in dedicated pane
- `gt feed --pane` to force pane mode

**Phase 3: Cross-rig** (if needed)
- Aggregate from multiple rig daemons
- Unified activity stream across town

## Related

- gt-rivr (tombstoned) - Original TUI epic
- gt-22ng - Activity aggregator (blocked)
- bd activity command - The underlying implementation


Digest: mol-deacon-patrol

Patrol 10: all healthy


Polecat template: move startup announcement into molecule

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


Digest: mol-deacon-patrol

Patrol 9: All clear


Merge: nux-1767059693217

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


Witness swarm landing protocol

Witness responsibilities for swarm landing cleanup.

## Trigger

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

## Landing Protocol

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

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

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

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

## Code at Risk Handling

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

## Reference

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


gt mq submit: create MR from current branch

Implement 'gt mq submit' command that creates a merge-request bead.

Auto-detection logic:
1. Branch: current git branch
2. Issue: parse from branch name (polecat/Nux/gt-xyz → gt-xyz)
3. Target: main (or integration branch if --epic specified)
4. Worker: parse from branch name
5. Rig: current rig

Options:
- --branch BRANCH: explicit source branch
- --issue ISSUE: explicit source issue
- --epic EPIC: target integration/EPIC instead of main
- --priority P: override priority (default: inherit from source issue)

Creates merge-request bead and prints MR ID.

Reference: docs/merge-queue-design.md#creating-merge-requests


Digest: mol-deacon-patrol

P6: stable, beads polecats exited


Agent monitoring and status inference

Agent monitoring with status inference from activity, like PGT.

## Agent Status Enum
```go
type AgentStatus string
const (
    StatusAvailable AgentStatus = "available"
    StatusWorking   AgentStatus = "working"
    StatusThinking  AgentStatus = "thinking"
    StatusBlocked   AgentStatus = "blocked"
    StatusWaiting   AgentStatus = "waiting"
    StatusReviewing AgentStatus = "reviewing"
    StatusIdle      AgentStatus = "idle"
    StatusPaused    AgentStatus = "paused"
    StatusError     AgentStatus = "error"
    StatusOffline   AgentStatus = "offline"
)
```

## Status Sources (priority order)
```go
type StatusSource string
const (
    SourceBossOverride StatusSource = "boss"      // Witness/Mayor sets
    SourceSelfReported StatusSource = "self"      // Agent reports own status
    SourceInferred     StatusSource = "inferred"  // Detected from activity
)
```

## Activity Detection

### Pattern Registry
```go
var activityPatterns = []struct {
    Pattern string
    Status  AgentStatus
}{
    {"Thinking...", StatusThinking},
    {"BLOCKED:", StatusBlocked},
    {"Error:", StatusError},
    // etc
}
```

### Idle Detection
No pane output for N seconds → StatusIdle

### Resource Monitoring (optional)
CPU/memory via os.Process

## New Package
internal/monitoring/
├── types.go      # AgentStatus, StatusReport
├── detector.go   # PatternRegistry, detect from output
├── tracker.go    # Per-agent status tracking
└── idle.go       # Idle timeout detection

## Integration
- Session capture output → monitoring detector
- Status shown in gt status, gt session list

## PGT Reference
gastown-py/src/gastown/monitoring/

## Acceptance Criteria
- [ ] Status enum with 10 states
- [ ] Pattern-based detection from pane output
- [ ] Idle detection with configurable timeout
- [ ] Status visible in CLI output


Witness swarm integration

Add swarm coordination to Witness patrol.

The Witness should be able to:
1. Receive swarm assignments via mail (SWARM: subject prefix)
2. Query ready front and dispatch to available polecats
3. Monitor polecat progress on swarm tasks
4. Detect completion and close swarm molecule
5. Use Christmas Ornament pattern for arm-bonding (optional)

Implementation:
- Add swarm handling to mol-witness-patrol formula
- Mail trigger: SWARM in subject
- Dispatch: bd ready --parent=<epic> to find ready issues
- Assign: gt sling <issue> to available polecat
- Monitor: Check polecat status during patrol
- Complete: When bd ready --parent returns empty and all closed

Reference: ~/gt/docs/swarm-architecture.md - Witness Integration section

Dependencies: gt-kc7yj.1 (gt swarm refactor)


Break up long functions in start.go

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

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


Digest: mol-deacon-patrol

Patrol 20: all healthy, new polecats spawning


Digest: mol-deacon-patrol

Patrol 3: all healthy, mayor running, witnesses running


Witness pre-kill verification protocol

Add pre-kill verification protocol to Witness CLAUDE.md template.

## Protocol for Witness Prompting

```markdown
## Pre-Kill Verification Protocol

Before killing any worker session, verify workspace is clean.

### Verification Steps

When a worker signals done:

1. **Capture worker state**:
```bash
town capture <polecat> "git status && git stash list && bd sync --status"
```

2. **Assess the output** (use your judgment):
- Is working tree clean?
- Is stash list empty?
- Is beads synced?

3. **Decision**:
- **CLEAN**: Proceed to kill session
- **DIRTY**: Send nudge with specific issues

### Nudge Templates

**Uncommitted Changes**:
```
town inject <polecat> "WITNESS CHECK: Uncommitted changes found. Please commit or discard: <files>. Signal done when clean."
```

**Beads Not Synced**:
```
town inject <polecat> "WITNESS CHECK: Beads not synced. Run 'bd sync' then commit. Signal done when complete."
```

### Kill Sequence

Only after verification passes:
```bash
town kill <polecat>
town sleep <polecat>
```

### Escalation

If worker fails verification 3+ times:
```bash
town mail send mayor/ -s "Escalation: <polecat> stuck" -m "Cannot complete cleanup after 3 attempts. Issues: <list>."
```
```

## Implementation

Add to WITNESS_CLAUDE.md template.


Remove unused style helper functions

internal/style/style.go defines RenderSuccess, RenderWarning, RenderError, and RenderInfo helper functions that are never used. Code uses style.Success.Render() directly instead. Either use the helpers consistently or remove them.


Standardize session end: gt handoff for all roles

## Summary

Standardize session ending across all agent roles to use `gt handoff` as the canonical command. This is critical for the beads propulsion cycle - turning agent sessions from pets into cattle.

## Current State (Inconsistent)

| Role | Current Guidance | Command |
|------|-----------------|---------|
| Mayor | Manual mail send | `gt mail send mayor/ -s 'HANDOFF:...' -m '...'` |
| Crew | Manual mail send | `gt mail send <rig>/crew/<name> -s 'HANDOFF:...' -m '...'` |
| Witness | Manual mail send | `gt mail send <rig>/witness -s 'HANDOFF:...' -m '...'` |
| Refinery | Manual mail send | `gt mail send <rig>/refinery -s 'HANDOFF:...' -m '...'` |
| Deacon | Exit on high context | (implicit) |
| Polecat | `gt done` | `gt done [--exit TYPE]` |

## Target State (Unified)

All roles use `gt handoff`:
- `gt handoff` - Hand off current session to fresh instance
- `gt handoff -s 'context' -m 'details'` - Hand off with custom message
- For polecats: `gt handoff` internally calls `gt done`

## Changes Required

### 1. Code Changes
- [ ] Update `gt handoff` to detect polecat role and call `gt done` internally
- [ ] Consider adding `--exit` flag to `gt handoff` for polecat compatibility

### 2. CLAUDE.md Updates (gastown)
- [ ] ~/gt/CLAUDE.md (Mayor)
- [ ] gastown/crew/max/CLAUDE.md
- [ ] gastown/crew/joe/CLAUDE.md
- [ ] gastown/witness/CLAUDE.md
- [ ] gastown/refinery/CLAUDE.md (and rig/)
- [ ] deacon/CLAUDE.md

### 3. CLAUDE.md Updates (beads)
- [ ] beads/mayor/rig/CLAUDE.md
- [ ] beads/crew/dave/CLAUDE.md
- [ ] beads/crew/zoey/CLAUDE.md
- [ ] beads/witness/CLAUDE.md
- [ ] beads/refinery/CLAUDE.md (and rig/)

### 4. Architecture Docs
- [ ] docs/patrol-system-design.md
- [ ] gastown/mayor/rig/docs/prompts.md
- [ ] gastown/mayor/rig/docs/session-management.md

## New Session End Checklist (Universal)

```
# SESSION CLOSE PROTOCOL

[ ] 1. git status              (check uncommitted changes)
[ ] 2. git add <files>         (stage changes)
[ ] 3. git commit -m '...'     (commit with issue ID)
[ ] 4. bd sync                 (sync beads)
[ ] 5. git push                (push to remote - CRITICAL)
[ ] 6. gt handoff              (hand off to fresh session)
       OR gt handoff -s 'Context' -m 'Details for next session'
```

## Why This Matters

The handoff mechanism is what turns agent sessions from **pets** (precious, long-lived) into **cattle** (disposable, replaceable). At any time, any agent can:
1. Send itself a detailed handoff mail (or sling itself a mol)
2. System shuts them down and restarts them
3. Fresh session runs priming and reads mail
4. Work continues seamlessly

This enables:
- Unlimited context through automatic cycling
- Clean recovery from any state
- Consistent behavior across all roles
- Simplified agent instructions


Day 3.3: Witness sends MERGE_READY to refinery

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

Parent: gt-hwka3


Create PolecatArmMolecule() for per-polecat inspection

Add PolecatArmMolecule() to builtin_molecules.go.

Steps:
- capture: Capture tmux output
- assess: Categorize state
- load-history: Get nudge counts
- decide: Apply nudge matrix
- execute: Take action

Uses variable substitution:
- {{polecat_name}}
- {{rig}}

This proto is bonded dynamically by survey-workers step.


Document merge queue architecture

Update docs/architecture.md with:

- Merge Queue section explaining Beads-native approach
- Engineer role (renamed from Refinery)
- Session restart protocol
- gt mq command reference
- Federation considerations for queue

Also update any references to .gastown/ → config/.


Digest: mol-deacon-patrol

Patrol 10: OK


Digest: mol-deacon-patrol

Patrol 11: Nominal


Success handling: close MR, close source issue, cleanup

Handle successful merge completion.

Steps:
1. Update MR with merge_commit SHA:
   bd update <id> --body='...\nmerge_commit: <sha>'
2. Close MR with reason:
   bd close <id> --reason='merged'
3. Close source issue (the work item):
   bd close <source_issue> --reason='Merged in <mr_id>'
4. Delete source branch (if configured):
   git push origin --delete <mr.branch>
5. Log success

Configuration:
- delete_merged_branches: bool (default true)

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


Digest: mol-deacon-patrol

P14: stable


Digest: mol-deacon-patrol

Patrol 13: Quiet


VM outpost setup: Terraform and documentation

## Overview

Documentation and optional Terraform for setting up VM outposts.

## Manual Setup Guide

```markdown
# Setting Up a VM Outpost

## Prerequisites
- GCE VM (or any Linux machine with SSH access)
- SSH key pair
- Git configured on VM

## Steps

1. Install Claude Code on VM:
   ```bash
   ssh user@vm
   npm install -g @anthropic-ai/claude-code
   ```

2. Clone Gas Town:
   ```bash
   mkdir -p ~/ai
   cd ~/ai
   gt install .
   ```

3. Configure Git credentials:
   ```bash
   git config --global user.name "Your Name"
   git config --global credential.helper store
   ```

4. Add outpost to local config:
   ```bash
   gt outpost add ssh \
     --name gce-burst \
     --host 10.0.0.5 \
     --user steve \
     --key ~/.ssh/gce_worker \
     --town-path /home/steve/ai \
     --max-workers 8
   ```

5. Test connectivity:
   ```bash
   gt outpost ping gce-burst
   ```
```

## Terraform Module (Optional)

```hcl
# deploy/terraform/vm-outpost/main.tf

variable "project" {}
variable "zone" { default = "us-central1-a" }
variable "machine_type" { default = "e2-standard-4" }

resource "google_compute_instance" "outpost" {
  name         = "gastown-outpost"
  machine_type = var.machine_type
  zone         = var.zone

  boot_disk {
    initialize_params {
      image = "ubuntu-2204-lts"
      size  = 100
    }
  }

  network_interface {
    network = "default"
    access_config {}
  }

  metadata_startup_script = file("${path.module}/startup.sh")
}

output "external_ip" {
  value = google_compute_instance.outpost.network_interface[0].access_config[0].nat_ip
}
```

## Files

- `docs/vm-outpost-setup.md`
- `deploy/terraform/vm-outpost/` (optional)

Depends on: gt-9a2.5 (SSHOutpost)


Create activity aggregator

Component that connects to multiple rig beads daemons and merges their activity into a unified view. Polls GetMutations and GetWorkerStatus from each rig, groups by rig/worker. Handles connection failures gracefully.

BLOCKED BY (Beads rig):
- bd-gqxd: Enrich MutationEvent with title and assignee
- bd-l13p: Add GetWorkerStatus RPC endpoint
- bd-0oqz: Add GetMoleculeProgress RPC endpoint


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.


Digest: mol-deacon-patrol

Patrol cycle 2: quick scan, no changes


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.


Condition evaluator for gates and loops

Implement mechanical condition evaluation:
- step.status == 'complete'
- step.output.field == value
- children(step).all(status == 'complete')
- file.exists(path), env.VAR

Keep decidable: no arbitrary code, bounded evaluation.


Automatic spawn for ready work

Auto-spawn polecats for ready work:

When Witness has capacity (active_workers < max_workers):
1. Query bd ready for unblocked issues
2. Filter to rig-appropriate work (by prefix or epic)
3. For each ready issue up to capacity:
   - gt spawn --issue <id>
   - Track that we spawned for this issue

Configuration (in rig config.json):
- max_workers: 4 (default)
- spawn_delay: 5s between spawns
- auto_spawn: true/false

This enables 'fire and forget' swarming:
- Mayor creates epic with children
- Mayor tells Witness to work epic
- Witness spawns polecats automatically
- Witness cleans up as they complete


Digest: mol-deacon-patrol

Patrol 11: All clear


Digest: mol-deacon-patrol

Patrol 2: All healthy, no events


Digest: mol-deacon-patrol

Patrol 14: clear


Add hook-singleton doctor check

Add gt doctor check to ensure each agent has at most one handoff bead.

Check: hook-singleton
Error if: Multiple pinned beads with same '{role} Handoff' title
Fix suggestion: Delete duplicate(s) with bd close


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)


Test Epic: GGT MVP Validation


Handle callbacks from agents

Handle callbacks from agents.

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

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

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


Digest: mol-deacon-patrol

Patrol 11: All healthy


Merge: gt-0ei3

branch: polecat/capable
target: main
source_issue: gt-0ei3
rig: gastown


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-wewf
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


MQ Submit: Notify Witness on MR submission

When `gt mq submit` is run, notify the Witness so it can verify the submission.

## Implementation

1. In mq_submit.go after successful MR creation:
   ```
   gt mail send <rig>/witness -s "LIFECYCLE: mr submitted" -m "
   Worker: <polecat>
   MR: <mr-id>
   Branch: <branch-name>
   Target: <target-branch>
   Action: Verify MR submission, help polecat if needed.
   "
   ```

2. This happens BEFORE the existing polecat auto-cleanup logic

## Acceptance
- MR submission sends notification to Witness
- Witness receives mail with all relevant details
- Works for both polecat and crew submissions


Digest: mol-deacon-patrol

Patrol complete: no inbox, no polecats, cleaned 3 stale locks, witnesses/refineries intentionally stopped


Create mol-gastown-polecat derived molecule

Create the standard Gas Town polecat workflow molecule.

## Molecule Definition
\`\`\`markdown
## Molecule: gastown-polecat
Full workflow for Gas Town polecats including binary installation.

Includes: mol-engineer-in-box

## Step: install-binary
After merge is submitted, rebuild and install the local gt binary.
This ensures the latest code is available to all local agents.

Run from the rig directory:
\`\`\`
go build -o gt ./cmd/gt
go install ./cmd/gt
\`\`\`

Needs: submit
\`\`\`

## Why This Molecule
Every polecat that pushes to main should also rebuild the binary.
This ensures the installed gt is always current with main.

## Implementation
1. Add to builtin_molecules.go (after Includes support lands)
2. Update SeedBuiltinMolecules
3. Run gt molecule seed

## Acceptance
- [ ] mol-gastown-polecat exists
- [ ] Includes all engineer-in-box steps
- [ ] Adds install-binary step after submit
- [ ] Can be used with gt spawn --molecule


Merge: gt-8v8

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


Add WaitsFor parsing to molecule steps

Add WaitsFor field to MoleculeStep struct and parse 'WaitsFor: all-children' (and future variants) from molecule descriptions.

This enables:
- mol progress to understand fanout patterns
- Validation that WaitsFor references valid constructs
- Future automated orchestration

Implementation:
1. Add WaitsFor []string to MoleculeStep struct
2. Add waitsForLineRegex to parse 'WaitsFor: ...' lines
3. Update ParseMoleculeSteps to extract WaitsFor
4. Update tests


Digest: mol-deacon-patrol

Patrol 11: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 4: All agents healthy, routine


Merge: morsov-1766966180179

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


Multiple merge/landing models documented without clarification

Architecture describes three different merge models:

1. Refinery-only model (traditional)
2. Direct landing model (Mayor bypass)
3. Swarm integration branch model (internal/swarm)

These appear to conflict. Documentation should clarify:
- Which model is canonical?
- When to use which model?
- Or are some deprecated?

This is confusing for users trying to understand the system.


Process witness mail

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.


Consolidate molecular-chemistry.md with rig-cook-run.md

Merge rig-cook-run.md into molecular-chemistry.md as the canonical chemical algebra spec:
- Rig/Cook/Run as the lifecycle backbone
- Full generation graph: Formula → Compound Formula → Proto → Mol/Wisp
- Bond table at artifact level (symmetric)
- Rig operator at source level
- Unified vocabulary
- Archive or redirect rig-cook-run.md


Digest: mol-deacon-patrol

Patrol 4: all quiet


Digest: mol-deacon-patrol

Patrol #5: Routine - 6 sessions healthy


Merge: nux-1767073376184

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


Digest: mol-deacon-patrol

Patrol 12: all clear


Merge: keeper-1767074342207

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


Digest: mol-deacon-patrol

P17: stable


Digest: mol-deacon-patrol

Patrol 9: All healthy.


Refinery semantic merge processing loop

Implement the Refinery semantic merge loop for processing polecat work.

## Overview

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

## Processing Loop

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

## Semantic Merge

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

## Daemon Poking

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

## Dependencies

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

## Reference

See PGT ephemeral.py for branch operations.


Digest: mol-deacon-patrol

Patrol 8: all healthy


Digest: mol-deacon-patrol

P16: stable


Digest: mol-deacon-patrol

Patrol complete: 2 mayor handoffs (not for deacon), all agents healthy, no orphans


Configuration in Beads: use pinned beads for rig/agent config

## Summary

Move configuration from JSON files into Beads data plane using pinned beads.

## Motivation

- Config becomes versionable and syncable like issues
- Agents can read config via `bd show`
- Unified data model for everything
- Supports the 'Beads as Universal Data Plane' vision (gt-aqm)

## Config Types to Migrate

### Rig-level (pinned per rig)
- Theme/colors for tmux status line
- Default branch naming conventions
- Merge queue settings
- Witness thresholds

### Agent-level (pinned per role)
- Handoffs (already planned - gt-cu7r)
- Agent preferences
- Current focus/context

### Town-level (pinned at town root)
- Cross-rig settings
- Federation config
- Global themes

## Implementation

1. Implement StatusPinned (beads-6v2) ✓ in progress
2. Create config pinned beads on rig init
3. Add `bd config get/set` commands that read/write pinned beads
4. Migrate existing config.json fields

## Naming Convention

```
<prefix>-cfg-<scope>
gt-cfg-theme      # gastown theme
bd-cfg-merge      # beads merge settings
gm-cfg-town       # town-level config
```

## Dependencies

- beads-6v2: Add StatusPinned to beads schema
- gm-w13: Pinned Beads epic


Digest: mol-deacon-patrol

Patrol 2: all healthy, no incidents


gt mq status: detailed MR view

Implement 'gt mq status <id>' command for detailed MR view.

Display:
- All MR fields (branch, target, source_issue, worker, rig)
- Current status with timestamps
- Dependencies (what it's waiting on)
- Blockers (what's waiting on it)
- Processing history (attempts, failures)

Under the hood: bd show <id> with MR-specific formatting.

Reference: docs/merge-queue-design.md#command-details


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


Fetch and conflict check: git operations for MR

Implement git operations for MR processing.

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

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

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


Witness daemon: heartbeat loop, spawn ephemeral agent

Background daemon for agent lifecycle and monitoring.

## Core Responsibilities

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

## Session Lifecycle (Witness Protection)

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

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

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

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

## Interface

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

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

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

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

## Heartbeat Loop

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


Digest: mol-deacon-patrol

Patrol 16: All agents healthy


LocalConnection: Local file/exec/tmux operations

LocalConnection implementation for local machine operations.

## Implementation

```go
type LocalConnection struct {
    tmux *Tmux
}

func NewLocalConnection() *LocalConnection

func (c *LocalConnection) Name() string { return "local" }
func (c *LocalConnection) IsLocal() bool { return true }
```

## File Operations

Direct passthrough to os package:
```go
func (c *LocalConnection) ReadFile(path string) ([]byte, error) {
    return os.ReadFile(path)
}
// etc.
```

## Command Execution

Uses exec.Command:
```go
func (c *LocalConnection) Exec(cmd string, args ...string) ([]byte, error) {
    return exec.Command(cmd, args...).Output()
}
```

## Tmux

Delegates to Tmux wrapper:
```go
func (c *LocalConnection) TmuxNewSession(name, dir string) error {
    return c.tmux.NewSession(name, dir)
}
```

## Notes

Straightforward implementation - this is the "baseline" connection that SSHConnection will mirror remotely.


Digest: mol-deacon-patrol

P18: stable


Deacon plugin scheduler: cron-like execution

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

## Concept

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

## Plugin Registration

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

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

## Schedule Format

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

## Execution

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

## Plugin Execution Modes

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

## State Tracking

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

## Relation to gt-axz

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


Digest: mol-deacon-patrol

Patrol 2: archived stale Mayor handoffs, all agents healthy


Digest: mol-deacon-patrol

Patrol 17: quiet


Digest: mol-deacon-patrol

Patrol cycle 8: All healthy


Update Refinery to use Beads merge queue

Replace branch discovery with Beads queue in the Refinery module:

Current (internal/refinery/manager.go):
- Scans for polecat/* branches
- Creates MR objects on-the-fly

New:
- Pull from Beads: bd ready --type=merge-request
- Process each MR
- Close with merge commit: bd close <id> --reason="Merged at <sha>"
- Handle failures: bd update <id> --status=blocked --reason="..."

The Engineer (agent) becomes Beads-native.
The Refinery (module) provides the infrastructure.


Merge: gt-o3is

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


Merge: ace-1767074385080

attached_args: Code review this merge request

branch: polecat/ace-1767074385080
target: main
source_issue: ace-1767074385080
rig: gastown


Merge: capable-1767074169502

attached_args: Code review this merge request

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


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

Patrol 13: All healthy


Merge: gt-vmk7

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


Digest: mol-deacon-patrol

Patrol 7: Interrupted, routine


Remove hook code from cmd callers

Remove hook file calls from:
- resume.go:151 - WriteSlungWork → use bd update --status=pinned
- park.go:114 - ReadHook → query pinned beads
- spawn.go:407 - WriteSlungWork → use bd update --status=pinned
- molecule_step.go:293 - WriteSlungWork → use bd update --status=pinned
- molecule_step.go:368 - BurnHook → use bd update --status=open


Remove stubbed ProcessMRFromQueue and mrqueue package

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

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

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

Leaning toward removal - YAGNI.


Digest: mol-deacon-patrol

Patrol 20: final check, all healthy, handoff threshold


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)