Witness pre-kill verification protocol

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

## Protocol for Witness Prompting

```markdown
## Pre-Kill Verification Protocol

Before killing any worker session, verify workspace is clean.

### Verification Steps

When a worker signals done:

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

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

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

### Nudge Templates

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

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

### Kill Sequence

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

### Escalation

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

## Implementation

Add to WITNESS_CLAUDE.md template.


Digest: mol-deacon-patrol

Patrol 7: routine, all healthy


Merge: furiosa-1767059690595

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


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
```


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.


Refinery as Worktree: Local MR Integration

Move refinery from separate clone to git worktree. Polecats stop pushing to origin - refinery sees their branches locally. MRs become wisps (ephemeral). Only main gets pushed after merge.

## Goals
- Origin stays clean (only main + beads-sync branches)
- No orphaned polecat branches ever
- Simpler mental model for MR coordination
- Faster integration (no network for local MR ops)

## Trade-offs
- Machine crash = redo pending work (acceptable, beads track state)
- Future federation needs different approach (bundles or integration branch)

## Components Affected
- Rig initialization (refinery setup)
- Spawn/polecat workflow (remove origin push)
- Refinery manager (local branch access)
- Documentation (architecture, workflows)
- Molecule templates (remove push instructions)


Digest: mol-deacon-patrol

Patrol #17


Digest: mol-deacon-patrol

Patrol 10: Midpoint, all healthy


Refinery background daemon mode

The refinery 'gt refinery start' command only works in foreground mode (--foreground). Need to implement background daemon mode for production use.

Options:
1. Use a separate tmux session for the refinery
2. Implement proper daemonization
3. Use Claude Code session for the refinery agent

For MVP, option 1 (tmux session) is probably simplest.


Digest: mol-deacon-patrol

Patrol #1: All agents healthy, no messages, no orphans


Support nested expansion formulas


gt polecat done should auto-stop running session

Currently 'gt polecat done' fails if session is running, requiring a separate 'gt session stop' first. This is unnecessary friction - done should just stop the session automatically since that's always what you want.


Witness startup: bond mol-witness-patrol on start

Wire up Witness to automatically bond its patrol molecule on startup.

## Desired behavior
On Witness session start:
1. gt prime detects RoleWitness
2. Check for existing in-progress patrol
3. If found: resume from current step
4. If not found: bd mol bond mol-witness-patrol --wisp
5. Output patrol context to agent

## Depends on
- gt-83k0 (mol-witness-patrol definition)
- gt-caih (handoff bead state persistence)


Simplify Go daemon to Deacon-watcher

Refactor internal/daemon to only: (1) check deacon/heartbeat.json every 60s, (2) poke gt-deacon if stale, (3) restart Deacon and mail for help if very stale. Remove all lifecycle processing and agent poking.


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.


Create patrol formula YAML files

Create formula YAML files for:
- mol-deacon-patrol.formula.yaml
- mol-witness-patrol.formula.yaml
- mol-refinery-patrol.formula.yaml

Use the step definitions currently in molecules_patrol.go as reference.
Store in .beads/formulas/


Document harness concept in docs/harness.md

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


Merge: gt-h6eq.3

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


Rename engineer-in-box to shiny across all docs

Systematic rename of mol-engineer-in-box to shiny throughout docs: molecular-chemistry.md, molecules.md, architecture.md, etc. The shiny name is now canonical per the Breaking Bad × Mad Max naming.


Digest: mol-deacon-patrol

Patrol 3: All healthy, routine


Digest: mol-deacon-patrol

Patrol 5: clear


Digest: mol-deacon-patrol

Patrol 13: all clear


Polecat CLAUDE.md update for hook execution

Update polecat role CLAUDE.md to include hook execution instructions.

## Key Additions

### Startup Protocol

```markdown
## Startup Protocol

When you wake up:

1. **Check your hook first**
   Run: gt prime
   This shows your assigned work.

2. **If hook has molecule**
   You are running a workflow. Execute the current step.
   When done: bd mol advance <mol-id>

3. **If hook has slung bead**
   Work on that specific issue.
   Claim it: bd update <id> --status=in_progress

4. **If hook empty**
   Wait for assignment via mail or spawn.
```

### Work Completion

```markdown
## Completing Work

When you finish your assigned issue:

1. Commit changes: git add && git commit -m "description (issue-id)"
2. Push branch: git push -u origin <branch>
3. Create MR bead: bd create "Merge: <issue-id>" --type=merge-request
4. Close issue: bd close <issue-id> --reason "Fixed in commit abc123"
5. Sync: bd sync
6. Signal done: gt mail send witness/ -s "LIFECYCLE: Done" -m "Completed <issue-id>"
```

### Exit States

```markdown
## Exit States

When finishing, signal your state:

- COMPLETED: Work done successfully
- BLOCKED: Cannot proceed, need help
- ESCALATE: Problem beyond your scope
- HANDOFF: Passing to successor
```

## File

templates/polecat/CLAUDE.md


Digest: mol-deacon-patrol

Patrol 20: Mayor OK, 11 sessions


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

Patrol 12: quiet


Digest: mol-deacon-patrol

Patrol 10: Routine


Work request: gt-976 crew lifecycle support

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

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

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

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

- Dave (beads/crew/dave)


Digest: mol-deacon-patrol

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


Swarm doesn't track dynamically added workers

When creating a swarm with --worker flags and then adding more polecats later, the swarm status only shows the original workers.

Steps to reproduce:
1. gt swarm create gastown --epic gt-i26df --worker slit --worker rictus --start
2. Add more polecats: gt polecat add gastown capable
3. gt sling gt-xxx gastown/capable
4. gt swarm status gt-i26df -> only shows slit, rictus

Expected: Swarm tracks all workers that are working on swarm tasks.
Actual: Only original workers shown.


Rewrite role templates without step lists

Update:
- prompts/roles/deacon.md
- prompts/roles/refinery.md
- prompts/roles/witness.md

Templates should describe HOW to run patrols (propulsion principle, bd mol current, bd close --continue) not WHAT the steps are. Steps come from proto beads.


Test message

Testing GGT mail system


Digest: mol-deacon-patrol

P11: stable


Digest: mol-deacon-patrol

Patrol cycle 5: routine, healthy


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

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


Digest: mol-deacon-patrol

Cycle 14: quiet


ensure-beads-refinery

Start the beads rig Refinery.

## Action
```bash
gt refinery start beads
```

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

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

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


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

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

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

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

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


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

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

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

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

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

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

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


Plugin system: subprocess JSON protocol

Language-agnostic plugin system via subprocess JSON protocol.

## Concept

Allow extending Gas Town with external scripts/programs. Plugins communicate via stdin/stdout JSON.

## Protocol

Request (gt → plugin):
```json
{"method": "check", "params": {"rig": "wyvern", "polecat": "Toast"}}
```

Response (plugin → gt):
```json
{"result": {...}, "error": null}
```

Error response:
```json
{"result": null, "error": {"code": 1, "message": "..."}}
```

## Interface

```go
type Plugin struct {
    Name    string
    Path    string  // executable path
    Methods []string
}

type PluginManager struct {
    plugins map[string]*Plugin
}

func NewPluginManager() *PluginManager
func (pm *PluginManager) Register(plugin *Plugin) error
func (pm *PluginManager) Call(plugin, method string, params any) (any, error)
func (pm *PluginManager) Discover(dir string) error  // auto-discover plugins
```

## Plugin Discovery

Look in:
1. `<town>/plugins/`
2. `~/.config/gastown/plugins/`
3. System path with `gt-plugin-*` prefix

## Built-in Hooks

Plugins can register for events:
- `polecat.started` - Polecat session started
- `polecat.done` - Polecat signals done
- `merge.requested` - MR submitted
- `merge.completed` - MR merged

## Use Cases

- Custom health checks
- Integration with external systems (Slack, etc.)
- Custom merge policies
- Metrics collection

## Future

Consider MCP integration for richer plugin capabilities.


Digest: mol-deacon-patrol

Patrol cycle 3: routine check, all healthy


Keepalive signal from bd/gt commands

Every bd and gt command should touch a keepalive file to signal 'agent is alive/working'.

## Implementation

Touch `<workspace>/.gastown/keepalive.json`:
```json
{"last_command": "bd show gt-99m", "timestamp": "2025-12-18T13:45:00Z"}
```

## Usage by Daemon

- Fresh (< 2 min) → agent is working, skip heartbeat
- Stale (2-5 min) → might be thinking, gentle poke
- Very stale (> 5 min) → likely idle, safe to interrupt

## Benefits

- Zero cost (just file I/O)
- Works during long tool calls
- Doesn't require agent cooperation
- Foundation for smarter backoff strategies


Digest: mol-deacon-patrol

Patrol 12: Quiet


Mail CLI: archive, purge, search, mark

GGT mail CLI needs more commands for mail management.

## Commands to Add

### gt mail check
Check for new mail without full inbox display.
```
gt mail check [--quiet] [--inject]
```
- --quiet: Only output if new mail (for scripts)
- --inject: Send notification to running session

### gt mail mark
Change read status.
```
gt mail mark <id> --read
gt mail mark <id> --unread
```

### gt mail delete
Remove message from inbox.
```
gt mail delete <id> [--force]
```
- Confirm unless --force

### gt mail archive
Move old/read messages to archive.
```
gt mail archive [--older-than DAYS] [--all-read] [--dry-run]
```
- Creates inbox.jsonl.archive or separate archive.jsonl

