VC Pattern Integration: Bring validated ideas to Gas Town

Analysis of ~/src/vc identified 6 validated patterns from the 2nd orchestrator attempt that map cleanly to Gas Town primitives. VC achieved 254 issues closed, 90.9% gate pass rate, and 24 successful missions.

Key insight: VC built ~4300 lines of Go for features that become ~65 lines of YAML + CLI flags in Gas Town's architecture.

Child tasks track each pattern to integrate.


Dog agent beads with role_type=dog

## Dog Agent Beads for @group Resolution

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

## Background

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

## Deliverables

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

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

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

## Schema

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

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

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


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


Context cycling protocol

Document and verify gt handoff pattern for patrol agents. Ensure hook chain works: handoff mail sent, session respawns, SessionStart hook runs gt prime, work continues from pinned molecule.


Digest: mol-deacon-patrol

Patrol cycle 5: All healthy


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

Patrol 19


Digest: mol-deacon-patrol

Patrol 6: Nominal


Phase 1.1: gt rig init creates .beads-ephemeral/

Add ephemeral beads repo creation to rig initialization.

## Implementation

In `gt rig init` (or equivalent setup):
1. Create `<rig>/.beads-ephemeral/` directory
2. Initialize as git repo
3. Create minimal beads config (no sync-branch needed)
4. Add to .gitignore if not already

## Config

```yaml
# .beads-ephemeral/config.yaml
ephemeral: true
# No sync-branch - ephemeral is local only
```

## Verification

```bash
gt rig init gastown
ls gastown/.beads-ephemeral/  # Should exist
```


Digest: mol-deacon-patrol

Patrol 5: OK


Digest: mol-deacon-patrol

Patrol cycle 13: routine


Digest: mol-deacon-patrol

Patrol 12: All healthy.


Design: Polecat lifecycle and patrol coordination

## Context

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

## Core Insight: Session-Per-Step Model

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

## Two Cleanup Stages

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

## Per-Rig Polecat Channel

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

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

## GUPP + Pinned Work = Completion

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

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

## Daemon → Deacon Heartbeat

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

## Open Design Questions

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

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

Needs: Analysis of optimal granularity based on step complexity.

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

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

Question: When is mechanical intervention appropriate?

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

Mail seems most consistent with Gas Town patterns.

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

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

## Related Issues

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

## Design Principles (from HOP/MEOW context)

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

## Next Steps

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


gt-gastown-polecat-alpha

gt-gastown-polecat-alpha

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


Swarm completion detection and auto-close

Detect when all epic children are closed and auto-close the swarm molecule.

Core logic:
1. After any issue closes, check if it was part of a swarm
2. Query bd list --parent=<epic> --status=open
3. If empty (all closed), close the swarm molecule
4. Fire completion event for activity feed

Can be implemented as:
- Part of Witness patrol
- Or as a bd hook triggered on issue close
- Or as a gt swarm check command called periodically

Reference: ~/gt/docs/swarm-architecture.md - Recovery Protocol

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


Witness cleanup should know worktree parent repo

Witness had to discover that polecat worktrees are created from mayor/rig, not the rig root.

## Problem
When cleaning up polecat/tracer:
- Witness ran git worktree remove from gastown/ - failed
- Had to discover worktree was from mayor/rig
- Then removed correctly

## Improvement
Witness should know the worktree parent repo path (mayor/rig) and clean up from there directly.

## Evidence
Tracer bullet 2025-12-23: Witness took extra steps to figure out cleanup path.


Digest: mol-deacon-patrol

Patrol 11


Witness: instantiate mol-witness-patrol on start

When witness starts, create a mol-witness-patrol instance and pin it to the witness hook.

## Changes to witness/manager.go

In Start() or run():
1. Check if patrol instance exists on hook
2. If not, call beads.InstantiateMolecule(mol-witness-patrol, handoffBead)
3. Store instance ID for later reference

## Hook Structure

The witness handoff bead gets:
- attached_molecule: gt-patrol-xyz
- attached_at: timestamp

## Idempotency

If patrol already exists (from previous session), reuse it.
Don't create duplicate instances on restart.


Witness Patrol Molecule

Create mol-witness-patrol molecule for witness heartbeat loop.

Similar to DeaconPatrolMolecule but for per-rig witness duties.

## Steps
1. inbox-check - Process witness mail
2. survey-workers - List polecats, check status
3. inspect-workers - Capture pane output, assess state
4. plugin-run - Execute plugins from <rig>/plugins/witness/
5. decide-actions - Determine nudges, escalations
6. execute-actions - Send nudges, process shutdowns
7. context-check - Check own context, handoff if needed
8. loop-or-exit - Continue or cycle

The plugin-run step enables user customization of the patrol loop.


Digest: mol-deacon-patrol

Patrol 13: healthy


Deacon primes pending workers instead of spawn nudge

## Problem

When gt spawn starts a polecat, it tries to send a nudge message immediately:
1. Starts tmux session with Claude Code
2. Waits 3 seconds (hardcoded)
3. Sends nudge via NudgeSession

But Claude Code takes 10-20+ seconds to be ready. The message arrives before
the prompt is ready, so it appears as part of the prompt string instead of
being executed.

## Solution

Move priming responsibility to the Deacon patrol cycle:

1. gt spawn: Mark polecat as pending_prime=true in state, return immediately
2. Deacon patrol: New step prime-pending-workers that:
   - Scans all rigs for workers with pending_prime=true
   - Uses WaitForClaudeReady() to poll for "> " prompt (already exists in tmux.go)
   - Once ready, sends gt prime + assignment nudge
   - Clears pending_prime flag

## Implementation

### spawn.go changes
- Remove the 3-second sleep (line 368)
- Remove the NudgeSession call (lines 375-383)
- Instead: Update polecat state with pending_prime=true

### Polecat state addition
status: assigned, pending_prime: true, issue: gt-xxx

### Deacon patrol addition
Add step between inbox-check and plugin-run:
prime-pending-workers: Check all rigs for workers marked pending_prime.
For each pending worker: WaitForClaudeReady(60s), then gt prime + nudge

### Benefits
- No race condition - we poll until actually ready
- Deacon already does health checks - priming is natural fit
- Works for polecats, witnesses, refineries, crew (unified approach)
- Timeout handling built in

## Depends on
- Existing WaitForClaudeReady() in tmux.go (lines 384-403)


Merge: gt-ay1r

branch: polecat/dementus
target: main
source_issue: gt-ay1r
rig: gastown


gt witness: Witness management commands

Add 'gt witness' command group for witness lifecycle management.

Subcommands:
- gt witness start [rig] - Start witness for a rig
- gt witness stop [rig] - Stop witness
- gt witness status [rig] - Show witness status
- gt witness attach [rig] - Attach to witness session

Witness monitors polecats and handles:
- Idle detection and cleanup
- Session health checks
- Nudging stuck agents


Digest: mol-deacon-patrol

Patrol #3: Stable, no changes


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

Patrol 14


Digest: mol-deacon-patrol

Patrol 9: routine, all healthy


Digest: mol-deacon-patrol

Patrol cycle 3: all systems nominal


Update Mayor startup protocol for bootstrap

Teach Mayor to respond to "boot up gas town" by slinging mol-gastown-boot.

## Current Protocol

1. Announce: "Mayor, checking in."
2. Check mail
3. If handoff, continue
4. Await user instruction

## Enhanced Protocol

1. Announce: "Mayor, checking in."
2. Check mail
3. If handoff, continue
4. **If user says "boot"/"startup"/"bootstrap":**
   - Sling mol-gastown-boot as wisp
   - Execute verification-gated steps
   - Report town status when complete
5. Otherwise await instruction

## Trigger Phrases

- "boot up gas town"
- "bootstrap the town"
- "start gas town"
- "bring up the town"

## Execution

Mayor runs the molecule manually (not via subagent):

```
1. Bond the proto: bd mol bond mol-gastown-boot --wisp
2. For each step:
   a. Run action command
   b. Loop verification with backoff
   c. On stall, run recovery
   d. Close step when verified
3. Squash wisp with summary
4. Report: "Gas Town is up. All agents healthy."
```

## CLAUDE.md Update

Add to Mayor CLAUDE.md:

```markdown
## Bootstrap Command

When user requests town bootstrap:
1. gt sling gastown-boot mayor/ --wisp
2. Execute molecule steps with verification
3. Keep trying until all agents healthy
4. No timeouts - you are the town engineer
```


Comprehensive help text and examples

Improve help text with examples and cross-references.

## Improvements

### 1. Examples Section
Add to Long description:
```go
var spawnCmd = &cobra.Command{
    Long: `Spawn a polecat with work assignment.

Examples:
  gt spawn gastown/Toast --issue gt-abc
  gt spawn gastown --issue gt-def          # auto-select polecat
  gt spawn gastown/Nux -m "Fix the tests"  # free-form task`,
}
```

### 2. Cross-References
Reference related commands:
```
See also:
  gt polecat list    List available polecats
  gt session attach  Attach to spawned session
```

### 3. Flag Descriptions
More detail on flags:
```go
cmd.Flags().StringVar(&issue, "issue", "",
    "Beads issue ID to assign. The polecat will work on this issue.")