### gt mail purge
Permanently delete archived messages.
```
gt mail purge [--older-than DAYS] [--dry-run] [--force]
```

### gt mail search
Find messages by content.
```
gt mail search <query> [--from SENDER] [--subject] [--body]
```

### gt mail reply
Reply to a message.
```
gt mail reply <id> -m BODY
```
- Auto-sets reply_to and thread_id
- Auto-addresses to original sender

## Files to Modify
- internal/cmd/mail.go: Add commands
- internal/mail/mailbox.go: Add Archive(), Search(), Delete()

## Acceptance Criteria
- [ ] All commands implemented
- [ ] Archive stores in separate file
- [ ] Search supports regex patterns
- [ ] Delete confirms by default


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

Patrol 5: All healthy


Digest: mol-deacon-patrol

P7: escalation for mayor (wrong-rig work)


Campaign: Large-Scale Work Graph Execution

A Campaign is a Molecule-wrapped Epic graph ready for orchestrated execution.

## Concept

Campaign = Molecule + Epics + Dependency Graph + Execution Strategy

Key properties:
1. **Work graph**: Linked epics with dependency edges (possibly from different authors)
2. **Combinators as glue**: >>, |, wrap define bridging/shaping between epics
3. **Molecule shell**: Provides execution state, persistence across sessions
4. **Witness-aware**: Can be parallelized across polecats on independent branches
5. **Single-rig scoped**: One rig executes it (spans sessions/polecats)

## The "Maximum Speed" Model

Witness becomes a scheduler that:
- Watches campaign progress
- Identifies ready nodes (all dependencies satisfied)
- Spawns/assigns polecats to ready nodes
- Respects parallelism constraints
- Handles failures (retry? skip? escalate?)

## Where Campaign Fits in MEOW

Campaign is the convergence point where work-tracking meets workflow-execution:
- An Epic-of-Epics (work dimension)
- A Molecule (workflow dimension)

## Open Questions

1. Campaign creation UX - manual wire vs declare intent?
2. Partial completion - can you commit progress and resume?
3. Distinct entity type or molecule with type="campaign"?
4. Cross-rig campaigns - can graph span multiple rigs?

## Related

- docs/formula_evolution.md - original discussion
- gt-8tmz - molecule algebra (foundation)


Consolidate design docs into beads descriptions

The markdown design docs (swarm-shutdown-design.md, polecat-beads-access-design.md, mayor-handoff-design.md) will decay. Extract key decisions and prompting templates into the beads descriptions themselves, then archive or remove the markdown files. Beads are the source of truth.


Digest: mol-deacon-patrol

Patrol 12: healthy


Mail inbox from witness/refinery dirs shows Mayor inbox

When running `gt mail inbox` from the witness or refinery directories, it shows the Mayor's inbox instead of the agent's own inbox.

Reproduction:
```
$ cd ~/gt/beads/witness && gt mail inbox
📬 Inbox: mayor/ (1 messages, 1 unread)
  ● 🤝 HANDOFF: Swarm session complete...
```

Expected: Should show beads/witness inbox

Likely cause: The cwd-based identity resolution isn't recognizing witness/refinery as valid mail identities, so it falls back to Mayor.


Formula error handling and recovery

Specify how cooking errors are reported and recovered:
- What happens when extends chain is broken (missing formula)?
- What happens when aspect pointcut matches nothing?
- What happens when expansion produces invalid structure?
- Graceful degradation vs fail-fast semantics
- Error metadata in cooked protos

Deferred: post-launch polish


gt-gastown-polecat-cheedo

gt-gastown-polecat-cheedo

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


CLI: rig commands (list, show, add)

Rig management CLI commands.

## Commands

### gt rig list
List all registered rigs.
```
gt rig list [--json]
```
Output:
- Rig name
- Git URL
- Polecat count
- Witness/Refinery status

### gt rig show
Show details for a specific rig.
```
gt rig show <name> [--json]
```
Output:
- Full rig info
- Polecats with status
- Recent activity
- Beads summary (open issues)

### gt rig add
Add a new rig to the town.
```
gt rig add <name> <git-url>
gt rig add <name> --local <path>
```
Steps:
- Clone repo to town root (or link local)
- Register in rigs.json
- Create agent directories
- Configure git exclude

### gt rig remove
Remove a rig from the town.
```
gt rig remove <name> [--force]
```
- Warns if active polecats
- --force required if uncommitted changes

## Implementation

```go
var rigCmd = &cobra.Command{Use: "rig"}
rigCmd.AddCommand(rigListCmd, rigShowCmd, rigAddCmd, rigRemoveCmd)
```


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


Harness & Priming: Document architecture and update all role contexts


Daemon patrol should clean stale locks

The gt daemon patrol cycle should detect and clean up stale locks.

## Problem
If daemon crashes or there are orphaned locks, they can block operations indefinitely.

## Proposed Solution
During patrol cycle:
1. Check for lock files older than threshold (e.g., 5 minutes)
2. Verify owning process is dead (check PID if stored)
3. Remove stale locks
4. Log cleanup for audit


MEOW Stack Evolution: Higher-Order Workflow Abstractions

Molecular Expression of Work (MEOW) - the full taxonomy of workflow abstractions.

## Current Hierarchy

```
WORK TRACKING              WORKFLOW EXECUTION
─────────────              ──────────────────

Bead (issue)               Step (action)
    │                          │
    ▼                          ▼
Epic (bead group)          Molecule (runtime)
    │                          │
    ▼                          │
    └───────► CAMPAIGN ◄───────┘
                  │
                  ▼
             Schematic (domain template)
                  │
                  ▼
             Protocol (interface/type)
                  │
                  ▼
             Catalyst (meta-generator)
                  │
                  ▼
             Mol Mall (distribution)
```

## Key Concepts

1. **Campaign** (gt-camx5): Molecule-wrapped Epic graph for orchestrated execution
2. **Schematic** (gt-8ws7o): Domain-level formula composition
3. **Protocol** (gt-y3jb9): Type system for formulas
4. **SDK** (gt-ihzqr): Developer tooling (Forge, Lab, Validator)
5. **Mol Mall** (gt-vm85o): Package registry for distribution

## Design Principles

- Chemistry metaphor: atoms → molecules → compounds → materials
- Two orthogonal dimensions: work tracking × workflow execution
- Campaign is the convergence point
- Everything compiles down to executable molecules

## Origin

Discussion: 2024-12-26, Mayor session
Related: docs/formula_evolution.md
Foundation: gt-8tmz (Molecule Algebra)


gt mail: Cross-level routing is broken

When Mayor sends mail to rig worker, message lands in wrong beads database. Sender's beads vs recipient's.


Digest: mol-deacon-patrol

Patrol 9: All healthy


Digest: mol-deacon-patrol

Patrol 14: All healthy, 2 crew active


Proto marketplace: shareable molecule templates

Enable sharing protos between Gas Town installations.

## Vision

A public registry of protos that users can pull and use:

```bash
gt proto search "code review"
gt proto install gastown/code-review
gt sling code-review gastown/Toast --wisp
```

## Registry Design

### Local Catalog
`~/gt/molecules/` - user-defined and installed protos

### Remote Registry
`registry.gastown.dev/protos/` (future)
- Browse online catalog
- Version-controlled protos
- Rating/reviews
- Usage statistics

## Proto Package Format

```
gastown-code-review-1.0.0/
├── PROTO.md          # Main proto definition
├── README.md         # Usage documentation
├── LICENSE           # Usage terms
└── plugins/          # For pluggable molecules
    ├── security/
    └── performance/
```

## Commands

```bash
gt proto list              # Show installed protos
gt proto search <query>    # Search registry
gt proto install <name>    # Install from registry
gt proto publish <path>    # Publish to registry
gt proto update            # Update all installed
```

## For Now

Start with local catalog. Marketplace is future phase.
Ensure proto format is registry-compatible from the start.


Work reconciliation module

Port reconcile.py work verification to Go.

## Purpose

Verify assigned issues are completed before landing.

## Interface

```go
type ReconcileResult struct {
    CompletedIssues  []IssueInfo
    IncompleteIssues []IssueInfo
    AllComplete      bool
    PolecatsChecked  []string
    Errors           []string
}

func ReconcileWork(rig string, polecats []string) *ReconcileResult
func GetAssignedIssues(assignee string) []IssueInfo
func UnassignIssue(issueID string, resetStatus bool) error
```

## Logic

1. Get list of polecats in swarm
2. For each polecat, query beads for assigned issues
3. Categorize as completed (closed) or incomplete (open/in_progress)
4. Return summary for landing decision

## Handling Incomplete Work

If issues incomplete:
- Abort landing (default)
- Or force landing (leaves work unfinished)
- Unassign incomplete issues for future work

## Reference

PGT: swarm/reconcile.py


Witness role template + CLAUDE.md

Create the Witness agent's role context:

1. internal/templates/roles/witness.md.tmpl
   - Witness responsibilities (polecat lifecycle)
   - Core loop description
   - Commands available (gt polecats, bd ready, etc)
   - Escalation protocol

2. Generate CLAUDE.md for witness/ directories
   - Context about the rig
   - Mail address: <rig>/witness
   - Startup protocol (gt prime, check inbox)

The Witness is the per-rig 'pit boss' - NOT a global coordinator. It manages polecats for ONE rig only.