```

### 4. Common Workflows
Add workflow docs to gt --help:
```
Common Workflows:
  Start a swarm:
    gt swarm preflight
    gt swarm create gastown --epic gt-abc --worker Toast --worker Nux --start
    gt refinery start gastown

  Check status:
    gt status
    gt swarm status <id>
```

## Files to Update
All internal/cmd/*.go files

## Acceptance Criteria
- [ ] All commands have Examples
- [ ] Related commands cross-referenced
- [ ] Flags have detailed descriptions
- [ ] Root help shows workflows


gt shutdown should fully cleanup polecats (worktrees, branches, inboxes)

Current gt shutdown only kills tmux sessions but leaves:

1. Git worktrees in polecats/ directory
2. Polecat branches (polecat/<name>)
3. Inbox messages
4. Beads assignee state

This causes stale polecats to be reused on next startup.

## Expected Behavior

gt shutdown should:
1. Kill all polecat tmux sessions (current behavior)
2. For each polecat with StateIdle or StateDone:
   - Remove worktree
   - Delete branch
   - Clear inbox
3. For polecats with uncommitted work:
   - REFUSE to clean up
   - Report which polecats have uncommitted changes
   - Require --force or --nuclear to proceed

## Current Code

- start.go:runImmediateShutdown() only calls t.KillSession()
- Witness cleanupPolecat() does full cleanup but isn't called by shutdown

## Fix

Either:
1. Call Witness cleanup for each polecat during shutdown
2. OR add rig.ShutdownPolecats() that does the full cleanup


Digest: mol-deacon-patrol

Patrol 3: All agents healthy, routine


Digest: mol-deacon-patrol

Patrol 13: All clear


Deacon has no rig-level presence - only global gt-deacon

The Deacon patrol role exists only at the global level (~/gt/deacon) but doesn't have per-rig presence like Witness and Refinery.

Current structure:
```
~/gt/
├── deacon/           ← Global deacon only
├── beads/
│   ├── witness/      ← Per-rig witness
│   ├── refinery/     ← Per-rig refinery
│   └── (no deacon)   ← Missing
└── gastown/
    ├── witness/
    ├── refinery/
    └── (no deacon)   ← Missing
```

Question: Should Deacon be per-rig like Witness/Refinery, or is global-only intentional?

If per-rig is needed: Create beads/deacon and gastown/deacon with appropriate CLAUDE.md files.


Add tmux crash detection hooks

Use tmux hooks to detect when agent panes die unexpectedly.

## tmux Hooks to Use
- pane-died: fires when a pane exits
- session-closed: fires when session ends

## Implementation
```bash
set-hook -g pane-died 'run-shell "gt log pane-died #{pane_id} #{pane_dead_status}"'
set-hook -g session-closed 'run-shell "gt log session-closed #{session_name}"'
```

## Integration
- gt spawn should set these hooks on agent sessions
- Distinguish expected exits (handoff, done) from crashes
- Capture last N lines of output on crash
- Record exit code/signal for forensics

## gt log crash command
- Parse pane-died events
- Show crash history
- Filter by agent, time range


Digest: mol-deacon-patrol

Patrol 9: OK


Daemon: integration test with real lifecycle

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

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


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, 3 polecats idle, no orphans, 6 Mayor messages pending


Create rig settings/ directory for rig configuration

Replace .gastown/ with visible settings/ at rig level:
- Create <rig>/settings/ directory
- Move .gastown/config.json → settings/config.json (theme, merge_queue, max_workers)
- Create settings/namepool.json for pool settings (style, max - not state)
- Create settings/roles/ for per-role overrides (optional)
- Update RigConfig type to reference settings/
- Update loader to read from settings/


Polecat template cleanup

Collection of improvements to the polecat role template (polecat.md.tmpl). Focus: reduce prose redundancy, move behavior into molecules, fix terminology, improve clarity.


Digest: mol-deacon-patrol

Patrol 4: All healthy, no messages


Burn and respawn or loop

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

Decision point at end of patrol cycle:

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

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

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

This enables infinite patrol duration via context-aware respawning.


Wire GT_ACCOUNT env var into spawn/attach

When spawning Claude Code (gt spawn, gt crew attach), check GT_ACCOUNT env var. If set, look up account in config and set CLAUDE_CONFIG_DIR accordingly.


MQ config schema: merge_queue section in rig config.json

Define and implement merge_queue configuration in rig config.

Schema:
{
  "merge_queue": {
    "enabled": true,
    "target_branch": "main",
    "integration_branches": true,
    "on_conflict": "assign_back",  // or "auto_rebase"
    "run_tests": true,
    "test_command": "go test ./...",
    "delete_merged_branches": true,
    "retry_flaky_tests": 1,
    "poll_interval": "30s",
    "max_concurrent": 1
  }
}

Implement:
- Config loading in rig package
- Default values
- Validation

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


Plugin: Plan-to-Epic converter

## Purpose

Help users create beads epics from various planning inputs.

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

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

## Implementation Options

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

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

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

## Axiom

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

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

## Priority

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

## Note

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


Rollback support: gt mq revert for problematic merges

Implement 'gt mq revert <mr-id>' for rolling back merges.

Actions:
1. Find merge commit from closed MR
2. Create revert commit: git revert <merge-commit>
3. Push revert to target branch
4. Create 'reverted' MR tracking the revert
5. Optionally reopen source issue

Options:
- --reason REASON: required explanation
- --reopen-issue: reopen the source work item

Track revert in MR metadata for audit trail.

Reference: docs/merge-queue-design.md#open-questions


Molecule schema: YAML format for workflow definitions

Define the YAML schema for molecule definitions:

```yaml
molecule: <name>
version: 1
description: "Human description"
steps:
  - id: <step-id>
    title: "Step title"
    prompt: "Instructions for agent"
    depends: [<other-step-ids>]  # optional
    tier: haiku|sonnet|opus      # optional, default from config
    timeout: 30m                 # optional
```

Store molecules in:
- `<rig>/molecules/<name>.yaml` for rig-specific
- `<town>/molecules/<name>.yaml` for town-wide

Built-in molecules to ship:
- engineer-in-box: design→code→review→test→submit
- quick-fix: implement→test→submit
- research: investigate→document


Swarm remaining gt-8tmz P3/P4 issues

## Swarm Plan for Molecule Algebra Completion

Encapsulates the remaining swarmable work from gt-8tmz (Molecule Algebra epic).

### Swarmable Issues (6 total)

**Batch 1 - Parallel (3 polecats):**
- gt-8tmz.10: Rename Engineer in Box to Shiny (simple rename)
- gt-8tmz.36: Validate expanded step IDs are unique (validation)
- gt-8tmz.31: Formula validation specification (docs)

**Batch 2 - Sequential (1 polecat):**
- gt-8tmz.34: Expansion var overrides → gt-8tmz.35: Inline step expansion
  (dependency chain - .35 depends on .34)

**Batch 3 - Solo (1 polecat):**
- gt-8tmz.30: Proto debugging and inspection tools (add --graph)

### Hold for Human (7 issues - need design decisions)
- gt-8tmz.19: Meta-formulas (schema design)
- gt-8tmz.20: Org inheritance (policy structure)
- gt-8tmz.21: Conditional aspects (when clause syntax)
- gt-8tmz.22: Review dimensions as aspects (refactor)
- gt-8tmz.28: Error handling policy
- gt-8tmz.29: Versioning strategy
- gt-8tmz.37: Nested expansion recursion

### Code Location
All work is in beads repo: /Users/stevey/gt/beads/crew/emma
- internal/formula/*.go
- cmd/bd/cook.go

### Execution
Hand to Witness for polecat dispatch, or execute manually with polecats.


Built-in molecules: engineer-in-box, quick-fix, research

Create built-in molecules as Beads issues:

## engineer-in-box

```markdown
id: mol-engineer-in-box
type: molecule
title: Engineer in a Box

Full workflow from design to merge.

## Step: design
Think carefully about architecture. Consider:
- Existing patterns in the codebase
- Trade-offs between approaches
- Testability and maintainability

Write a brief design summary before proceeding.

## Step: implement
Write the code. Follow codebase conventions.
Needs: design

## Step: review
Self-review the changes. Look for:
- Bugs and edge cases
- Style issues
- Missing error handling
Needs: implement

## Step: test
Write and run tests. Cover happy path and edge cases.
Fix any failures before proceeding.
Needs: implement

## Step: submit
Submit for merge via refinery.
Needs: review, test
```

## quick-fix

```markdown
id: mol-quick-fix
type: molecule
title: Quick Fix

Fast path for small changes.

## Step: implement
Make the fix. Keep it focused.

## Step: test
Run relevant tests. Fix any regressions.
Needs: implement

## Step: submit
Submit for merge.
Needs: test
```

## research

```markdown
id: mol-research
type: molecule
title: Research

Investigation workflow.

## Step: investigate
Explore the question. Search code, read docs,
understand context. Take notes.