Witness: bond mol-polecat-arm when discovering polecat

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

## Changes to witness/manager.go

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

## Arm Lifecycle

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

## Deduplication

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


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


Config directory and schema for messaging

Create ~/gt/config/ directory structure for messaging configuration.

## Deliverables

1. Create ~/gt/config/ directory
2. Define JSON schema for lists.json:
   ```json
   {
     "oncall": ["mayor/", "gastown/witness"],
     "cleanup/gastown": ["gastown/witness", "deacon/"]
   }
   ```
3. Define JSON schema for queues.json (if separate from lists)
4. Add config loading utility in internal/config/

## Acceptance
- Config directory exists
- Schema documented
- Load/parse functions work


load-context

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

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


CLI API Audit: gt and bd command structure review before OSS launch

# CLI API Audit for OSS Launch

Before launching Gas Town + Beads as an SDK, we need to ensure the command-line
API is intelligently designed, consistent, intuitive, and structurally sound.

## Current State Audit

### gt (Gas Town) - 50+ top-level commands

**Agent Lifecycle:**
- `gt mayor`, `gt deacon`, `gt witness`, `gt refinery` - agent management
- `gt polecat` - worker management (subcommands: add, remove, list, etc.)
- `gt crew` - persistent workspace management
- `gt spawn` - create polecat with work

**Work Lifecycle:**
- `gt spawn` - assign work to new polecat
- `gt sling` - hook work + start immediately
- `gt hook` - attach work durably
- `gt handoff` - pass work to fresh session
- `gt done` - signal work complete
- `gt release` - release stuck issues

**Infrastructure:**
- `gt daemon`, `gt up`, `gt down`, `gt start`, `gt stop`, `gt shutdown`
- `gt init`, `gt install`, `gt doctor`

**Communication:**
- `gt mail` (subcommands: send, inbox, read, etc.)
- `gt nudge`, `gt broadcast`

**Molecules:**
- `gt molecule` / `gt mol` (17 subcommands!)

### bd (Beads) - Well-categorized but some sprawl

**Core CRUD:**
- `bd create`, `bd show`, `bd update`, `bd close`, `bd list`

**Molecules:**
- `bd mol` (5 subcommands: catalog, show, bond, run, distill)
- `bd wisp` (3 subcommands: create, gc, list)
- `bd pour` (top-level alias for instantiation)
- `bd cook` (compile formula to proto)

**Hook/Pin:**
- `bd pin` - attach mol to agent hook
- `bd unpin` - remove from hook
- `bd hook` - inspect what's on hook

## Structural Concerns

### 1. gt is sprawling (50+ top-level commands)

Many commands could be subcommands:
```
# Current                      # Could be
gt up/down/start/stop         gt daemon {up|down|start|stop}
gt spawn/sling/hook/handoff   gt work {spawn|sling|hook|handoff}
gt mayor/deacon/witness       gt agent {mayor|deacon|witness|...}
```

### 2. Overlap between gt and bd

| Concept | gt | bd |
|---------|----|----|
| Hook | `gt hook` | `bd pin`, `bd hook` |
| Mail | `gt mail` | `bd mail` (delegates) |
| Molecules | `gt mol` (17 cmds) | `bd mol` (5 cmds) |

Which owns what? User confusion likely.

### 3. Naming inconsistencies

- `gt polecat` (noun) vs `gt spawn` (verb) - both about polecats
- `gt done` vs `gt handoff` - both end work but different
- `bd mol run` vs `bd pour` - both instantiate

### 4. Subcommand depth decisions

**Good patterns:**
- `bd mol {catalog|show|bond|run|distill}` - coherent group
- `gt mail {send|inbox|read|archive}` - coherent group

**Questionable patterns:**
- `bd create --wisp` AND `bd wisp create` - two ways to do same thing
- `gt spawn --molecule X` AND `gt mol instantiate` - overlap

### 5. Flag vs subcommand guidelines needed

When to use flags vs subcommands?
- `--json` as flag ✓ (modifier)
- `--wisp` as flag for create? Or separate `bd wisp create`?
- `--molecule` on spawn? Or separate workflow?

## Recommendations to Evaluate

### A. Consolidate gt top-level commands

Group related commands:
```
gt agent {mayor|deacon|witness|refinery|polecat}
gt work {spawn|sling|hook|handoff|done}
gt infra {daemon|up|down|doctor}
```

### B. Clarify gt vs bd ownership

| Domain | Owner | Other defers |
|--------|-------|--------------|
| Issues | bd | gt uses bd |
| Agents | gt | bd doesn't touch |
| Molecules | bd mol | gt mol wraps for UX |
| Hooks | bd pin/hook | gt hook wraps |
| Mail | gt mail | bd mail delegates |

### C. Apply consistent naming

- All agent commands: nouns (`gt polecat`, `gt mayor`)
- All work commands: verbs (`gt spawn`, `gt sling`, `gt hook`)
- Avoid synonyms: pick one term and stick with it

### D. Flag vs subcommand rule

- Flags: modify behavior of command (`--json`, `--force`, `--wisp`)
- Subcommands: distinct operations (`mol run`, `mol squash`, `mol burn`)
- Exception: very common operations can have top-level aliases

## Tasks

1. [ ] Review gt command groupings - propose consolidation
2. [ ] Review bd command groupings - check for sprawl
3. [ ] Document gt vs bd ownership boundaries
4. [ ] Identify and resolve naming inconsistencies
5. [ ] Document flag vs subcommand decision criteria
6. [ ] Create migration plan for any breaking changes
7. [ ] Update help text to be consistent
8. [ ] Test agent UX: can Claude guess commands correctly?

## Success Criteria

- New user can guess command structure intuitively
- `gt --help` fits on one screen (or is well-categorized)
- No duplicate functionality between gt and bd
- Consistent naming throughout
- Claude agents can discover commands without documentation


Phase 4.1: mol-deacon-patrol uses ephemeral

Deacon patrol cycles run as ephemeral molecules.

## Current Deacon Loop

```
while running:
    check_heartbeat()
    check_mail()
    sleep(interval)
```

## Molecule-Based Loop

```
while running:
    mol = bd mol bond mol-deacon-patrol-cycle --ephemeral
    execute_cycle(mol):
        check_heartbeat()
        check_mail()
        log_status()
    summary = generate_cycle_summary()
    bd squash mol --summary summary
    sleep(interval)
```

## Benefits

- Each cycle is tracked
- Digests show daemon health over time
- Can query: 'show me patrol cycles from last hour'
- Crash mid-cycle → ephemeral shows where we were


Day 3.6: Polecat closes steps for activity feed

**REVISED**: Step completion is for visibility, not session control.

Polecats close molecule steps as they complete them:
```bash
# After completing implement step:
bd close <step-bead-id>  # Or: mol step done implement
```

This provides:
1. **Activity feed visibility** - Observers see progress in real-time
2. **Audit trail** - Step completion timestamps in beads
3. **Stuck detection** - Witness can see 'long time on same step'

What this does NOT do:
- Trigger session recycle (polecat self-manages)
- Block next step (polecat continues immediately)
- Require Witness intervention

Implementation options:
- Option A: Polecat runs `bd close <step-id>` manually
- Option B: Formula `on_complete` hook auto-closes step bead
- Option C: `mol step done <step>` convenience command

Priority lowered: Nice-to-have for visibility, not launch-blocking.

**Dependency removed**: No longer depends on gt-zb0io (recycle between steps).


gt-polecat-gastown-testcat

gt-polecat-gastown-testcat

role_type: polecat
rig: gastown
agent_state: running
hook_bead: null
role_bead: null


Digest: mol-deacon-patrol

Patrol cycle 9: routine, healthy


Digest: mol-deacon-patrol

Patrol cycle 3: All healthy


Conditional aspects (feature flags)

Apply aspects conditionally based on environment or config. Example: apply security-audit only when env.SECURITY_SCANNING == enabled. Adds 'when' clause to aspect composition.


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


Digest: mol-deacon-patrol

Cycle 7: quiet


mol sling command: attach molecule to agent hook

Add `gt mol sling <molecule-id>` command to attach a molecule to the current agent's hook.

## Behavior

```bash
gt mol sling mol-witness-patrol
```

1. Find agent identity from cwd (witness, polecat, crew, etc.)
2. Find or create agent's handoff bead
3. Attach molecule to handoff bead (attached_molecule field)
4. Create root issue for this molecule instance
5. Instantiate molecule steps under the root

## Difference from mol attach

- `mol attach` attaches to an existing pinned bead
- `mol sling` creates a fresh instance for execution

## Output

```
🧬 Slung mol-witness-patrol on gastown/witness
  Instance: gt-xyz (9 steps)
  First step: inbox-check
```

## Implementation

- Reuse InstantiateMolecule from molecule.go
- Create wrapper issue for the instance
- Set attached_molecule on handoff bead


Remove legacy .beads-wisp/ infrastructure

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

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

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

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

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

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


Preflight molecule: verify baseline health before work

Before assigning work, verify baseline (main branch) is healthy.

**From VC**: Self-healing state machine (HEALTHY → SELF_HEALING → ESCALATED). ~200 lines.

**Gas Town implementation**: Preflight molecule or refinery feature:
```yaml
preflight:
  gates: [test, lint, build]
  on_failure: create-fix-issue
```

Run at session start. If baseline broken, file a P0 fix issue and work on that first.

**Value**: Self-healing baseline. Agents don't start from broken state.

**VC lesson**: Prevents cascading failures. Agent shouldn't start work on broken code.


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


Digest: mol-deacon-patrol

Patrol 10: all quiet


MQ metrics: pending count, processing time, success rate

Implement merge queue metrics collection.

Metrics to track:
- mq_pending_count: MRs waiting
- mq_processing_time: Time from submit to merge (histogram)
- mq_success_rate: Merges vs rejections
- mq_conflict_rate: How often conflicts occur
- mq_test_failure_rate: Test failures

Storage options:
- Simple: JSON file with rolling stats
- Advanced: Prometheus-compatible metrics endpoint

Display via:
- gt mq stats: summary statistics
- Dashboard widget (separate task)

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


Day 4.5: Test multi-step molecule lifecycle

Integration test (UPDATED for self-managed handoffs):
1. Sling work with molecule to polecat
2. Polecat works through all steps (self-handoffs as context fills)
3. Polecat calls gt done when work complete
4. Witness verifies clean state and sends MERGE_READY to refinery
5. Refinery merges branch
6. Refinery sends MERGED to witness
7. Witness calls gt polecat nuke for full cleanup
8. Verify clean state (no worktree, no branch, agent bead closed)

**VALIDATED**: rictus lifecycle worked end-to-end: gt done → witness → refinery → merged

Parent: gt-4a2qt


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)
```


Digest: mol-deacon-patrol

Patrol 17: All agents healthy


Recreate beads rigs with fresh clones

## Problem

Beads rigs have schema mismatches (missing thread_id column, etc.) from development iteration.

## Tasks

1. Shut down any active polecats
2. Delete existing beads rigs: mayor/rig, refinery/rig, witness/rig, crew/*
3. Re-clone from beads repo
4. Run bd init in each new clone

## Rigs to recreate

- /Users/stevey/gt/beads/mayor/rig
- /Users/stevey/gt/beads/refinery/rig
- /Users/stevey/gt/beads/crew/* (if any)

## Source

Clone from beads repo (need to confirm remote URL)


MessagingConfig: Add missing test cases

Missing test coverage:
1. Version > CurrentMessagingVersion rejection
2. Malformed JSON handling


gt mail: Cross-level routing is broken

**Problem:**
When Mayor (at ~/gt) sends mail to a rig worker (gastown/crew/max), the message lands in town-level beads (~/.beads/) but the recipient checks rig-level beads (crew/max/.beads/).

**Reproduction:**
```bash
cd ~/gt
gt mail send gastown/crew/max -s 'Test' -m 'body'
# Message goes to ~/gt/.beads/ with prefix hq-*

cd ~/gt/gastown/crew/max
gt mail inbox
# Does NOT see the message - it's looking in crew/max/.beads/
```

**Root cause:**
`findBeadsWorkDir()` walks up from CWD to find .beads. `Router.Send()` runs `bd create` in that directory. This means messages always go to the sender's beads, not the recipient's.

**Fix options:**
1. Route based on recipient address - if sending to rig/*, use that rig's .beads
2. Use a single shared beads database for all mail (simpler but less isolated)
3. Teach agents to check both levels (workaround, not fix)

**Related:**
- gt-ngu1: Pinned beads sorting (done but pointless if mail doesn't route)
- This blocks all cross-level mail functionality


gt feed: Activity feed command with tmux-aware modes

## Context

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

## Requirements

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

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

## Design Questions

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

## Implementation Options

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

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

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

## Related

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


Digest: mol-deacon-patrol

Patrol 12: All clear


Add unit tests for internal/mrqueue package

attached_args: mrqueue package tests

Add comprehensive tests for the merge request queue package.

## Files to create
- internal/mrqueue/mrqueue_test.go

## Test cases to cover
1. NewQueue creates queue directory
2. Add() persists MR to queue
3. Get() retrieves MR by ID
4. List() returns all MRs
5. Remove() deletes MR
6. MR serialization/deserialization
7. Queue handles concurrent access

## Acceptance criteria
- [ ] internal/mrqueue/mrqueue_test.go created
- [ ] At least 6 test functions
- [ ] Tests pass: go test ./internal/mrqueue/...
- [ ] Coverage > 70%


Digest: mol-deacon-patrol

Patrol 5: all quiet


Digest: mol-deacon-patrol

Patrol 16: Nominal


Digest: mol-deacon-patrol

Patrol 4: Stable


Digest: mol-deacon-patrol

Patrol 6: Quiet


Ephemeral patrol molecules leaking into beads

## Problem

Ephemeral patrol orchestration molecules (e.g., mol-deacon-patrol, wisp step issues) keep appearing in bd ready output in gastown beads.

These are ephemeral/wisp issues that should:
1. Never be synced to the beads-sync branch
2. Live only in .beads-wisp/ (ephemeral storage)
3. Be squashed to digests, not persisted as regular beads

## Examples found

- gt-wisp-6ue: mol-deacon-patrol
- gt-pacdm: mol-deacon-patrol
- gt-wisp-mpm: Check own context limit
- gt-wisp-lkc: Clean dead sessions

## Investigation needed

1. Where are these being created? (gt mol bond? manual bd create?)
2. Why are they using the gt- prefix instead of staying ephemeral?
3. Is the wisp storage (.beads-wisp/) being used correctly?
4. Is bd sync accidentally picking up ephemeral issues?

## Expected behavior

Patrol molecules and their steps should be ephemeral and never appear in bd ready or bd list.

Moved from bd-exy3.


load-context

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

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


Implement verification patterns for boot steps

Define and implement the verification logic Mayor uses.

## Verification Utilities

Mayor needs to check:

### Session Exists
```bash
tmux has-session -t <session> 2>/dev/null && echo "exists"
```

### Not Stalled (Claude waiting at prompt)
```bash
gt peek <agent> 10 | grep -q "> Try" && echo "stalled"
```

Pattern: `> Try "..."` indicates Claude started but no message sent.

### Recent Heartbeat
```bash
# For deacon
age=$(( $(date +%s) - $(stat -f %m ~/gt/deacon/heartbeat.json) ))
[ $age -lt 120 ] && echo "fresh"
```

### Active Work Output
```bash
gt peek <agent> 20 | grep -q "⏺" && echo "working"
```

Pattern: `⏺` indicates Claude is executing tools.

## Mayor Execution Pattern

```
for each step in molecule:
  run action
  loop:
    check verification
    if verified: close step, continue
    if stalled: run on_stall recovery
    if timeout (5 attempts): log warning, continue
    sleep 10s
```

No hard timeout - Mayor keeps trying with increasing backoff.


Document crew worker patrol integration

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


Digest: mol-deacon-patrol

Patrol #9


Work on ga-lue: Implement Witness as Claude agent. Conver...

Work on ga-lue: Implement Witness as Claude agent. Convert from shell script to Claude agent that monitors polecats, nudges idle ones, handles escalations. When done, submit MR (not PR) to integration branch for Refinery.


Mol Mall: Formula marketplace and aspect composition

## Summary

A marketplace for sharing molecule formulas using GitHub as backend, plus a new
**aspect composition** capability for cooking that allows formulas to be applied
as cross-cutting transformations to existing mols.

## Key Insight

Formulas aren't just standalone workflows—they're **transformations** you can
apply to other mols. This enables patterns like:
- "Apply Rule of Five code review to any coding task"
- "Wrap any epic with security review steps"
- "Add logging/metrics to any patrol molecule"

## Architecture

```
Remote Formulas (GitHub)
        ↓ install
Local Formulas (~/.gt/formulas/ or .beads/formulas/)
        ↓ cook --with
Mols (beads, git-tracked)
        ↓ pour/sling
Execution (ephemeral or tracked)
```

## Formula Types

1. **Standalone** - Complete workflows (mol-polecat-work, mol-deacon-patrol)
2. **Aspects** - Cross-cutting concerns woven into other mols (rule-of-five)
3. **Adapters** - Wrappers that make things runnable

## Aspect Composition (New Cooking Capability)

```bash
bd cook my-epic --with rule-of-five,security-review
```

Aspects declare injection points:

```yaml
# rule-of-five.formula.yaml
kind: aspect
name: rule-of-five
version: 1.2.0

inject_after:
  tag: generates-code  # matches any step with this tag

steps:
  - id: review-correctness
    title: "Review: Correctness"
  - id: review-edge-cases
    title: "Review: Edge Cases"
  - id: review-performance
    title: "Review: Performance"
  - id: review-security
    title: "Review: Security"
  - id: review-maintainability
    title: "Review: Maintainability"
```

Injection modes:
- `inject_after: <step-id or tag>` - insert steps after
- `inject_before: <step-id or tag>` - insert steps before
- `wrap: <step-id or tag>` - insert before AND after
- `replace: <step-id or tag>` - substitute entirely

## The Mall Index

A well-known repo maps short names to full references:

```yaml
# steveyegge/gt-mall/index.yaml
formulas:
  rule-of-five:
    repo: steveyegge/gt-formulas
    path: aspects/rule-of-five.formula.yaml
    version: v1.2.0
    description: "Five-lens code review"
    tags: [review, quality]