## Step: document
Write up findings. Include:
- What you learned
- Recommendations
- Open questions
Needs: investigate
```

## Storage

Built-in molecules live in `<town>/.beads/` as regular issues.
Created during `gt install` or `bd init`.


Implement town activity logging

Add centralized logging for Gas Town agent lifecycle events.

## Events to Log
- spawn: new agent created
- wake: agent resumed
- nudge: message injected
- handoff: agent handed off (intentional restart)
- done: agent finished work
- crash: agent exited unexpectedly
- kill: agent killed intentionally

## Implementation
- Add internal/log/town.go with LogEvent() function
- Log to ~/gt/logs/town.log or .beads/town.log
- Add gt log command to view/tail/filter logs
- Include timestamps, agent identity, context

## Log Format
```
2025-12-26 15:30:45 [spawn] gastown/crew/max spawned for gt-xyz
2025-12-26 15:31:02 [nudge] gastown/crew/max nudged with "start work"
2025-12-26 15:45:33 [crash] gastown/crew/max exited unexpectedly (signal 9)
```


Merge: gt-y5o

branch: polecat/Doof
target: main
source_issue: gt-y5o
rig: gastown


Digest: mol-deacon-patrol

Patrol 10: All green - halfway mark


Polecat Lifecycle Events: Refinery-Witness Coordination

## Problem

Polecat work completion is currently treated as a single event (MR submission), but the true completion is when the Refinery merges the work. This creates a lifecycle gap:

1. Polecat submits MR → considered "done" by Witness
2. But MR might fail to merge (conflicts, test failures)
3. No one notifies anyone when merge actually succeeds

## Solution: Two-Event Lifecycle

**Event 1: MR Submitted**
- `gt mq submit` notifies Witness
- Witness verifies submission was clean
- Polecat can go idle (but worktree retained)
- If submission had issues, Witness can help

**Event 2: MR Merged**
- Refinery sends `LIFECYCLE: work merged` to Witness
- Witness updates polecat state to `merged`
- Worktree now eligible for full cleanup/recycling

## Village Sibling Watch

For robustness, patrol roles check on their siblings:
- Refinery checks Witness via `gt peek`
- Witness checks Refinery via `gt peek`
- Creates defense in depth - if primary notification fails, someone catches it

## Recovery

If Refinery misses sending lifecycle notification:
- Witness polecat-scan can detect: polecat in mr_submitted but MR shows merged
- Deacon orphan-check can detect: merged MRs with stale polecats


Digest: mol-deacon-patrol

Patrol 5: nominal


Add gt crew rename command


Digest: mol-deacon-patrol

Patrol 14


Immediate daemon notification on lifecycle request

When gt handoff sends a lifecycle request to the daemon (via bd mail send deacon/), the daemon only discovers it on its next heartbeat poll (every 5 min). Workers wait unnecessarily for retirement.

## Current Behavior
1. Worker runs gt handoff
2. Lifecycle mail sent to deacon/ via beads
3. Worker blocks waiting for retirement
4. Daemon heartbeat runs (up to 5 min later)
5. Daemon processes lifecycle request and kills session

## Expected Behavior
Lifecycle requests should be processed immediately, not on poll interval.

## Proposed Solutions

### Option A: SIGUSR1 Signal (simplest)
1. Add SIGUSR1 handler in daemon that calls ProcessLifecycleRequests()
2. gt handoff reads daemon.pid and sends SIGUSR1 after mail send

### Option B: Unix Socket
1. Daemon listens on ~/gt/daemon/lifecycle.sock
2. gt handoff connects and sends 'process' message

### Option C: Watchfile + fsnotify
1. gt handoff touches ~/gt/daemon/lifecycle.trigger
2. Daemon uses fsnotify to detect and process

Recommend Option A for simplicity.

## Affected Files
- internal/daemon/daemon.go - add signal handler
- internal/cmd/handoff.go - send signal after mail


Ensure refinery is alive

Ensure the refinery is alive and processing merge requests.

**Redundant system**: This check runs in both gt spawn and Witness patrol
to ensure the merge queue processor stays operational.

```bash
# Check if refinery session is running
gt session status <rig>/refinery

# Check for merge requests in queue
bd list --type=merge-request --status=open
```

If merge requests are waiting AND refinery is not running:
```bash
gt session start <rig>/refinery
gt mail send <rig>/refinery -s "PATROL: Wake up" -m "Merge requests in queue. Please process."
```

If refinery is running but queue is non-empty for >30 min, send nudge.
This ensures polecats don't wait forever for their branches to merge.


Remove keepalive file infrastructure

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 11: All green


Polecat mood command and status line display

CLI and status line support for polecat mood.

## CLI Command
```
gt polecat mood <name> <emoji>   # Set mood
gt polecat mood <name>           # Get mood
```

Sets GT_MOOD environment variable in the polecat's tmux session.

## Status Line Integration
Update runWorkerStatusLine() to read mood:
```go
mood, _ := t.GetEnvironment(session, "GT_MOOD")
if mood != "" {
    icon = mood  // Use mood emoji instead of default
} else {
    icon = AgentTypeIcons[AgentPolecat]  // Fallback to 😺
}
```

## Storage
Mood stored in tmux session environment (ephemeral, per-session).
No persistence needed - mood is reassessed each patrol cycle.

Depends on: gt-u818 (plugin system)


Phase 5: Integration and Demo

$(cat /tmp/phase5.md)


Day 4.3: Polecat self-manages session handoffs

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

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

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

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

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


Refactor patrol context functions to reduce duplication

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

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

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

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


Add unit tests for internal/lock package

attached_args: Lock package tests

Add comprehensive tests for the file locking package.

## Files to create
- internal/lock/lock_test.go

## Test cases to cover
1. Lock() acquires lock successfully
2. Lock() blocks when lock held by another
3. Unlock() releases lock
4. TryLock() returns immediately if locked
5. IsLocked() detects lock state
6. Lock file contains correct PID
7. Stale lock detection (if implemented)

## Acceptance criteria
- [ ] internal/lock/lock_test.go created
- [ ] At least 5 test functions
- [ ] Tests pass: go test ./internal/lock/...
- [ ] Coverage > 70%: go test -cover ./internal/lock/...


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

This proto enables nondeterministic idempotence for polecat work.
A polecat that crashes after any step can restart, read its molecule state,
and continue from the last completed step. No work is lost.

Variables:
- gt-1wmw - The source issue ID being worked on


Beads CLI wrapper: shell out to bd

Wrapper for bd (beads CLI) commands.

## Interface

```go
type Beads struct {
    workDir string
}

func NewBeads(workDir string) *Beads

// Query
func (b *Beads) List(opts ListOptions) ([]*Issue, error)
func (b *Beads) Ready() ([]*Issue, error)
func (b *Beads) Show(id string) (*Issue, error)
func (b *Beads) Blocked() ([]*Issue, error)

// Mutations
func (b *Beads) Create(opts CreateOptions) (*Issue, error)
func (b *Beads) Update(id string, opts UpdateOptions) error
func (b *Beads) Close(ids ...string) error

// Sync
func (b *Beads) Sync() error
func (b *Beads) SyncStatus() (*SyncStatus, error)
```

## Data Types

```go
type Issue struct {
    ID          string
    Title       string
    Status      string
    Priority    int
    Type        string
    Description string
    Parent      string
    Children    []string
    DependsOn   []string
    Blocks      []string
}

type ListOptions struct {
    Status   string  // "open", "closed", "all"
    Type     string
    Priority int
}