```

Commands:
- `gt mol search review` - search the index
- `gt mol install rule-of-five` - fetch from GitHub
- `gt mol install github.com/acme/formulas/custom@v1` - direct URL

## Implementation Phases

### Phase 1: Aspect Composition (Cooking)
- Extend `bd cook` to accept `--with aspect1,aspect2`
- Aspect application during mol generation
- Local aspects in `.beads/formulas/`

### Phase 2: Mall Index
- Create gt-mall repo with index.yaml
- `gt mol search` queries the index
- `gt mol install` fetches and caches formulas

### Phase 3: Publishing
- `gt mol publish` pushes to your formula repo
- PR workflow to add to mall index

### Phase 4: Refinements
- Aspect ordering and conflict detection
- Aspect dependencies (`requires: [other-aspect]`)
- Private formula repos (enterprise)
- Local overrides/forks

## Open Questions

1. **Ordering conflicts**: Two aspects inject after same step—which goes first?
2. **Aspect dependencies**: Aspect A requires aspect B?
3. **Compile-time vs runtime**: Aspects are compile-time (baked into mol).
   Wisps remain runtime (slung dynamically).

## Deferred Until

Gas Town patrols operational. Prerequisites:
- [ ] Patrol system working (Deacon, Witness, Refinery)
- [ ] Basic spawn/work/merge cycle
- [ ] Activity feed showing work progress

Then the mall becomes valuable for sharing patrol customizations.

## Supersedes

This replaces gt-uzf2l which had the original marketplace concept but lacked
the aspect composition insight.

## Related

- Cooking system (bd cook)
- Formula definitions (.formula.yaml)
- Wisp architecture (runtime molecules)

See docs/formula_evolution.md for expanded thinking on: formula resolution hierarchy, combinators (>>, |, wrap, inject, extends), algebraic properties, higher abstractions, Mol Mall registry predictions, distribution scenarios, and open questions. The aspect composition in this design corresponds to the Wrapping (AOP) and Injection combinators in that doc.


gt crew at/attach: Start session in crew workspace

Implement 'gt crew at <rig>/<name>' and 'gt crew attach <name>' commands:
- Start tmux session (optional - could just print cd instructions)
- Launch claude code in the workspace
- Deliver any pending mail
- Support --no-tmux to just print directory path
- 'attach' infers rig from cwd


Add WaitsFor parsing to molecule steps

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

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

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


Digest: mol-deacon-patrol

Patrol 3: All healthy


Merge: gt-3x0z.1

branch: polecat/furiosa
target: main
source_issue: gt-3x0z.1
rig: gastown


Digest: mol-deacon-patrol

Patrol 10: Quick cycle, 50% to handoff


Merge: gt-xw7b

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


gt-gastown-polecat-dag

gt-gastown-polecat-dag

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


Feed-Based Wake Model for Patrol Agents

## The Paradigm Shift

> **Backoff is not about polling less. It is about waiting for signals with a timeout.**

This epic captures the shift from time-driven to event-driven patrol wake.

## Key Insight (Recovered from 2025-12-29 session crash)

The Beads activity feed (bd activity --follow) is the universal data plane for
wake signals. Every meaningful action creates a beads mutation; agents subscribe to
the feed and wake within ~500ms. The timeout is just a safety net.

**OLD**: Time-driven. Wake because time passed. Poll less when idle.
**NEW**: Event-driven. Wake because signal arrived. Timeout is safety net.

## Architecture

ANY MUTATION:
  bd create/update/close -> issues.jsonl mutation
                        -> bd activity --follow sees it (~500ms)
                        -> All subscribed agents wake immediately

PATROL AGENT:
  Runs bd activity --follow as background source
  Any output line = wake signal
  Timeout expiry = safety net (not primary wake)

## Wake Sources (Priority Order)

| Source | Latency | Purpose |
|--------|---------|---------|
| Feed | ~500ms | Primary - any beads mutation |
| Nudge | Instant | Explicit wake (startup hooks) |
| Timeout | Backoff | Safety net for missed signals |
| Daemon | 5-60min | GUPP backstop, session recovery |

## Key Design Decisions

1. No wake_on conditions - signals carry no semantic meaning. Just wake up.
   Agent discovers reality by checking mail, beads, hook, git state.

2. Read-only commands do not wake - gt status, bd show create no mutations.

3. Daemon is recovery-focused - catches edge cases (GUPP violations, dead sessions).

4. Keepalive file deprecated - the feed replaces the keepalive mechanism.

## Reference

- ~/gt/docs/patrol-system-design.md (Sleeping Agents section)
- ~/gt/docs/PRIMING.md (Feed Is the Signal insight)

## Related

- gt-l6ro3: Patrol Exponential Backoff System (backoff timing, complements this)


Remove doctor staleness detection

**File:** doctor/stale_check.go (lines 11-48)

**Current behavior:**
- DefaultStaleThreshold = 1 hour hardcoded
- Scans molecules for in_progress status older than threshold
- Reports "stale" molecules automatically

**Fix:**
- Remove automatic staleness detection from doctor
- Doctor becomes pure diagnostic tool (reports facts, not judgments)
- Deacon molecule step does "orphan-check" instead:
  "Find issues in_progress with no active polecat"

**Lines to remove:**
- stale_check.go:13 (DefaultStaleThreshold constant)
- stale_check.go:243-256 (staleness classification logic)


Track merge requests as beads (type=merge-request)

Currently MRs are tracked in .gastown/refinery.json. For HOP audit trail and entity CV tracking, merge requests should be Beads entries with type=merge-request. This enables:
- Full audit trail of what was merged, when, by whom
- Entity chain contributions (who validated what)
- Cross-rig visibility of merge activity

The refinery would create an MR bead when work enters the queue, update status as it progresses (open → in_progress → merged/rejected).

Part of Beads-as-data-plane vision from HOP.


Check Witness and Refinery health

Check Witness and Refinery health for each rig.

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

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

**Signals to assess:**

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

**Tracking unresponsive cycles:**

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

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

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

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

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

Reset unresponsive_cycles to 0 when component responds normally.


gt crew add: CLAUDE.md customization leaves git dirty

When gt crew add generates a customized CLAUDE.md for crew workers, it differs from the repo version (Crew Worker Context vs Polecat Context, personalized footer). This leaves the git state 'dirty'.

Options:
1. Add CLAUDE.md to .gitignore in crew workspaces
2. Auto-commit the customized CLAUDE.md locally
3. Store crew CLAUDE.md content elsewhere (e.g., .claude/CLAUDE.md)

Current behavior is functional but 'gt crew list' shows 'Git: dirty' for new crew.

Found during: adding crew workers grip, fang, wolf


Show actor on pinned/status change events

Pinned events currently show no actor:

  [10:22:25] → gt-95j13 → pinned · Add tmux hotkey...

Should show who pinned it:

  [10:22:25] → gt-95j13 → pinned · Add tmux hotkey... @gastown/crew/joe

Part of epic gt-u7dxq


Digest: mol-deacon-patrol

Patrol 2: Quick scan, no changes


Digest: mol-deacon-patrol

Patrol 17: All healthy.


Digest: mol-deacon-patrol

Patrol 2: inbox empty, all agents healthy, fixed 1 orphan process


done

Exit received. Ready for cleanup.

The polecat has completed its work and sent SHUTDOWN.
Perform cleanup:
```bash
gt session kill {{polecat}}
gt worktree prune {{polecat}}
```

Update beads state and close the lease.
Variables: {{polecat}}, {{issue}}


Code Smell Cleanup: Gas Town Code Quality

Comprehensive code smell cleanup identified in code review session.

## Scope
Fixes for duplication, thread safety, missing tests, inconsistent patterns, and dead code.

## Child issues (18 total)

### Thread Safety & Data Integrity (P2)
- gt-wled7: Atomic write pattern for state files
- gt-xtsb5: Fix namepool Save() mutex
- gt-bp0ht: Add swarm.Manager mutex

### Duplication Removal (P2)
- gt-560ge: Extract processExists function
- gt-ddw3y: Extract molecule_lifecycle boilerplate
- gt-atqr8: Session name helper functions
- gt-ov2uv: AgentIdentity type for parsing

### Missing Tests (P2)
- gt-p2eg5: Lock package tests
- gt-0vu9e: mrqueue package tests
- gt-1pelm: mail router/mailbox tests

### Code Quality (P2)
- gt-gcnnr: Add logging for ignored errors

### Constants Extraction (P3)
- gt-4u682: SupportedShells constant
- gt-795e8: Timing constants

### Refactoring (P3)
- gt-tkbd5: Refactor runStart
- gt-dsqxw: Refactor runStartCrew

### Error Handling (P3)
- gt-h3skz: Remove os.Exit from RunE
- gt-g6kor: Standardize warning output

### Dead Code (P4)
- gt-2g130: Remove unused code

## Acceptance criteria
- [ ] All child issues closed
- [ ] go build ./... passes
- [ ] go test ./... passes
- [ ] go test -race ./... passes


Extract shared state load/save pattern to generic helper

Nearly identical loadState/saveState methods in:
- internal/witness/manager.go (lines 39-72)
- internal/refinery/manager.go (lines 63-96)
- internal/crew/manager.go (lines 257-306)

All use the same pattern: read JSON file, handle not-exists, unmarshal/marshal.

Suggestion: Create a generic stateStore[T any] helper in a shared package.


Ephemeral rig support for ad-hoc batch work

Support for temporary worker rigs for ad-hoc batch work.

## Use Case

Ad-hoc batch work where you want temporary workers:
- gt spawn --epic <epic-id> --ephemeral --workers 3
- Creates temp rig with 3 clones
- Workers process epic children
- Work merges through queue
- Clones cleaned up when done

## Interface

```go
type EphemeralRig struct {
    ID               string
    GitURL           string
    BaseCommit       string
    Workers          []string
    IntegrationBranch string
    EpicID           string  // associated epic (for cleanup trigger)
    CreatedAt        time.Time
}

func InitEphemeralRig(gitURL string, numWorkers int) (*EphemeralRig, error)
func (r *EphemeralRig) AddWorker(name string) error
func (r *EphemeralRig) Destroy(force bool) error
```

## Directory Structure

```
<rig>/ephemeral/
└── rig-a3f7/
    ├── config.json
    ├── Alice/     # clone
    ├── Bob/       # clone
    └── Carol/     # clone
```

## Cleanup Trigger

When all issues in the associated epic are closed AND merged, the ephemeral rig can be destroyed.

## Note

No swarm ID needed - the epic ID provides the grouping. Ephemeral rig is just a convenience for temporary clones.

## Reference

PGT: ephemeral.py (for structure, ignore swarm ID coupling)


Witness tmux status: show polecat count under management

Add witness-specific status line showing:
- Number of polecats under management
- Active/idle status
- Maybe: last nudge time, blocked count

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


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol cycle 2: All healthy. No callbacks, orphans, or gates.


#channel resolution for real-time broadcast

Wire tmux scanner into nudge system for #channel addresses.

## Deliverables

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

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

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

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


Deacon convoy patrol steps

New Deacon patrol steps for convoy orchestration.

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

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

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

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


Design: Deacon exponential backoff when town is idle

## Problem

When the user goes to sleep and all workers have stopped, the Deacon continues
polling at full speed (every daemon heartbeat). This wastes resources and creates
unnecessary log noise.

## Requirements

1. **Gradual slowdown**: Deacon patrol frequency should exponentially back off
   when there's no activity in the town.

2. **Wake on activity**: Any gt or bd command (human or agent) should reset
   the backoff immediately.

3. **Daemon coordination**: Deacon needs to "program" the daemon for next
   heartbeat duration.

## Design Considerations

### Option A: Daemon tracks last-activity timestamp
- Daemon mechanically slows heartbeat based on time since last activity
- Activity signal comes from gt/bd command hooks
- Simple, no Deacon state needed
- But: Daemon is "dumb" by design - adding intelligence here feels wrong

### Option B: Deacon tracks patrol-count-since-activity
- Deacon maintains counter (via label on patrol molecule or state.json)
- Each idle patrol increments counter, calculates next sleep
- Deacon tells daemon "wake me in X minutes"
- More complex but keeps intelligence in AI agent

### Option C: Discovery-based (preferred if feasible)
- Can we detect "no activity" without explicit counters?
- Ideas:
  - Compare current time to last git commit across all clones?
  - Check tmux activity timestamps?
  - Look at beads modification times?
- Pros: No state to manage
- Cons: May be expensive to compute, could miss activity

### Wake mechanism
- Hook on gt commands (gt.hooks.pre-command or similar)
- Hook on bd commands (bd.hooks.pre-command)
- Both should signal daemon (SIGUSR2?) or write to activity file
- Daemon reads activity file on each heartbeat, resets backoff if fresh

### Backoff schedule (strawman)
| Idle patrols | Next heartbeat |
|--------------|----------------|
| 0-5          | 5 min (default) |
| 6-10         | 10 min |
| 11-20        | 30 min |
| 21+          | 60 min (max) |

## Open Questions

1. Should tmux activity count as "activity"? (cursor movement, typing)
2. How does Deacon communicate next-heartbeat to daemon?
3. Where to store backoff state? (daemon state.json? deacon state.json? label?)
4. Should wake be instant (SIGUSR) or next-heartbeat?

## Implementation Sketch

Activity file written by hooks at ~/gt/daemon/activity.json:
- last_command: timestamp
- command: the gt/bd command that ran
- actor: who ran it


Digest: mol-deacon-patrol

Patrol 3: Quiet, all healthy


MR field parsing: extract structured fields from description

Parse merge-request beads to extract structured fields:
- branch: source branch name
- target: target branch (main or integration/xxx)
- source_issue: the work item being merged
- worker: who did the work
- rig: which rig
- merge_commit: (set on close)
- close_reason: (set on close)

Fields stored in description as YAML block or key: value lines.
Provide helper functions: ParseMRFields(issue) and SetMRFields(issue, fields).

Reference: docs/merge-queue-design.md#merge-request-schema


Deacon patrol banners: visual feedback on atom transitions

Print large ASCII banners when transitioning between patrol atoms.

## Problem

When the deacon progresses through patrol atoms (steps), there is no visual feedback.
The operator cannot easily see what the deacon is doing without reading the full output.

## Desired Behavior

Print banners on step start and completion:

  INBOX-CHECK - Checking for lifecycle requests, escalations, timers
  INBOX-CHECK COMPLETE - Processed 3 messages, 0 lifecycle requests

## Benefits

1. Scanability: Operator can glance at tmux and see what is happening
2. Progress tracking: Easy to see where in the patrol loop we are
3. Debugging: Clear demarcation between steps for troubleshooting

## Implementation Options

1. In deacon CLAUDE.md: Instruct agent to print banners
2. gt patrol step start/end: Commands that print banners
3. bd mol step hooks: Automatically on step transitions

## Related

- gt-id36: Deacon Kernel
- gt-rana: Patrol System


TODO: Check if issue is child of configured epic in Witness

witness/manager.go:688 has a TODO to filter issues by whether they're children of the configured epic. Currently this filter is skipped.


Digest: mol-deacon-patrol

Patrol 12: Quick cycle, all quiet


Digest: mol-deacon-patrol

Patrol 20: Final cycle, all clear, handoff triggered


Check own context limit

Check own context limit.

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

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

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

This enables the Deacon to burn and respawn cleanly.


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

Patrol 18: All healthy


Digest: mol-deacon-patrol

Patrol 10: clear


Test message

Test body


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


Add charmbracelet TUI dependencies (bubbletea, bubbles)

Add charmbracelet TUI framework dependencies.

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

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

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

Quick task, just adding deps.


Prompt templates: role contexts, nudge messages

Prompt templates for role contexts and messages.

## Template Types

### Role CLAUDE.md Templates

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

### Message Templates

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

## Implementation

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

type Templates struct {
    fs embed.FS
}

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

## Template Data

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

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

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

## Template Location

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

## Usage

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


Refinery startup: bond mol-refinery-patrol on start

Wire up Refinery to automatically bond its patrol molecule on startup.

## Current state
- mol-refinery-patrol exists in builtin_molecules.go
- prompts/roles/refinery.md describes the protocol
- Refinery doesn't auto-bond on startup

## Desired behavior
On Refinery session start:
1. gt prime detects RoleRefinery
2. Check for existing in-progress patrol: bd list --status=in_progress --assignee=refinery
3. If found: resume from current step
4. If not found: bd mol bond mol-refinery-patrol --wisp
5. Output patrol context to agent

## Implementation options
A) Add to gt prime (outputRefineryPatrolContext)
B) Add startup hook in refinery CLAUDE.md
C) Both (prime detects, template reinforces)

## Testing
- Start refinery session
- Verify patrol bonds automatically
- Kill mid-patrol, restart, verify resumes

## Depends on
- gt-3x0z.10 (existing issue for Refinery patrol)


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


Merge: gt-7919

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


Digest: mol-deacon-patrol

Patrol 10: Nominal - halfway point


gt nudge doesn't work with crew addresses

## Bug

`gt nudge beads/crew/dave "message"` fails because it uses the polecat session manager which produces wrong session names.

## Expected
Session name: `gt-beads-crew-dave` (hyphen)

## Actual
Session name: `gt-beads-crew/dave` (slash, from polecat manager)

## Root Cause

In nudge.go line 46-57, parseAddress returns polecatName=`crew/dave`, then SessionName keeps the slash.

## Fix

Detect `crew/` prefix and use crewSessionName() instead.


gt sling fails for terminated polecats even with --naked flag

## Problem
When a polecat terminates after completing work (submits MR, session ends), the polecat directory still exists but the tmux session is gone. Attempting to sling new work to that polecat fails:

```
gt sling bd-fa1q beads/Toast --naked
Error: resolving target: getting pane for gt-beads-toast: exit status 1
```

The `--naked` flag should bypass tmux pane requirements, but the error occurs during target resolution before the flag is checked.

## Expected Behavior
`gt sling <bead> <polecat> --naked` should:
1. Attach work to the polecat hook
2. Skip session creation (manual start later)
3. NOT require an existing tmux pane

## Workaround
Use crew workers instead (they have persistent sessions).

## Fix
Target resolution should check `--naked` flag before attempting pane lookup, or provide a way to respawn terminated polecats.


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 complete: inbox clear, no gates, all agents healthy, no orphans


gt prime molecule execution prompt

Enhance gt prime to show molecule execution prompts.

## When Hook Has Molecule

gt prime should output:

```markdown
## Your Patrol: mol-deacon-patrol

**Current Step:** inbox-check
**Status:** pending (ready to execute)

### Step: inbox-check

Handle callbacks from agents.

Check the Mayor inbox for messages from:
- Witnesses reporting polecat status
- Refineries reporting merge results
...

**EXECUTE THIS STEP NOW.**

When complete, close the step:
  bd close <step-id>