type CreateOptions struct {
    Title       string
    Type        string
    Priority    int
    Description string
    Parent      string
}
```

## Implementation

Shell out to bd binary, parse JSON output where available.
```go
func (b *Beads) runBd(args ...string) ([]byte, error) {
    cmd := exec.Command("bd", args...)
    cmd.Dir = b.workDir
    return cmd.Output()
}
```

## Error Handling

- bd not installed: Clear error with install instructions
- Not a beads repo: Detect and report
- Sync conflicts: Parse and report


Digest: mol-deacon-patrol

Patrol 19: Nominal


MR state transitions: validate open→in_progress→closed

Enforce valid state transitions for merge-requests:

Valid transitions:
- open → in_progress (Engineer claims MR)
- in_progress → closed (merge success or rejection)
- in_progress → open (failure, reassign to worker)
- open → closed (manual rejection)

Invalid:
- closed → anything (immutable once closed)

Implement validation in MR update operations.

Reference: docs/merge-queue-design.md#state-machine


Add 'wit' alias for witness command

ref works as alias for refinery, but wit doesn't work for witness. Add Aliases: []string{"wit"} to witnessCmd.


Blocked issues: gt-um6q, gt-lz13, gt-5xph depend on missing beads features

Template/docs updates blocked on: bd-nurq (bd mol current), bd-29fb (bd close --continue). These gastown issues should be marked blocked on the beads issues once cross-rig deps work.


Track operational stats as entity/audit beads

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

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

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

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


Polecat beads not synced with rig beads

When gt spawn assigns an issue to a polecat, the polecat cannot find the issue because:

1. Rig beads at /gt/gastown/.beads contains gt-th7
2. Polecat beads at /gt/gastown/polecats/dementus/.beads does NOT have gt-th7
3. bd sync in polecat dir pulls from beads-sync branch which doesn't have the new issue
4. Rig bd sync uses 'main' branch, causing a branch mismatch

The polecat gets a work assignment for an issue it literally cannot see.

## Root Cause

- Rig beads and polecat beads are separate git-tracked copies
- No mechanism to propagate newly created issues from rig to polecats before assignment
- Sync branch configuration mismatch between rig and polecats

## Fix Options

1. gt spawn should sync rig beads before assigning work
2. gt spawn should sync polecat beads after assignment
3. Use shared beads (symlink or same DB) instead of copies
4. Push new issues immediately on create

Note: This sync mismatch is resolved by gt-9nf (fresh polecats). Rather than fixing sync between stale clones, we'll always create fresh worktrees. This issue documents the root cause for posterity.


Digest: mol-deacon-patrol

P14: stable


Implement bd bond command for artifact-level composition

Implement the artifact-level bond operator distinct from source-level rigging.

Bond accepts:
- Formula names (cooks inline to ephemeral proto, then bonds)
- Mol IDs (existing liquid work)
- Wisp IDs (existing vapor work)

See molecular-chemistry.md for the full bond table semantics.

**Updated 2025-12-25**: With ephemeral protos (gt-4v1eo), bond takes formula names directly and cooks inline. No pre-cooked proto beads.


gt mq integration create: create integration branch for epic

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 18: all quiet


Plugin: work-oracle (pre-dispatch analysis)

Plugin for pre-dispatch task analysis and decomposition.

## Purpose

Before dispatching workers for an epic, ask work-oracle to:
- Validate task breakdown
- Identify parallelization opportunities
- Predict conflicts between tasks
- Suggest worker count

## Hook Point

Mayor consults work-oracle before spawning workers.

## Interface

Input (via mail):
- Epic ID with proposed child issues
- Rig context (current state of codebase)

Output (via mail + bead):
- Recommended task groupings
- Dependency suggestions
- Risk assessment (which files might conflict)
- Optimal worker count

## Structure

```
<rig>/plugins/work-oracle/
├── CLAUDE.md       # Analysis prompts
├── mail/inbox.jsonl
└── state.json
```

Uses existing plugin-as-agent architecture.

## Note

Was "swarm-oracle" - renamed because there are no swarm IDs. This plugin helps plan batch work, not manage swarm entities.


Add compaction recovery protocol to role templates

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

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

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


Digest: mol-deacon-patrol

Patrol complete: 0 mail, Mayor+2 witnesses+2 refineries healthy, 3 polecats working (gastown), no orphans, gc N/A


Digest: mol-deacon-patrol

Patrol 6: routine


Extract magic values to named constants

Magic strings and numbers throughout codebase:

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

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

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

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


Digest: mol-deacon-patrol

Patrol 10


Silent error handling with _ = err patterns

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

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

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


Polecat cleanup should refuse to lose uncommitted work

The system should stubbornly refuse to lose work from a polecat.

## Current Problem

- gt spawn --force bypasses safety checks
- gt shutdown doesn't check for uncommitted work
- Witness cleanup doesn't check git status

## Desired Behavior

Before any polecat cleanup, check:
1. git status - any uncommitted changes?
2. git stash list - any stashes?
3. Unpushed commits on branch?
4. Unsynced beads changes?

If ANY of these exist:
- REFUSE to clean up
- Print clear error message listing what would be lost
- Require explicit --nuclear flag to force (not just --force)

## Implementation

Add to cleanupPolecat() in witness/manager.go:
```go
func (m *Manager) checkUncommittedWork(polecatName string) error {
    dir := m.polecatDir(polecatName)

    // Check git status
    if hasUncommitted, _ := git.HasUncommittedChanges(dir); hasUncommitted {
        return fmt.Errorf("polecat %s has uncommitted changes", polecatName)
    }

    // Check stashes
    if stashCount, _ := git.StashCount(dir); stashCount > 0 {
        return fmt.Errorf("polecat %s has %d stashes", polecatName, stashCount)
    }

    // Check unpushed commits
    if unpushed, _ := git.UnpushedCommits(dir); unpushed > 0 {
        return fmt.Errorf("polecat %s has %d unpushed commits", polecatName, unpushed)
    }

    return nil
}
```

## Affected Commands

- gt shutdown
- gt rig shutdown
- Witness cleanup
- gt spawn --force (should warn if overwriting)


142 instances of error suppression with _ = pattern

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

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

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


mol-christmas-launch: 3-day execution plan

---

## Wisp Integration Wave Plan (added 2025-12-21)

Dependency-ordered execution for gt-3x0z (Wisp Molecules) + gt-rana (Patrol System):

### Wave 1 (parallel - no blockers)
- gt-3x0z.1: gt rig init creates .beads-ephemeral/
- gt-3x0z.2: Configure bd for ephemeral molecule bonding
- gt-3x0z.3: gt doctor checks for ephemeral health
- gt-rana.1: Attachment field on pinned beads
- gt-rana.3: mol-deacon-patrol definition

### Wave 2 (after Wave 1)
- gt-3x0z.4: gt spawn --molecule bonds ephemeral (GATE 1)
- gt-rana.2: Daemon attachment detection

### Wave 3-5 (sequential)
- gt-3x0z.5, gt-3x0z.6 → gt-3x0z.7 → gt-3x0z.8 (GATE 2: squash)

### Wave 6+ (patrol integration)
- gt-rana.4: Basic patrol runner (needs gt-rana.3 + gt-3x0z.8)
- gt-3x0z.9: mol-deacon-patrol uses wisp (needs gt-rana.3 + gt-3x0z.8)
- Then: gt-rana.5-7, gt-3x0z.10-12

### Key Gates
1. gt-3x0z.4 - spawn/bond unlocks Phase 2
2. gt-3x0z.8 - squash unlocks patrol integration
3. gt-rana.4 - patrol runner unlocks Phase 2+ patrol

Postponed to New Year's launch. Christmas was too ambitious.


Digest: mol-deacon-patrol

Patrol 3: All witnesses/refineries healthy, no work


Test polecat lifecycle end-to-end

Test the full polecat lifecycle:

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 11: all clear


Polecat wisp architecture: Proto → Wisp → Mol pattern

Design the three-layer architecture for polecat lifecycle:

## The Insight

Polecats should run a ONE-SHOT WISP (not looping like patrols):

**Step 1: Onboard**
- Read full polecat protocol (polecat.md template)
- Learn Gas Town operation, exit strategies, molecule protocol
- This is the 'how to be a polecat' education

**Step 2: Execute Mol**
- Run the assigned molecule (the actual work item)
- Could span multiple sessions via session continuity
- The mol is pure work content (epic, issue, feature)

**Step 3: Cleanup**
- Run final step of the wisp
- Self-delete / request shutdown

## Three Layers

- **Proto**: polecat.md template (instructions for being a polecat)
- **Wisp**: One-shot harness instantiated from proto (wraps the mol)
- **Mol**: The work item (issue/epic being processed)

## Why This Matters

1. **Separation of concerns**: Protocol (how) vs Work (what)
2. **Reusability**: Same wisp harness wraps any mol
3. **Extensibility**: Plugin points for custom behavior
4. **Session continuity**: Wisp handles multi-session, not the mol
5. **Blurred control/data planes**: Intentional in Gas Town

## Design Questions

1. How does proto (polecat.md) become a wisp instance?
2. What are the plugin/extension points?
3. Should all 'engineer in a box' mols use proto → wisp → mol?
4. How does this relate to refinery/deacon patterns?


Digest: mol-deacon-patrol

Patrol 18: All agents healthy


Digest: mol-deacon-patrol

Patrol 11: healthy


Digest: mol-deacon-patrol

Patrol 10: all healthy


Spawn inject: Enter not submitted after multiline paste

When gt spawn injects a multiline context (85+ lines), Claude Code shows
'[Pasted text #1 +85 lines]' but the prompt is not submitted.

The tmux SendKeys function does include 'Enter' but it appears to not work
for long pasted text:

```go
func (t *Tmux) SendKeys(session, keys string) error {
    _, err := t.run("send-keys", "-t", session, keys, "Enter")
    return err
}
```

Possible fixes:
1. Use tmux paste-buffer instead of send-keys for long text
2. Send Enter separately after the text
3. Use bracketed paste mode correctly

Reproduction:
```bash
gt spawn gastown/Nux --issue gt-u1j.13 --create
# Session shows pasted text but waits at prompt
```


Fix docs: Formulas are JSON not YAML

The molecular chemistry docs (molecule-algebra.md, molecular-chemistry.md) incorrectly refer to formulas as YAML. Formulas are JSON (.formula.json). Fix all references: .formula.yaml -> .formula.json, 'YAML files' -> 'JSON files', 'formula YAML' -> 'formula JSON', code blocks from yaml to json syntax.


Day 3.4: Refinery processes MERGE_READY mail

Refinery patrol handles merge requests:
1. Check inbox for MERGE_READY messages
2. For each, verify branch exists
3. Run merge checks (tests, lint)
4. If passing, merge to main
5. Send MERGED signal back

Parent: gt-hwka3


Add hook-attachment-valid doctor check

Add gt doctor check to verify attached molecules exist and are not closed.

Check: hook-attachment-valid
Error if: Hook's attached_molecule field points to non-existent or closed issue
Fix suggestion: Clear attachment with gt mol detach


Digest: mol-deacon-patrol

Patrol 15: healthy


Fix out-of-sync molecule test expectations

Tests in builtin_molecules_test.go have hardcoded expectations that no longer match actual molecules:
- TestBuiltinMolecules: expects 9 molecules, got 11
- TestPolecatWorkMolecule: step refs out of sync
- TestDeaconPatrolMolecule: step count and refs out of sync

This is pre-existing on main, not introduced by any polecat work.


Merge: gt-unrd

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


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.


Swarm: report generation

Generate markdown reports for completed swarms.

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

## Report Content

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

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

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

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

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

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

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

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

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


gt handoff should accept full session paths like gastown/crew/max

Currently gt handoff only accepts role shortcuts like 'crew', 'witness', etc. and tries to auto-detect the rig/name from environment. User tried 'gt handoff gastown/crew/max' and got 'unknown session type'. Should parse paths like '<rig>/crew/<name>' or '<rig>/<role>' directly into session names like 'gt-<rig>-crew-<name>'.


Advice operators: before, after, around

Implement Lisp-style advice operators for molecules:
- before(target, step) - insert step before target
- after(target, step) - insert step after target
- around(target, wrapper) - wrap target with before/after

Support glob patterns for targeting (*.implement, shiny.*, etc).


Digest: mol-deacon-patrol

Patrol complete: 5 mayor msgs (informational), all agents healthy, triggered 3 polecats, closed 1 orphan (gt-mol-aux test artifact)


gt crew refresh: Context cycling with handoff

Implement 'gt crew refresh <name>' command:
- Send handoff mail to self (context summary)
- Kill current session cleanly
- Start new session
- New session reads handoff mail and resumes
- Support --message to add custom handoff notes


bd mail send: pinned column missing from schema

gt mail send fails with: sqlite3: SQL logic error: table issues has no column named pinned

Likely a schema migration issue - bd schema has 'pinned' field but SQLite table doesn't.

## Reproduction
gt mail send gastown/Immortan -s 'test' -m 'test'

## Error
table issues has no column named pinned

## Fix
Either:
1. Add migration to add pinned column
2. Remove pinned from insert if not present
3. Regenerate DB from JSONL


gt daemon: Background service management

## Summary

ONE daemon for all Gas Town - a simple Go process (not a Claude agent) that:
1. Pokes agents periodically (heartbeat)
2. Processes lifecycle requests
3. Restarts sessions when agents request cycling

## Architecture

Daemon (gt daemon)
- Pokes Mayor: "HEARTBEAT: check your rigs"
- Pokes each Witness: "HEARTBEAT: check your workers"
- Has inbox at daemon/ for lifecycle requests
- Restarts sessions on cycle requests

## NOT the daemon's job:
- Making decisions (Witnesses do that)
- Running Claude (it's a Go process)
- Processing work (polecats do that)
- Direct polecat management (Witnesses do that)

The daemon is a **dumb scheduler** - poke things, execute lifecycle requests. All intelligence is in agents.

## Commands

- gt daemon start: Start daemon (background)
- gt daemon stop: Stop daemon
- gt daemon status: Show daemon status
- gt daemon logs: View daemon logs

## Daemon Loop

Every heartbeat interval:
1. Poke Mayor
2. For each rig: Poke Witness
3. Process lifecycle requests from daemon/ inbox
4. Check for dead sessions, restart if cycle requested

## Lifecycle Request Handling

Daemon checks its inbox (daemon/) for lifecycle requests:
- From Mayor: cycle/restart Mayor session
- From Witnesses: cycle/restart Witness session

On request:
1. Verify agent state shows requesting_cycle
2. Kill session
3. Start new session
4. Clear requesting_cycle flag

## Poke Protocol

Poke = tmux inject "HEARTBEAT: do your job"
- Agent ignores if already working
- Agent wakes up if idle
- Idempotent - multiple pokes are fine

## Lifecycle Hierarchy

- Daemon manages: Mayor, all Witnesses
- Witness manages: Polecats, Refinery (per rig)
- Crew: self-managed (human workspace)

## Related Issues

- gt-kmn.11: Daemon heartbeat details
- gt-gby: gt handoff command (unified lifecycle)
- gt-u1j.9: Fold witness daemon into this


Digest: mol-deacon-patrol

Patrol 3: all healthy


detectSender() doesn't recognize crew workers

## Problem

detectSender() in internal/cmd/mail.go only checks for /polecats/ directories. Crew workers in /crew/<name>/ fall through to the default 'mayor/', so:
- gt mail inbox shows mayor's inbox instead of the crew worker's
- gt mail send sets the wrong From address

## Fix

Add crew worker detection before the /polecats/ check:

if strings.Contains(cwd, "/crew/") {
    parts := strings.Split(cwd, "/crew/")
    ...
    return fmt.Sprintf("%s/crew/%s", rigName, crewMember)
}

## Affected
- Any crew worker running gt mail inbox without explicit address
- Crew worker handoffs (wrong sender)


implement

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


Draft mol-ready-work protomolecule definition

Draft the actual protomolecule definition in markdown format.

## Molecule Structure

```markdown
## Molecule: ready-work
Autonomous backlog processing patrol for crew workers.

Phase: vapor (wisp) - ephemeral patrol cycles
Squash: after each work item or context threshold

## Step: orient
Load context and check for interrupts:
- Read mail for overseer instructions
- Check for predecessor handoff
- Load current context state

## Step: scan-backlogs
Survey all backlogs in priority order:
1. gh pr list --state open
2. gh issue list --state open --label untriaged (or no label)
3. bd ready
4. gh issue list --state open --label triaged

Capture counts and candidates.

Needs: orient

## Step: select-work
Apply ROI heuristic to select best work item:
- Estimate size (tokens needed)
- Check remaining context capacity
- Weight by impact (priority, type)
- Select highest ROI achievable item
- If empty: exit patrol

Needs: scan-backlogs

## Step: execute-work
Work the selected item:
- For PRs: review, request changes, or merge
- For untriaged: triage and label
- For beads: implement and close
- For triaged GH: implement fix

Commit, push, close/update as appropriate.

Needs: select-work

## Step: check-context
Assess context state:
- Estimate remaining capacity
- If < 20%: goto handoff
- If ok: loop to scan-backlogs

Needs: execute-work

## Step: handoff
Prepare for session transition:
- Summarize work completed this cycle
- Note any in-progress items
- Send handoff mail to self
- Squash wisp to digest
- Exit for fresh session