Then check for next step:
  bd ready
```

## Logic

1. Check if hook has pinned molecule (via handoff bead with attachment)
2. Use bd mol current to find current step (derives from open children)
3. Get step details from the bead itself
4. Format execution prompt
5. Include close command (NOT bd mol advance - that was rejected)

## Key Insight (from bd-hulf rejection)

Molecule execution state is DERIVED from which child beads are closed vs open.
No separate state.yaml files. bd mol current already does this correctly.

"Advancing" a molecule = closing the current step bead. The next step
is whichever child is now ready (unblocked).

## Different from Slung Work

Slung work (bead) says "work on this issue"
Molecule says "execute this step of this workflow"

Both use the hook, but prompts differ.

## Files

- internal/cmd/prime.go
- Uses bd mol current for step discovery


Per-epic config overrides: custom merge settings

Allow per-epic merge configuration overrides.

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

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

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

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


Add Gas Town theory of operation to all role primings

All roles (Mayor, Witness, Refinery, Polecat) should get basic GT architecture context: harness, rigs, agents, mail, beads workflow


Witness patrol: cleanup idle orphan polecats

Add patrol step to find and cleanup polecats that are idle with no assigned issue. These orphans occur when polecats crash before sending DONE or Witness misses the message. Patrol should verify git is clean before removing worktree. Part of gt-rana.


Merge: gt-a95

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


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

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


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.


attached_args: Refactor runStart into focused helper functions

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 9: Mayor OK, 11 sessions


Molecular Chemistry Cleanup: Fix inaccurate molecule depictions

## The Correct Model

According to molecular-chemistry.md, the hierarchy is:

Formula (YAML DSL) --cook--> Proto (template beads) --pour/wisp--> Mol/Wisp (actual work)

- **Formulas**: YAML files in .beads/formulas/ that define workflow structure
- **Cook**: Transform formula to proto beads (with [template] label)
- **Proto**: Template beads with child beads for each step
- **Pour**: Proto to Mol (persistent liquid)
- **Wisp**: Proto to Wisp (ephemeral vapor)

## What's Wrong

We have legacy code and docs that use the OLD model where molecules are defined
in Go code as structs with embedded markdown, instead of as formula YAML cooked into proto beads.

---

## MAJOR ISSUES

### 1. Go Code: molecules_*.go (DELETE OR REWRITE)

**Files:**
- internal/beads/builtin_molecules.go
- internal/beads/molecules_patrol.go (19KB!)
- internal/beads/molecules_session.go (13KB)
- internal/beads/molecules_work.go (13KB)

**Problem:** Defines molecules as Go structs with embedded markdown descriptions.
This is completely wrong. Molecules should come from:
1. Formula YAML files cooked into proto beads
2. Proto beads with child beads for each step

**Used by:**
- install.go:seedBuiltinMolecules() - seeds during install
- catalog.go - includes in catalog
- molecule_list.go:ExportBuiltinMolecules()

**Fix:** Delete these files. Create formula YAML files instead. Update seeding
to cook formulas into protos.

### 2. Role Templates: Steps Listed in Markdown (REWRITE)

**Files:**
- prompts/roles/deacon.md - Lists 7 patrol steps
- prompts/roles/refinery.md - Lists 10 patrol steps
- prompts/roles/witness.md - Procedural "Heartbeat Protocol" (not molecule-based!)
- prompts/roles/polecat.md - References molecule steps

**Problem:** The steps are listed in the markdown template, but they should be
discovered from the proto beads via bd mol current. Templates should say
"check your hook, run your patrol" without duplicating step definitions.

**Fix:** Templates should describe HOW to run a patrol (propulsion principle,
bd mol current, bd close --continue), not WHAT the steps are.

### 3. Protos are Empty/Missing (CREATE)

**Current state:**
- gt-iep9 (mol-deacon-patrol) - Only 2 child steps
- gt-qflq (mol-witness-patrol) - EMPTY (0 children)
- mol-refinery-patrol - DOESN'T EXIST

**Fix:** Create formula YAML files for each patrol, cook them into proper protos
with child beads for each step.

---

## MEDIUM ISSUES

### 4. Command Confusion: spawn vs pour/wisp

**Files:**
- prompts/roles/deacon.md - Uses bd mol spawn ... --assignee=deacon
- prompts/roles/refinery.md - Uses bd mol spawn ... --wisp
- Various docs

**Problem:** The correct commands per molecular-chemistry.md:
- bd pour proto - Create persistent mol (liquid)
- bd wisp proto - Create ephemeral wisp (vapor)
- bd mol spawn - Old/deprecated

**Fix:** Update all references to use bd wisp for patrols, bd pour for
persistent work.

### 5. Command Confusion: gt mol vs bd mol

**Files:** Various docs and templates

**Problem:** Some use gt mol status, others bd mol status. Need to clarify:
- gt mol = Gas Town wrapper (if it exists, what does it add?)
- bd mol = Beads molecule commands (authoritative)

**Fix:** Audit and standardize. If gt mol is a thin wrapper, remove it.

### 6. polecat-wisp-architecture.md (UPDATE OR DELETE)

**File:** docs/polecat-wisp-architecture.md

**Problem:** References adding molecules to builtin_molecules.go - old model.

### 7. manager.go (UPDATE)

**File:** internal/rig/manager.go

**Problem:** Comment references "subset of builtin_molecules.go for seeding"

---

## IMPLEMENTATION ORDER

1. **Create formula YAML files** for the 3 patrol molecules:
   - mol-deacon-patrol.formula.yaml
   - mol-witness-patrol.formula.yaml
   - mol-refinery-patrol.formula.yaml

2. **Implement bd cook** if not already working to create protos from formulas

3. **Cook the formulas** into proto beads with proper child beads

4. **Update role templates** to use propulsion principle without step lists

5. **Delete molecules_*.go** once formulas are working

6. **Update install.go** to cook formulas instead of seeding Go structs

7. **Audit gt mol vs bd mol** and standardize


Outpost configuration: YAML config and OutpostManager

## Overview

Configuration file for outposts and manager to load/track them.

## Config File

`~/ai/config/outposts.yaml`:

```yaml
outposts:
  - name: local
    type: local
    max_workers: 4

  - name: gce-burst
    type: ssh
    host: 10.0.0.5
    user: steve
    ssh_key: ~/.ssh/gce_worker
    town_path: /home/steve/ai
    max_workers: 8

  - name: cloudrun-burst
    type: cloudrun
    project: my-gcp-project
    region: us-central1
    service: gastown-worker
    max_workers: 20
    cost_cap_hourly: 5.00

policy:
  default_preference: [local, gce-burst, cloudrun-burst]
  overrides:
    - condition: "priority >= P3"
      prefer: cloudrun-burst
```

## OutpostManager

```go
type OutpostManager struct {
    outposts map[string]Outpost
    policy   AssignmentPolicy
}

func NewOutpostManager(configPath string) (*OutpostManager, error)
func (m *OutpostManager) Get(name string) (Outpost, bool)
func (m *OutpostManager) List() []Outpost
func (m *OutpostManager) SelectOutpost(issue Issue) Outpost
```

## Files

- `internal/outpost/manager.go`
- `internal/outpost/config.go` (extend)
- `internal/outpost/policy.go`

Depends on: gt-9a2.1 (interfaces)


Digest: mol-deacon-patrol

Patrol 14


Delete molecules_*.go files

Remove legacy Go-defined molecules:
- internal/beads/builtin_molecules.go
- internal/beads/molecules_patrol.go
- internal/beads/molecules_session.go
- internal/beads/molecules_work.go

Update install.go to cook formulas instead of seeding Go structs.
Update catalog.go if needed.


Fix potential race conditions in state file operations

Non-atomic state file operations could cause data loss:

All packages with state files (witness, refinery, crew, swarm):
State is loaded, modified, and saved without locking:
  ref, err := m.loadState()
  // ... modify ref ...
  return m.saveState(ref)

If two processes modify state simultaneously, one update may be lost.

internal/polecat/namepool.go (lines 179-194):
Save() uses RLock() but performs file I/O - should use write lock.

internal/swarm/manager.go:
swarms map[string]*Swarm accessed without mutex but multiple goroutines could call Create/GetSwarm.

Suggestion:
1. Use file locking (flock) for critical state updates
2. Or use atomic write pattern (write to temp, then rename)
3. Add mutex to swarm.Manager.swarms map


Digest: mol-deacon-patrol

Patrol 2: all healthy, no action needed


Fix TestHasPolecat test failure


Glass Cockpit: See WTF is happening

Glass cockpit - see what's happening across the system.

Phase 1 got the engine running. Phase 2 makes it observable.

**Pillars:**
- Pillar 4: Swarm-in-Beads (gt-kc7yj - already exists)
- Pillar 5: MQ Observability
- Pillar 6: Witness Observability
- Pillar 7: Unified Dashboard

**Success criteria:**
1. gt status shows per-rig queue depth and agent health
2. gt feed shows MQ and swarm lifecycle events
3. gt dashboard provides live system visibility
4. No .runtime/*.json files for observable state
5. Swarms fully tracked in beads

Reference: ~/gt/docs/liftoff-plan.md


Mail orchestrator daemon

Background mail orchestrator daemon.

## Command
```
gt mail orchestrate [--interval N] [--once] [--verbose]
```

## Purpose
Background process that:
1. Monitors outbox for pending mail
2. Delivers to recipient inboxes
3. Handles offline recipients (retry later)
4. Cleans delivered messages from outbox

## Why Needed?
Current mail is synchronous. If recipient is offline or mailbox locked, send fails.
Orchestrator enables async delivery with retry.

## Implementation
```go
func (o *Orchestrator) Run(interval time.Duration) error {
    ticker := time.NewTicker(interval)
    for range ticker.C {
        o.processOutbox()
    }
}