Needs: check-context
```

## Variables

- `backlog_priority`: Override backlog scan order
- `context_threshold`: Percentage at which to handoff (default: 20)
- `max_items`: Maximum items to process per session

## Notes

- This is a vapor-phase molecule (wisp)
- Each work item should squash to a digest
- The patrol itself squashes at handoff


beads: Stop searching upward when .beads found

## Problem

When running bd commands in a nested directory structure with multiple .beads directories, bd shows a confusing warning:

```
╔══════════════════════════════════════════════════════════════════════════╗
║ WARNING: 2 beads databases detected in directory hierarchy              ║
╠══════════════════════════════════════════════════════════════════════════╣
║ Multiple databases can cause confusion and database pollution.          ║
║                                                                          ║
║   /Users/stevey/gt/gastown/.beads (261 issues)                           ║
║   /Users/stevey/gt/.beads (21 issues)                                    ║
║                                                                          ║
║ WARNING: Not using the closest database! Check your BEADS_DB setting.   ║
║                                                                          ║
║ RECOMMENDED: Consolidate or remove unused databases to avoid confusion. ║
╚══════════════════════════════════════════════════════════════════════════╝
```

## Why This Is Wrong

In Gas Town, nested .beads directories are **intentional and necessary**:
- Town level: /Users/stevey/gt/.beads (mail, town-level issues)
- Rig level: /Users/stevey/gt/gastown/.beads (gastown project issues)
- Worker level: polecats have their own beads in worktrees

These are **unrelated** beads instances for different scopes. They should never be consolidated.

## Expected Behavior

When bd finds a .beads directory, it should:
1. Use that directory (closest ancestor wins)
2. **Stop searching upward** - do not look for parent .beads directories
3. **No warning** about multiple databases

## Current Behavior

bd searches all the way up to root, finds all .beads directories, and warns about "multiple databases" even though they are separate, intentional instances.

## Fix

In the database discovery code, stop the upward search as soon as a .beads directory is found. The first .beads found is the one to use, and parent directories are out of scope.

## Note

This is a beads issue, filed here for tracking. Should be implemented in the beads codebase.


Daemon heartbeat becomes recovery-focused

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

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

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


gt-deacon

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

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


Digest: mol-deacon-patrol

Test patrol cycle - verifying wisp flow


Implement gt mol attach-from-mail command

Allow agents to self-pin work from mail.

Usage: gt mol attach-from-mail <mail-id>

Behavior:
1. Read mail body for attached_molecule field
2. Attach molecule to agent's hook
3. Mark mail as read
4. Return control for execution

Handles case where work was sent via mail but not slung to hook.


mol-swarm-cleanup: Post-swarm debris cleanup molecule

After a 20+ worker swarm completed, found significant beads debris:
- 18 stale messages (work assignments, lifecycle requests, swarm instructions)
- 3 completed issues still open/in_progress
- Test messages accumulated

Need: Document a post-swarm checklist or create gt swarm cleanup command that:
1. Closes stale work assignment messages
2. Reviews in_progress issues for completion
3. Closes orphaned lifecycle messages
4. Optionally archives test messages


Digest: mol-deacon-patrol

Patrol 18: all healthy


Digest: mol-deacon-patrol

Patrol 14: All healthy.


Merge: slit-1767073379145

attached_args: Code review this merge request

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

CODE REVIEW (valkyrie): REQUEST CHANGES

Critical bugs found in internal/swarm/manager.go:
1. JSON field changed from 'dependents' to 'dependencies' but bd outputs 'dependents'
2. 'hooked' status removed from in_progress handling
3. Assignee field removed from task loading

These changes will break swarm coordination. Polecat_spawn.go fix is correct.

Recommendation: Revert swarm/manager.go changes, keep polecat_spawn.go fix.


Merge: dag-1767074322940

attached_args: Code review this merge request

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


Fix failing beads tests: TestIntegration and TestPolecatWorkMolecule


Update WitnessPatrolMolecule() with Christmas Ornament structure

Update builtin_molecules.go WitnessPatrolMolecule() to use dynamic bonding pattern.

Changes:
1. Add survey-workers step that documents dynamic bonding
2. Add run-plugins step for plugin hook support
3. Add aggregate step with WaitsFor: all-children
4. Update step dependencies for new structure

The molecule prose guides the Witness agent on how to use bd mol bond.


gt rig add / gt doctor: patrol awareness and wiring

## Problem

When a rig is installed or audited, we need to ensure all built-in patrols and role hooks are properly wired up.

## gt rig add Changes

When adding a rig, automatically:

1. **Create patrol molecules** for each role:
   - mol-deacon-patrol (town-level)
   - mol-witness-patrol (per-rig)
   - mol-refinery-patrol (per-rig)

2. **Set up hooks** that trigger patrols:
   - Deacon: daemon timer / heartbeat
   - Witness: daemon timer / polecat lifecycle events
   - Refinery: MR submission events / daemon timer

3. **Configure daemon** to manage these patrols:
   - Register patrol molecules in daemon config
   - Set up respawn behavior for each role

4. **Create plugin directories**:
   - ~/gt/plugins/ (town-level)
   - <rig>/plugins/ (rig-level, if needed)

## gt doctor Changes

Add patrol health checks:

### patrol-molecules-exist
- Verify mol-deacon-patrol, mol-witness-patrol, mol-refinery-patrol exist
- Check they parse correctly (valid steps, dependencies)

### patrol-hooks-wired
- Verify hooks trigger patrol execution
- Check daemon is configured to manage patrols

### patrol-not-stuck
- Detect wisps that have been in-progress too long
- Flag orphaned patrol molecules (no active session)

### patrol-plugins-accessible
- Verify plugin directories exist and are readable
- Check plugin frontmatter parses correctly

### patrol-roles-have-prompts
- Verify prompts/roles/*.md exist for each role
- Check they reference the correct patrol molecule

## Auto-fix

gt doctor --fix can:
- Create missing patrol molecules
- Wire up missing hooks
- Create plugin directories
- NOT restart stuck patrols (needs human decision)

## Related
- gt-7920 (mol-refinery-patrol)
- gt-7921 (await-work and plugin-run)
- docs/wisp-architecture.md


Update gt doctor to check new config locations

Doctor should validate new structure:
- Check mayor/config.json exists and is valid
- Check settings/ exists for each rig
- Warn if old .gastown/ files still exist
- Offer --fix to migrate old locations to new


Execute registered plugins

Execute registered plugins.

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 3: All agents healthy.


Merge: dementus-1767073385126

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


Digest: mol-deacon-patrol

Patrol cycle 19: routine


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

Patrol 5: All healthy


Digest: mol-deacon-patrol

Patrol 10: all healthy, sessions up


Session pre-shutdown checks

Session stop should verify clean state before killing, like PGT.

## Pre-Shutdown Checks

### 1. Git Working Tree Clean
```go
func checkGitClean(clonePath string) error {
    // git status --porcelain
    // Fail if any output
}
```

### 2. All Commits Pushed
```go
func checkCommitsPushed(clonePath string) error {
    // git log origin/HEAD..HEAD
    // Fail if any unpushed commits
}
```

### 3. Assigned Issues Handled
```go
func checkIssuesHandled(polecat *Polecat) error {
    // If polecat.Issue != "", check if closed or reassigned
}
```

### 4. Beads Synced
```go
func checkBeadsSynced(clonePath string) error {
    // bd sync --status in clone directory
}
```

## Behavior on Failure
1. First attempt: Nudge worker to fix
2. Retry up to 3 times with delay
3. After retries: Escalate to Witness/Mayor

## Integration
Modify internal/session/manager.go Stop():
```go
func (m *Manager) Stop(polecat string, force bool) error {
    if !force {
        if err := m.runPreShutdownChecks(polecat); err != nil {
            return fmt.Errorf("pre-shutdown checks failed: %w", err)
        }
    }
    // existing stop logic
}
```

## Flags
- --force: Skip checks
- --grace-period N: Time to wait for fixes

## Dependencies
- Ties into gt-69l (hook system) - can be hook-based
- Ties into gt-f8v (Witness pre-kill verification)

## Acceptance Criteria
- [ ] Stop fails if uncommitted changes (without --force)
- [ ] Stop fails if unpushed commits
- [ ] Clear error messages with fix instructions
- [ ] --force bypasses all checks


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

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


Test merge request

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


CLI: gt stop --all (emergency swarm kill)

Emergency kill command for swarm operations.

## Commands

```bash
gt stop --all              # Kill ALL sessions across all rigs
gt stop --rig <name>       # Kill all sessions in one rig
gt stop --rig <name> --graceful  # Try graceful first, then force
```

## Implementation

### --all flag
1. List all tmux sessions matching gt-*
2. For each: capture final output, kill session
3. Update all polecat states to idle
4. Log all killed sessions
5. Send mail to Mayor: "Emergency stop executed"

### --rig flag
1. List sessions for specific rig
2. Same as above but scoped

### --graceful flag
1. First, try to inject "exit" command
2. Wait 5 seconds
3. If still running, force kill

## Output

```
Stopping all Gas Town sessions...
  [wyvern] Toast: captured output, killed
  [wyvern] Capable: captured output, killed
  [beads] Nux: captured output, killed

3 sessions stopped.
All polecat states set to 'idle'.
Mail sent to mayor/.
```

## Safety

- Always capture output before killing
- Update state files to reflect reality
- Log all operations to gt.log
- Warn if uncommitted changes detected (but still kill)

## Dependencies

Needs: Tmux wrapper, Session management, Polecat management


gt prime should detect mayor role from any rig's mayor/ folder

Currently gt prime only detects the Mayor role when run from town root (~/gt). It should also detect Mayor when run from:
- ~/gt/gastown/mayor/rig (rig's internal mayor dir)
- Any path containing /mayor/ under a rig

This would allow the mayor session to work correctly regardless of which rig directory it's attached to.


test sling pinned


Merge: gt-h6eq.3

branch: polecat/nux
target: main
source_issue: gt-h6eq.3
rig: gastown


Digest: mol-deacon-patrol


Work on ga-rd4: Add gt polecat status command. Show detai...

Work on ga-rd4: Add gt polecat status command. Show detailed polecat status including current issue, session state, last activity time. When done, submit MR (not PR) to integration branch for Refinery.


TIDY UP: Your previous work (gt-odvf: bd mol CLI docs) wa...

TIDY UP: Your previous work (gt-odvf: bd mol CLI docs) was already merged to main. Check your git status is clean, sync beads, and if nothing to do, just run 'gt done'.


Digest: mol-deacon-patrol

Patrol 9: Routine


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

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

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

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


Self-test

Testing gt mail works


Replace WaitForClaudeReady with gt peek for steady-state agent observation

## Problem

WaitForClaudeReady uses regex to detect Claude's prompt, which is a ZFC violation.

## Architectural Fix

**Bootstrap (ZFC violation acceptable):**
During cold town startup, no AI is available. Regex to get Deacon online is acceptable.

**Steady State (proper ZFC):**
Once any agent is running, AI should observe AI:
- Deacon starting polecats → Deacon uses gt peek
- Deacon restarting → Mayor watches via gt peek
- Mayor restarting → Deacon watches via gt peek

## Implementation

1. Keep WaitForClaudeReady for daemon bootstrap only
2. Update gt deacon trigger-pending to use gt peek
3. Document bootstrap vs steady-state distinction


decide-actions

Apply nudge matrix and queue actions.

Progressive nudge levels:
- Level 1: Gentle reminder
- Level 2: Stronger nudge
- Level 3: Final warning
- Level 4: Escalate to Mayor

Needs: inspect-workers


gt spawn: Not injecting work instructions to session

gt spawn starts session but doesn't inject the issue assignment.

Repro:
1. gt spawn gastown/Toast --issue gt-2ux
2. Session starts but polecat just sees Claude prompt
3. No issue context injected

Expected: Polecat should receive issue details automatically.
Actual: Polecat sits at blank prompt, needs manual injection.


Digest: mol-deacon-patrol

Cycle 3: quiet patrol


Digest: mol-deacon-patrol

Patrol 17: routine


Digest: mol-deacon-patrol

Patrol cycle 18: nominal


attached_args: Extract processExists function to reduce duplication

Extract duplicated processExists function to shared package.

## Files to modify
- internal/util/process.go (NEW)
- internal/witness/manager.go (remove local function, import util)
- internal/refinery/manager.go (remove local function, import util)

## Current duplication
Both files have identical implementations at:
- internal/witness/manager.go (lines 136-144)
- internal/refinery/manager.go (lines 646-654)

```go
func processExists(pid int) bool {
    proc, err := os.FindProcess(pid)
    if err != nil {
        return false
    }
    err = proc.Signal(nil)
    return err == nil
}
```

## Implementation
Create internal/util/process.go:
```go
package util

import "os"

// ProcessExists checks if a process with the given PID exists.
func ProcessExists(pid int) bool {
    proc, err := os.FindProcess(pid)
    if err != nil {
        return false
    }
    return proc.Signal(nil) == nil
}
```

## Acceptance criteria
- [ ] internal/util/process.go created with ProcessExists function
- [ ] internal/util/process_test.go with basic tests
- [ ] witness/manager.go imports util and uses util.ProcessExists
- [ ] refinery/manager.go imports util and uses util.ProcessExists
- [ ] Local processExists functions removed from both files
- [ ] go build ./... passes
- [ ] go test ./... passes


Digest: mol-deacon-patrol

Patrol cycle 6: routine


Digest: mol-deacon-patrol

Patrol cycle 7: all nominal


Polecat .beads/ contamination from stale branches

**Fixed in commit 8699b7b**

## Problem

When polecats are spawned from branches that previously had bd sync run on them, the .beads/ directory from the branch contains stale issues.jsonl, config.yaml, etc.

The setupSharedBeads() function was creating a redirect file, but NOT cleaning up the existing .beads/ contents first.

## Root Cause

1. Old polecat branch has .beads/ tracked in git (from previous bd sync)
2. gt spawn uses Add() which reuses existing branch
3. WorktreeAddExisting() checks out branch, including .beads/ files
4. setupSharedBeads() creates redirect, but other files remain
5. bd commands see stale data

## Fix

setupSharedBeads() now:
1. Removes entire .beads/ directory if it exists
2. Recreates fresh with only redirect file
3. Redirect points directly to mayor/rig/.beads (not through rig root)


Digest: mol-deacon-patrol

Patrol #4: 2 Witnesses OK, 2 Refineries OK


🤝 HANDOFF: Investigate beads-sync divergence (221 files)

## Context

gt doctor now detects orphaned code on beads-sync branch. Running it shows:

  beads-sync-orphans: 221 file(s) on beads-sync not in main

This is in the gastown repo (checking from crew/max).

## Background

- Earlier today we recovered orphaned mail migration code lost in merge 96c773f
- Recently simplified architecture: all workers use mayor/rig/.beads (redirects)
- This simplification may have caused beads-sync branch to diverge unexpectedly

## Investigation Steps

1. From crew/max run: git diff main..beads-sync --stat
2. Check if beads-sync should even exist anymore (was for multi-clone sync)
3. If obsolete with redirect architecture, consider deleting it
4. If it has legitimate changes, cherry-pick or merge to main

## Key Question

With all workers using mayor/rig/.beads via redirects, is beads-sync still needed?

## Commands

git log main..beads-sync --oneline | head -20
git diff main..beads-sync -- *.go | head -100


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

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


Deacon stuck-session detection and force-kill protocol

Deacon detects and kills genuinely stuck/hung Claude Code sessions.

## The Problem

Claude Code sessions can get stuck:
- Infinite loop / hung tool call
- Crashed but tmux session still exists
- Unresponsive to nudges

`gt rig boot` is idempotent (won't kill) - it only starts if not running.
Someone needs to detect stuck sessions and force-kill them.

## Detection Protocol

During Deacon health rounds:

1. **Ping test**: `gt nudge <agent> 'HEALTH_CHECK'`
2. **Wait for response**: Agent should update agent bead `last_activity`
3. **Timeout**: If no activity update within N seconds, mark suspicious
4. **Consecutive failures**: After M consecutive failures, declare stuck

## Force-Kill Protocol

When stuck detected:

```bash
# 1. Log the intervention
gt mail send <agent> -s 'FORCE_KILL: unresponsive' -m 'Deacon detected...'

# 2. Kill the tmux session
tmux kill-session -t <session-name>

# 3. Update agent bead state
bd update <agent-bead> --status=killed --reason='Deacon force-kill: unresponsive'