func (o *Orchestrator) processOutbox() {
    // List outbox/*.json
    // For each, attempt delivery
    // On success, delete from outbox
    // On failure, increment retry count
}
```

## Outbox Structure
```
<town>/mayor/mail/outbox/
├── msg-abc123.json
└── msg-def456.json
```

## Lower Priority
Current synchronous delivery works. Orchestrator is optimization.

## Acceptance Criteria
- [ ] Background daemon mode
- [ ] Retry failed deliveries
- [ ] --once for single pass
- [ ] Configurable interval


gt-gastown-polecat-keeper

gt-gastown-polecat-keeper

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


BUG: gt handoff --dry-run still sends mail

In handoff.go, the dry-run check happens AFTER sendHandoffMail() is called. This means --dry-run still sends mail.

**Location**: handoff.go L126-143

**Observed**: Testing with `gt handoff --dry-run -s 'Test' -m 'Message'` actually sent mail to mayor.

**Fix**: Move mail sending inside the non-dry-run block, or check dry-run first.

```go
// Current (buggy):
if handoffSubject \!= "" || handoffMessage \!= "" {
    sendHandoffMail(...)  // Executes even in dry-run\!
}
if handoffDryRun {        // Too late
    return nil
}

// Should be:
if handoffDryRun {
    // show what would happen
    return nil
}
// Then send mail
```


Digest: mol-deacon-patrol

Patrol 19


Digest: mol-deacon-patrol

Patrol cycle 17: nominal


Digest: mol-deacon-patrol

Patrol 14: all healthy


Digest: mol-deacon-patrol

Patrol 9: all healthy


Digest: mol-deacon-patrol

Patrol 8: All healthy, no messages


gt crew add: role_bead field references non-existent bead

## Problem

When `gt crew add` creates an agent bead (e.g., `gt-crew-gastown-grip`), it sets:
```
role_bead: gt-crew-gastown-grip-role
```

This is WRONG. It creates per-instance role bead references that don't exist.

## Correct Pattern

Role beads are SHARED templates defining what a role IS. Agent beads reference them:

| Role Type | Role Bead (shared) | Agent Bead (per-instance) |
|-----------|-------------------|---------------------------|
| Mayor | gt-mayor-role | gt-mayor |
| Deacon | gt-deacon-role | gt-deacon |
| Witness | gt-witness-role | gt-witness-<rig> |
| Refinery | gt-refinery-role | gt-refinery-<rig> |
| Crew | gt-crew-role | gt-crew-<rig>-<name> |
| Polecat | gt-polecat-role | gt-polecat-<rig>-<name> |

## Current State

Working correctly:
- gt-mayor → gt-mayor-role ✅
- gt-witness-gastown → gt-witness-role ✅
- gt-refinery-gastown → gt-refinery-role ✅

Broken:
- gt-deacon → gt-deacon-role (bead doesn't exist)
- gt-crew-* → gt-crew-<rig>-<name>-role (wrong pattern, beads don't exist)
- gt-polecat-* → (not set at all)

## Code Locations

1. `internal/cmd/crew_add.go:91` - sets `RoleBead: crewID + "-role"`
   Should be: `RoleBead: "gt-crew-role"`

2. `internal/polecat/manager.go:220,426` - doesn't set RoleBead
   Should set: `RoleBead: "gt-polecat-role"`

## Fix Required

1. Create missing role beads: gt-crew-role, gt-polecat-role, gt-deacon-role
2. Fix crew_add.go to use shared gt-crew-role
3. Fix polecat/manager.go to use shared gt-polecat-role
4. Update existing crew agent beads to point to gt-crew-role


Digest: mol-deacon-patrol

Patrol 9: all clear


Verify gt daemon start/stop works

Verify the daemon orchestrator:

```bash
gt daemon start   # Should start and stay running
gt daemon status  # Should show running
gt daemon stop    # Should stop cleanly
```

The daemon is responsible for:
- Respawning the deacon when it exits (context exhaustion)
- Heartbeat monitoring
- Clean shutdown coordination

Test: Start, verify deacon session appears, stop, verify clean exit.


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-qwyu - The source issue ID being worked on


Digest: mol-deacon-patrol

P9: stable


Town root .beads has schema mismatch with bd

The .beads directory at town root (/Users/stevey/gt/.beads) has an incompatible schema:

```
Error: failed to open database: failed to initialize schema: sqlite3: SQL logic error: no such column: thread_id
```

Meanwhile, gastown/.beads (symlinked to mayor/rig/.beads) works fine.

## Impact

- gt mail inbox fails at town root
- gt handoff sends mail to broken db
- Daemon can't check its inbox

## Options

1. Delete town root .beads/beads.db and let it recreate
2. Symlink town root .beads to gastown/.beads
3. Run schema migration on existing db

## Root Cause

Likely a beads version upgrade that added thread_id column, but the town root db was created before that.


Batch wisp squashing in Deacon maintenance

Add wisp squashing to Deacon's maintenance duties:
- Patrol plugin to find orphaned/completed wisps across all rigs
- Squash completed patrol wisps to digests
- Burn abandoned wisps that have no audit value
- Part of the hygiene/cleanup system

Also: Witness polecat shutdown should spawn its own short wisp for the cleanup protocol.


Add hook-singleton doctor check

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

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


Digest: mol-deacon-patrol

Patrol 9: All clear


Post-work discovery: AI analysis finds follow-on issues

AI analyzes completed work to discover: bugs, punted work, follow-on tasks.

**From VC**: Supervisor.AnalyzeResult() with iterative refinement. ~300 lines.

**Gas Town implementation**: Post-work hook in molecule:
```yaml
post_work:
  discover:
    - bugs
    - punted_items
    - follow_on_work
  file_as: beads
```

Polecat output gets analyzed by AI, discovered work becomes beads issues.

**Value**: Nothing gets forgotten. VC found ~25% more issues with refinement.

**Key**: Use semantic deduplication (gt-xxx) to avoid pollution.


Town-level beads: Real DB for coordination mail

Implement Option A from mail redesign: Town gets real beads DB for coordination.

## Background

Mail is now Beads. But currently:
- Town .beads/redirect points to rig beads
- mayor/mail/ has legacy JSONL files
- Cross-rig coordination has no clear home

## Design

Town beads = coordination, cross-rig mail, mayor inbox, handoffs
Rig beads = project issues, work items

Matches HOP hierarchy: platform > project > worker

## Structure

~/gt/
  .beads/           # REAL beads DB (prefix: gm-)
  mayor/
    town.json
    state.json      # NO mail/ directory
  gastown/
    .beads/         # Rig beads (prefix: ga-)

## Tasks

1. Delete ~/gt/.beads/redirect
2. Run bd init --prefix gm at ~/gt/ (town beads)
3. Delete ~/gt/mayor/mail/ directory
4. Update gt mail to use beads not JSONL
5. Add mail fields (thread_id, reply_to, msg_type)
6. Update gt prime for two-tier model
7. Update docs/architecture.md

## Addressing

- mayor/ -> town beads
- rig/agent -> rig beads
- Cross-rig -> town beads


Patrol agent state.json not updated on activity

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

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

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

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

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


Digest: mol-deacon-patrol


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


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


Test4

test4 body


Digest: mol-deacon-patrol

Patrol 4: Routine


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.


Witness arm bonding integration test

Test witness with 3 polecats. Verify: arms bonded per worker, each arm captures/assesses independently, aggregation waits for all arms, witness proceeds after aggregation.


Work on gt-ogr: Fix rig count in tmux status bar. The cou...

Work on gt-ogr: Fix rig count in tmux status bar. The count is showing wrong. Run 'bd show gt-ogr' for details.


Digest: mol-deacon-patrol

Patrol 15: all healthy, doctor pass


Digest: mol-deacon-patrol

Patrol 13: clear


Digest: mol-deacon-patrol

Patrol 2: All agents healthy, no actions


Human and mail gates

Implement human:<prompt> gate (requires explicit approval command). Implement mail:<pattern> gate (waits for mail matching pattern). These enable async human-in-loop workflows.


Digest: mol-deacon-patrol

Patrol 11: All green


Day 3.6: Witness pings Deacon for second-order monitoring

Implement WITNESS_PING protocol for second-order monitoring.

Witnesses collectively monitor Deacon health:
1. Each Witness sends WITNESS_PING to Deacon during patrol
2. Deacon responds (or doesn't if dead)
3. If no response after threshold, Witness escalates to Mayor

This prevents the 'who watches the watchers' problem - if Deacon dies, Witnesses detect it.

Implementation:
- Add WITNESS_PING step to mol-witness-patrol
- Deacon acknowledges pings (updates last_activity)
- Witness checks Deacon agent bead last_activity
- Escalate if stale beyond threshold


Day 5.2: Fix integration issues

Address any issues found in Day 5.1:
- Debug failures
- Fix edge cases
- Retry integration test
- Document remaining gaps

This is buffer time for reality.

Parent: gt-oki8p