# 4. Notify mayor (optional, for visibility)
gt mail send mayor/ -s 'Agent killed: <agent>' -m 'Reason: unresponsive...'
```

## Recovery

After force-kill, the agent is 'asleep'. Normal wake mechanisms apply:
- `gt rig boot` restarts it
- Or stays asleep until next activity trigger

## Parameters (configurable)

- ping_timeout: 30s (how long to wait for response)
- consecutive_failures: 3 (how many before force-kill)
- cooldown: 5m (minimum time between force-kills of same agent)

## NOT Deacon's Job

- Graceful shutdown (agent does this itself)
- Context-based recycling (agent self-handoffs)
- Normal backoff/sleep transitions

Deacon only force-kills when agent is genuinely unresponsive.


Remove gt mail dependency on bd mail commands

Replaced bd mail send/inbox/read/ack with bd create/list/show/close. Messages are now stored as beads issues with type=message.


Merge: gt-svi.1

type: merge-request
branch: polecat/Max
target: main
source_issue: gt-svi.1
rig: gastown


Formula validation specification

Complete validation rules for formulas:
- Required vs optional fields
- Valid step ID patterns
- Valid pointcut glob syntax
- Variable reference validation
- Compose rule ordering constraints
- Type-specific validation (workflow vs expansion vs aspect)

Deferred: post-launch polish


Digest: mol-deacon-patrol

Patrol 12: routine


Work on ga-y6b: Implement Refinery as Claude agent. Conve...

Work on ga-y6b: Implement Refinery as Claude agent. Convert from shell to Claude agent that processes MRs in merge queue, runs tests, merges to integration branch. When done, submit MR (not PR) to integration branch for Refinery.


Digest: mol-deacon-patrol

Patrol 17: all clear


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

Patrol 12: All healthy


inspect-workers

Capture output for each working polecat.

```bash
gt peek <rig>/<polecat>
```

Needs: survey-workers


Refactor formula transformation pipeline to shared helper

The formula transformation pipeline (control flow, advice, expansions, aspects) is duplicated between cook.go and mol_bond.go. Should be extracted to a shared function in the formula package.

Current duplication in:
- cmd/bd/cook.go:96-136
- cmd/bd/mol_bond.go:598-633

Suggested approach:
- Add formula.Transform(resolved *Formula, parser *Parser) (*Formula, error)
- Handles all transformation steps in order
- Both cook.go and mol_bond.go call this single function


Digest: mol-deacon-patrol

Patrol 4: Quick cycle, all quiet


Digest: mol-deacon-patrol

Patrol cycle 14: nominal


Digest: mol-deacon-patrol

Patrol 6: all quiet


Refinery-Witness communication protocol

Define mail protocol between Refinery and Witness:

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

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

Implement as structured mail with parseable format.


Digest: mol-deacon-patrol

Patrol 7: OK


CLI: worker status reporting commands

Worker status reporting CLI for polecats to report progress.

## Commands

### gt worker started
```
gt worker started <issue-id> [-m MESSAGE]
```
Reports work started on issue.

### gt worker progress
```
gt worker progress <issue-id> <0-100> [-m MESSAGE]
```
Reports percentage complete.

### gt worker blocked
```
gt worker blocked <issue-id> <reason> [-m MESSAGE]
```
Reports blocked status with reason.

### gt worker completed
```
gt worker completed <issue-id> [-m MESSAGE]
```
Reports task completion.

### gt worker failed
```
gt worker failed <issue-id> <reason> [-m MESSAGE]
```
Reports task failure.

## Implementation
Each command sends mail to refinery with structured content:
```go
type WorkerStatusReport struct {
    IssueID    string
    Status     string  // started|progress|blocked|completed|failed
    Progress   int     // 0-100 for progress
    Reason     string  // for blocked/failed
    Message    string  // optional detail
    ReportedAt time.Time
}
```

## Message Format
Subject: "[STATUS] <issue-id>: <status>"
Body: JSON-encoded WorkerStatusReport

## Default Recipient
```go
// Determine from context
func getDefaultRecipient() string {
    rig := os.Getenv("GT_RIG")
    if rig != "" {
        return rig + "/refinery"
    }
    return "refinery/"
}
```

## New File
internal/cmd/worker.go

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

## Acceptance Criteria
- [ ] All 5 commands implemented
- [ ] Status sent as mail to refinery
- [ ] Structured JSON body for parsing
- [ ] Works from polecat session context


Crew agent beads never created (dead code in reportAgentState)

## Problem

In prime.go, reportAgentState is called for ALL roles including crew workers.
The function calls bd.UpdateAgentState for crew with ID like gt-crew-gastown-max.

But crew agent beads are NEVER created:
- Polecats: Created on spawn (polecat/manager.go:167)
- Infrastructure: Created by doctor/install (doctor/agent_beads_check.go)
- Crew: Nothing creates them

The error is silently ignored, so this doesn't break anything, but it's dead code.

## Found in commit

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

## Decision

**Create crew agent beads** on first gt prime if they don't exist.

Crew workers are human-managed but their state is still valuable for:
- Town-wide status dashboards
- Understanding who's working on what
- Consistent agent bead model across all agent types

## Implementation

In prime.go reportAgentState(), before calling UpdateAgentState:
1. Try to get the agent bead
2. If it doesn't exist, create it with CreateAgentBead
3. Then update state as normal


Merge: gt-qz2l

branch: polecat/dementus
target: main
source_issue: gt-qz2l
rig: gastown


Replaceable notifications via Claude Code queue

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

## Problem

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

## Solution

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

## Implementation

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

## Research Needed

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


Selection operators: glob, filter, children

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

Used by advice, expansion, and aspects for targeting.


Digest: mol-deacon-patrol

Patrol 15: Green


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

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

## Two Points to Add Instructions

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

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

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

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

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


Verify architecture.md shows correct harness and rig structure

Review architecture.md diagrams:
- Verify town-level structure shows harness correctly
- Confirm rig-level mayor/rig/ is shown (it appears to be there at line 197)
- Check mermaid diagrams match ASCII diagrams
- Update if any inconsistencies found
- Cross-reference with new harness.md docs


Merge: capable-1767074974673

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 6: All healthy, no messages


Refactor builtin_molecules.go (1620 lines)

## Summary

builtin_molecules.go is 1620 lines and growing. Should be split into:
- builtin_molecules.go - registration and common helpers
- molecules_patrol.go - patrol molecules (deacon, witness, refinery)
- molecules_work.go - work molecules (polecat-work, ready-work, engineer-in-box)
- molecules_session.go - session wrappers (crew-session, polecat-session)

## Benefits
- Easier to find/edit specific molecules
- Smaller diffs on changes
- Clear categorization


Witness Role Definition

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

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

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

## Core Responsibilities

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

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

## Propulsion Principle

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

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

## Nudge Protocol

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

## Pre-Kill Verification

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

## Commands

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


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy


Digest: mol-deacon-patrol

P9: stable


Refinery tmux status: show merge queue length

Add refinery-specific status line showing:
- MQ length (pending merges)
- Currently processing item (if any)
- Maybe: success/failure counts

Implement in runRefineryStatusLine() in internal/cmd/statusline.go


Digest: mol-deacon-patrol

Patrol 16: All clear


Digest: mol-deacon-patrol

Patrol cycle 19: nominal


🤝 HANDOFF: Timing fixes applied

Fixed mayor attach timing bug. Completed: timing fix, gt-tulx, Emma beads-6v2. Remaining P1: gt-17zr, gt-kcee, gt-szsq. Run gt prime on startup.


Add accounts.yaml config parsing to gt

Parse ~/gt/mayor/accounts.yaml with structure: accounts map (handle -> email, config_dir) and default field. This is the foundational config that other account features depend on. Location follows existing town-level config pattern in mayor/.


Extract SupportedShells constant to constants package

Extract repeated shell list to a single constant.

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

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

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

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


Digest: mol-deacon-patrol

Patrol 17: clear


Proto debugging and inspection tools

Proto debugging and inspection tools.

With ephemeral protos (gt-4v1eo), this becomes:
- `bd cook <formula> --dry-run` - preview cooked output without persisting
- `bd cook <formula> --json` - output proto as JSON for inspection
- `bd cook <formula> --graph` - visualize step DAG

No persistent proto beads to inspect - formulas are the source of truth.


Deacon patrol molecules stored in wrong beads location

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


Digest: mol-deacon-patrol

Patrol 13: all healthy


Digest: mol-deacon-patrol

Patrol cycle 20: final before handoff


Digest: mol-deacon-patrol

Patrol 10: Quick cycle, 50% to handoff


Patrol formulas: Inconsistent variable placeholder syntax

The patrol formulas use inconsistent syntax for variable placeholders:

## Inconsistency

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

## Expected

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

## Fix

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


gt swarm status fails to find issues via rig discovery

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


Update config location: .gastown/ → config/

Move rig configuration from hidden .gastown/ to visible config/:
- config/rig.json: Rig configuration
- config/engineer.json: Engineer settings (test command, etc.)
- config/witness.json: Witness settings (heartbeat interval, etc.)

Hidden directories are poorly discovered by AI agents.


Polecats should auto-cleanup after MR submission

Currently polecats must manually run 'gt handoff --shutdown' after completing work. This is error-prone and leaves stale polecats around.

## Desired Flow

1. Polecat completes work
2. Polecat runs 'gt mq submit' (or similar)
3. MR is added to integration queue
4. **Polecat automatically cleans up** (no manual handoff needed)

## Implementation Options

### Option A: mq submit triggers cleanup
In 'gt mq submit':
1. Submit MR to queue
2. Automatically run cleanup (same as gt handoff --shutdown)
3. Polecat session terminates

### Option B: Refinery triggers cleanup
When Refinery picks up MR:
1. Refinery processes MR
2. Sends message to Witness: 'CLEANUP: <polecat>'
3. Witness cleans up polecat

### Option C: Molecule-driven
Define cleanup as final phase of polecat-work molecule:
1. code → test → submit-mr → cleanup

## Note
This reinforces the ephemeral model: polecats exist only for the duration of a single task.


Test message

Testing GGT mail integration


Digest: mol-deacon-patrol

Patrol 9: Quiet


Deacon Kernel: event processing molecule architecture

Extend the Deacon from "health orchestrator" to "event processing kernel" that runs a
molecule (rounds) each wake cycle, like an OS kernel scheduler.

## Core Insight

The Deacon already has:
- Wake cycle (daemon poke, timer, lifecycle request)
- Mail as event queue
- Health scanning
- Lifecycle processing

But it is REACTIVE. This epic makes it PROACTIVE with a structured molecule:

```
Deacon Wake
├── Step 0: Session Check (should I cycle myself?)
├── Step 1: Health Scan (Mayor, Witnesses, Crew, Refineries)
├── Step 2: Lifecycle Processing (cycle/restart/shutdown requests)
├── Step 3: Plugin Execution (scheduled, event-triggered, human-requested)
├── Step 4: Event Callbacks (timers, subscriptions)
└── Step 5: Heartbeat + Wait
```

## Key Design Decisions

1. **Session cycling first** - Token costs are quadratic with session length.
   Deacon should aggressively cycle to fresh sessions. First step of every
   wake is "do I need a new session?" based on context budget.

2. **Pinned bead with marching orders** - A pinned bead (like gt prime for
   agents) defines the Deacon's rounds molecule. This is the Deacon's
   "kernel" - its operating loop.

3. **Keepalive file for daemon quieting** - Instead of daemon tmux-poking
   the Deacon (which interrupts work), Deacon writes a keepalive file.
   Daemon reads it and backs off. Worst case: Deacon forgets, gets one
   extra heartbeat it squelches.

4. **Molecule-based rounds** - The wake cycle becomes a molecule with steps.
   Each step can have plugins (inline attention). Steps can be added/modified
   by updating the pinned bead.

## Architecture

```
Go Daemon (minimal, dumb)
├── Reads {townRoot}/deacon/keepalive.json
├── If fresh: do nothing
├── If stale: poke Deacon (fallback)
└── Process lifecycle requests (still daemon's job)

Deacon (Claude agent, smart)
├── Wakes: poke, timer, mail event
├── Writes keepalive (quiets daemon for duration of rounds)
├── Runs rounds molecule:
│   ├── session-check: cycle if context budget low
│   ├── health-scan: check agents, remediate
│   ├── lifecycle: process requests
│   ├── plugins: run scheduled/triggered plugins
│   ├── events: process timer/event callbacks
│   └── complete: update heartbeat, wait
└── Reads marching orders from pinned bead
```

## Relation to Existing Work

- Extends gt-5af (Deacon infrastructure) - CLOSED
- Relates to gt-axz (Plugin architecture) - P3
- Fits into phase3-deacon of gt-ngpz (Christmas Plan)
- Enables gt-976 (Crew lifecycle) as part of health-scan step


Digest: mol-deacon-patrol

Patrol 17: Quiet


Inconsistent error wrapping patterns

Error handling is inconsistent across the codebase:

1. Some functions use fmt.Errorf with %w for wrapping, others don't
2. return nil, nil patterns (40+ occurrences) sometimes represent 'not found' and sometimes 'error but continue' - should use sentinel errors
3. Some places return nil for errors when they should propagate them

Examples of nil,nil that might need review:
- internal/git/git.go:272, 308
- internal/crew/manager.go:227
- internal/witness/manager.go:517, 523, 530, 775
- internal/beads/beads.go:225, 492


Merge: gt-3x0z.2

branch: polecat/nux
target: main
source_issue: gt-3x0z.2
rig: gastown


Consider splitting large files (800+ lines)

Several files are getting large and may benefit from splitting:
- internal/beads/beads.go (990 lines)
- internal/cmd/molecule.go (981 lines)
- internal/refinery/manager.go (934 lines)
- internal/beads/beads_test.go (883 lines)
- internal/cmd/polecat.go (836 lines)
- internal/witness/manager.go (808 lines)
- internal/cmd/mail.go (804 lines)

For .go files, consider extracting logical subsystems. For test files, this is lower priority.


ensure-gastown-refinery

Start the gastown rig Refinery.

## Action
```bash
gt refinery start gastown
```

## Verify
1. Session exists: `tmux has-session -t gastown-refinery 2>/dev/null`
2. Not stalled: `gt peek gastown/refinery` does NOT show "> Try" prompt
3. Queue processing: Refinery can receive merge requests

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

## OnFail
Log error. Completed polecat work will queue until Refinery recovers.


gt-gastown-polecat-nux

gt-gastown-polecat-nux

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-5o2l0
role_bead: gt-polecat-role
cleanup_status: clean


Digest: mol-deacon-patrol

Patrol 4: routine