Fire notifications

Fire notifications for convoy and cross-rig events.

After convoy completion or cross-rig dependency resolution, notify relevant parties.

**Convoy completion notifications:**
When a convoy closes (all tracked issues done), notify the Overseer:
```bash
# Convoy gt-convoy-xxx just completed
gt mail send mayor/ -s "Convoy complete: <convoy-title>" \
  -m "Convoy <id> has completed. All tracked issues closed.
      Duration: <start to end>
      Issues: <count>

      Summary: <brief description of what was accomplished>"
```

**Cross-rig resolution notifications:**
When a cross-rig dependency resolves, notify the affected rig:
```bash
# Issue bd-xxx closed, unblocking gt-yyy
gt mail send gastown/witness -s "Dependency resolved: <bd-xxx>" \
  -m "External dependency bd-xxx has closed.
      Unblocked: gt-yyy (<title>)
      This issue may now proceed."
```

**Notification targets:**
- Convoy complete → mayor/ (for strategic visibility)
- Cross-rig dep resolved → <rig>/witness (for operational awareness)

Keep notifications brief and actionable. The recipient can run bd show for details.


Digest: mol-deacon-patrol

Patrol 117: All healthy


Digest: mol-deacon-patrol

Patrol #12


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

Patrol 5: all healthy, 2 crews (dave, max) active


Digest: mol-deacon-patrol

Patrol 3: all healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Move disk 1: A → B

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


Mol Mall: Formula marketplace using GitHub as backend

Create a marketplace for sharing molecule formulas using GitHub repos as the hosting backend.

## Architecture

Formulas ──cook──→ [ephemeral proto] ──pour/wisp──→ Mol/Wisp
    ↑                                                    │
    └────────────────── distill ─────────────────────────┘

- Formulas: JSON source files (.formula.json) - the thing you share
- Protos: Transient compilation artifacts - auto-deleted after use
- Mols/Wisps: Execution instances - not shared directly

## Key operations
- bd distill <mol-id> → Extract formula from completed work
- bd mol publish <formula> → Share to GitHub
- bd mol install <url> → Fetch from GitHub
- bd pour <formula> → Cook and spawn (proto is ephemeral)

## Migrated from beads rig (bd-1dez)
Completed: distill, formula add, versioning, installation tracking
Remaining: install, update, search, publish


gt-crew-gastown-joe

gt-crew-gastown-joe

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


gt status: Show agent hook_bead (current work) in status output

attached_args: Implement the hook_bead display in gt status. The agent bead lifecycle is complete - just need to read hook_bead and display it.

## Current State

gt status shows agents with their agent_state from beads:
```
   crew/max       ✓ running [running]
```

## Enhancement

Show what each agent is working on (hook_bead field from agent beads):
```
   crew/max       ✓ running [running] → gt-abc (Fix auth bug)
   crew/joe       ✓ running [running] → gt-xyz (Add tests)
   refinery       ✓ running → refinery Handoff
```

This gives the overseer a quick view of:
1. Who is running
2. What each agent is working on
3. Progress at a glance

## Implementation

In status.go, when displaying agents:
1. Look up agent bead by ID (e.g., gt-crew-gastown-max)
2. Parse hook_bead from description
3. If hook_bead set, fetch its title for display
4. Show as: agent_state → hook_bead (title truncated)

## Related

The agent bead lifecycle is now complete:
- prime.go creates agent beads
- sling.go sets hook_bead
- done.go clears hook_bead and sets final state


Digest: mol-deacon-patrol

Patrol 2: all healthy, no callbacks, no gates, no orphans, no plugins


Polecat template: move session close checklist into molecule steps

Template has prose checklists for 'Before Signaling Done' and 'SESSION CLOSE PROTOCOL'. These should be encoded as tail steps in the polecat molecule, not repeated as prose in CLAUDE.md. Reduces duplication and ensures the steps are actually followed.


Remove bd sync instruction from polecat startup workflow

Polecats are instructed to run `bd sync --from-main` on startup (spawn.go:634).

## Problem
- Spawn command already syncs beads before spawning (line 239)
- Polecats share rig-level beads via `.beads/redirect`
- Multiple polecats starting simultaneously all try to sync same shared beads
- This causes git conflicts/failures when many polecats spawn at once

## Observed
User reported: 'all polecats failing on beads sync on startup in one run'

## Fix
Remove line 634 from buildWorkAssignmentMail():
```
body.WriteString("2. Run \`bd sync --from-main\` to get fresh beads\n")
```

Polecats only need to sync at END of work (already in steps 5/7).

## Files
- internal/cmd/spawn.go: buildWorkAssignmentMail() and buildSpawnContext()


Add gt deacon start/stop/status commands

Add CLI commands: gt deacon start (spawn gt-deacon session), gt deacon stop (kill session), gt deacon status (show health state). Similar to gt mayor commands.


Digest: mol-deacon-patrol

Patrol 20: Green - routine cycle complete, handing off


Spawn --molecule integration

Implement gt spawn --molecule flag for molecule-based polecat workflows.

Usage: gt spawn --issue gt-xyz --molecule mol-gastown-polecat

Behavior:
1. Validate molecule exists and is well-formed
2. Create molecule instance (child beads) under the issue
3. Find first ready step(s) in the instance
4. Spawn polecat with first ready step as initial work

Implementation:
1. Add --molecule flag to spawn command
2. Call molecule.Instantiate()
3. Query ready steps from instance
4. Pass first ready step to polecat context

Files: internal/cmd/spawn.go

Acceptance:
- --molecule flag works
- Creates proper molecule instance
- Polecat starts on first ready step
- End-to-end test with actual polecat


MQ summary in gt status

Add per-rig MQ summary to gt status output.

Current gt status shows:
  gastown
    refinery  ✓ running

Add:
  gastown
    refinery  ✓ running
    MQ: 4 pending, 1 in-flight

Implementation:
- Query beads for merge-request type issues
- Count by status (open=pending, in_progress=in-flight)
- Display in rig section


Test Polecat Arm

Test child for bonding pattern


mol-deacon-patrol


Move disk 1: A → B

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


Success handling: close MR, close source issue, cleanup

Handle successful merge completion.

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

Configuration:
- delete_merged_branches: bool (default true)

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 5: All healthy


Move disk 1: A → B

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


Burn and respawn or loop

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

Decision point at end of patrol cycle:

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

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

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

This enables infinite patrol duration via context-aware respawning.


Merge: furiosa-1767082251065

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


Swarm-in-Beads: Discovery-based swarm execution

Swarm-in-Beads: Make swarm state derive from beads, not separate JSON. See ~/gt/docs/swarm-architecture.md for full design. Core principles: discovery over tracking, ready front model, nondeterministic idempotence.


Merge: gt-3x0z.4

branch: polecat/rictus
target: main
source_issue: gt-3x0z.4
rig: gastown


Burn and respawn or loop


Witness: detect polecat completion and trigger merge

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

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

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

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

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

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


Move disk 2: B → A

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


Move disk 1: A → B

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


Session ended: gt-gastown-nux


Digest: mol-deacon-patrol

Patrol 14: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol 18: All clear


Merge: slit-mjtj9dc8

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


Merge: gt-0ei3

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


Move disk 2: A → B

Move disk 2 from peg A to peg B.


Digest: mol-deacon-patrol

Patrol 9


Move disk 1: B → C

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


Merge: gt-ldk8

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


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 7: OK


More branches to process?

More branches to process?

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

Track: branches processed, branches skipped (with reasons).

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


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

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


gt handoff: Deadlock in waitForRetirement


gt doctor: Detect and clean up orphaned sessions/processes

## Problem
Orphaned tmux sessions and Claude processes accumulate over time, consuming memory.

## Discovered Orphans
- gt-deacon: Idle Claude session, not part of any rig

## Proposed Solution

### gt doctor --check (default)
Detect issues without fixing:
- Orphan sessions (not matching rig/polecat/crew/witness/refinery/mayor pattern)
- Claude processes without parent tmux session
- Tmux sessions without Claude (stuck at bash prompt)
- Polecats marked 'working' but session idle

### gt doctor --fix
Clean up detected issues:
- Kill orphan sessions
- Kill orphan Claude processes
- Optionally reset stuck polecat state

### gt gc (alternative name)
Short alias for cleanup operations.

## Acceptance Criteria
- [ ] Detects orphan sessions
- [ ] Detects orphan processes
- [ ] Safe cleanup (doesn't kill active work)
- [ ] Reports what was cleaned


Digest: mol-deacon-patrol

Patrol 15: All clear


Merge: gt-rana.4

branch: polecat/ace
target: main
source_issue: gt-rana.4
rig: gastown


Documentation: Feed-based wake model

Document the feed-based wake model in patrol-system-design.md and PRIMING.md.

DONE (2025-12-29):
- Updated patrol-system-design.md with full feed-based wake specification
- Added Feed Is the Signal and Discover Dont Be Told insights to PRIMING.md
- Committed as 39e46148


Update patrol formulas to use await-signal backoff

Layer 3: Update patrol formulas to use new gt mol await-signal with --agent-bead flag.

Update burn-or-loop steps in patrol formulas:
- mol-witness-patrol.formula.toml
- mol-refinery-patrol.formula.toml
- mol-deacon-patrol.formula.toml

The step should:
1. Reset idle counter on work found: gt agent state $AGENT_BEAD --set idle=0
2. Wait with backoff when no work: gt mol await-signal --agent-bead $AGENT_BEAD --backoff-base 30s --backoff-mult 2 --backoff-max 5m
3. Exit after 10 consecutive max-timeout cycles for fresh session


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 144 complete: All agents healthy


Mayor Role Definition

You are the Mayor - global coordinator of Gas Town. You sit above all rigs,
coordinating work across the entire workspace.

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

default_molecule: mol-mayor-patrol
capabilities:
  - dispatch_work
  - cross_rig_coordination
  - escalation_handling

## Responsibilities

- Work dispatch: Spawn workers for issues, coordinate batch work on epics
- Cross-rig coordination: Route work between rigs when needed
- Escalation handling: Resolve issues Witnesses cannot handle
- Strategic decisions: Architecture, priorities, integration planning

NOT your job: Per-worker cleanup, session killing, nudging workers (Witness handles that)

## Propulsion Principle

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

Your pinned molecule persists across sessions. Hook has work then Run it.
Hook empty then Check mail. Nothing anywhere then Wait for user.

## Key Commands

### Communication
- gt mail inbox - Check your messages
- gt mail read <id> - Read a specific message
- gt mail send <addr> -s "Subject" -m "Message" - Send mail

### Status
- gt status - Overall town status
- gt rigs - List all rigs
- gt polecats <rig> - List polecats in a rig

### Work Management
- bd ready - Issues ready to work (no blockers)
- gt sling <bead> <rig> - Assign work to polecat in rig

## Session End Protocol

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


Move disk 6: B → A

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


Merge: gt-svdsy

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


Digest: mol-deacon-patrol

Patrol 12: Quiet


Clarify formula semantics: read-only reference, not instantiated

## Problem

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

## What Happened

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

## Correct Model

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

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

## Fix Needed

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

(Moved from hq-ufiy)


Digest: mol-deacon-patrol

Cycle 10


Polecat template: simplify completion section to just 'gt done'

Completion section lists multiple options (gt done, gt handoff, bd sync). Should just say 'gt done' with succinct guidance on when bd sync is needed. Remove the alternatives that cause confusion.


Move disk 2: B → A

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


Merge: rictus-mjw1g7ny

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


Polecats should spawn with auto-accept mode enabled

During swarm bd-784c, polecats (Toast, Nux) were spawned without --dangerously-skip-permissions or equivalent auto-accept mode.

**Problem:**
Every edit, bash command, and tool use required manual confirmation via tmux send-keys. This defeats the purpose of autonomous polecat operation.

**Expected:**
Polecats in a swarm should run with permissions bypassed so they can work autonomously.

**Suggestion:**
- gt sling should pass --dangerously-skip-permissions by default for polecats
- Or polecats should have a .claude/settings.local.json pre-configured for auto-accept


Digest: mol-deacon-patrol

Patrol 99: All healthy


Run 1K Hanoi demo (10 disks)

End-to-end test:
1. Cook 20-disk Hanoi formula
2. Pour as wisp on a polecat
3. Let it run overnight
4. Monitor with bd mol progress
5. Verify completion via convoy


Digest: mol-deacon-patrol

Patrol 19: quick pass


Move disk 1: A → B

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


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 94: All healthy


Digest: mol-deacon-patrol

Patrol 6: All clear


Merge: gt-72so

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


Merge: gt-4ev4

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


Move disk 1: C → A

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


Bug: Deacon session linked to Mayor pane causes heartbeat crosstalk

**Root cause found**: The gt-deacon tmux session was linked to gt-mayor window 2 - they shared the same pane (@283). When the daemon sent heartbeats to the Deacon, they appeared as typed input in the Mayor's window, interrupting user prompts.

**Fix applied**: Killed the broken gt-deacon session. The daemon auto-recreates it with a proper independent pane.

**Prevention**: Investigate how sessions can get linked and add safeguards to session creation code.

Original symptom: Mayor receiving 'HEARTBEAT: Tip: Witnesses monitor polecats...' messages that ate user input.


gt done: Fails in worktrees due to missing origin tracking ref

In polecats (git worktrees), after git push -u origin <branch>, the origin/<branch> ref doesn't exist locally. This causes gt done to fail with 'unknown revision' when checking unpushed commits.

**Workaround**: After pushing, manually create the ref:
```bash
git fetch origin <branch>
git update-ref refs/remotes/origin/<branch> FETCH_HEAD
gt done
```

Root cause: Worktrees may not have the same fetch refspecs as the main repo. The tracking is set but the remote ref isn't fetched into refs/remotes/.

Fix: gt done should handle this edge case, perhaps by checking the remote directly or creating the ref after detecting the issue.


Digest: mol-deacon-patrol

Patrol 4: 3 polecats working, all healthy


Digest: mol-deacon-patrol

Patrol cycle 20: All 3 rigs healthy. No incidents. Handoff threshold reached.


Digest: mol-deacon-patrol

Patrol complete: all agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol 19: Quiet


Set hook_bead at polecat spawn time, not after

Currently polecat agent beads are created with empty hook_bead, then updated separately via updateAgentHookBead(). This causes cross-beads routing issues when town beads (hq-*) work is slung to rig polecats (gt-* agent beads).

Current flow:
1. sling.go calls SpawnPolecatForSling()
2. polecat/manager.go:Spawn() calls CreateAgentBead(HookBead: empty)
3. sling.go calls updateAgentHookBead() - separate call, different beads context

Proposed fix: Pass hookBead through the spawn chain so it is set atomically at creation time in manager.go:Spawn().

Files to change:
- polecat/manager.go:Spawn() - add hookBead parameter
- cmd/polecat_spawn.go:SpawnPolecatForSling() - pass hookBead through
- cmd/sling.go - pass beadID to spawn, remove separate updateAgentHookBead call

Benefits: Eliminates cross-beads routing problem, no race condition, removes agent bead might not exist error path.

Related: gt-ohqxq (partial fix using town root for routing)


Digest: mol-deacon-patrol

Patrol 20 - handoff threshold


Digest: mol-deacon-patrol

Patrol 10: OK


gt mail clear --all: Add flag for agent ergonomics

## Task

Add `--all` flag to `gt mail clear` as an affordance.

The command already clears all messages by default, but agents naturally try `--all` when they want to clear everything. Adding it as a no-op flag improves ergonomics.

## Implementation

In `internal/cmd/mail_clear.go` (or similar):

```go
var clearAll bool

func init() {
    clearCmd.Flags().BoolVar(&clearAll, "all", false, "Clear all messages (default behavior)")
}
```

The flag doesn't change behavior - it's just for discoverability and natural agent usage patterns.


Merge: nux-mjxn8p5t

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


Infrastructure formulas for dog tasks

Create formulas for dog-executed tasks:
- mol-convoy-cleanup: Archive convoy, notify overseer
- mol-dep-propagate: Cross-rig dependency resolution
- mol-digest-generate: Daily digest for overseer
- mol-orphan-scan: Find and reassign orphaned work
- mol-session-gc: Clean stale sessions


Digest: mol-deacon-patrol

Patrol 13: All healthy


Move disk 1: A → B

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


Move disk 1: A → B

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


Move disk 2: A → C

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


Merge: gt-r6td

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


Digest: mol-deacon-patrol

Patrol cycle 18: all healthy


Digest: mol-deacon-patrol

Patrol 7: Healthy. Furiosa resolved rig mismatch.


go install may fail for new users - private repo

README shows:
  go install github.com/steveyegge/gastown/cmd/gt@latest

This fails on fresh install if repo is private:
  fatal: could not read Username for 'https://github.com'

README should either:
1. Note the repo is private (if applicable)
2. Add SSH config instructions
3. Or provide 'build from source' alternative

This will be the first command new users try.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 1: A → B

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


Merge: rictus-mjw3nj1a

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


mol-deacon-patrol


gt sling: Support batch slinging multiple beads

Currently `gt sling` only accepts one bead at a time:

```
gt sling gt-abc gastown        # works
gt sling gt-abc gt-def gastown # fails: accepts between 1 and 2 arg(s)
```

## Proposed

Allow multiple beads in a single command:
```
gt sling gt-abc gt-def gt-ghi gastown
```

This would spawn a polecat for each bead (or reuse existing ones).

## Use case

Slinging related work from a convoy - want to parallelize without running gt sling N times manually.


Digest: mol-deacon-patrol

Cycle 8


Day 2.5: Test daemon pokes based on agent state

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

Parent: gt-d0jqp


Startup hook should validate attached molecule is still open

When the SessionStart hook outputs attached_molecule from the handoff bead, it should check if that molecule is still open. If closed, it should:
1. Clear the stale attachment
2. Auto-spawn a fresh patrol molecule
3. Attach the new patrol

Currently it just outputs the stale reference without validation, leaving the Deacon confused about what to run.


Move disk 4: B → A

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


Cost tracking v1: tmux scraping + ledger

## Overview
Implement basic cost tracking for Gas Town agents using tmux scraping.

## Scope

### 1. Live cost scraping
- `gt costs` command that:
  - Finds all Claude Code tmux sessions (polecat-*, witness-*, refinery-*, mayor-*)
  - Runs `tmux capture-pane -t <session> -p`
  - Extracts cost with regex: `\$[0-9]+\.[0-9]+`
  - Displays table: session | role | cost

### 2. Cost ledger
- File: `~/.gt/costs.jsonl`
- Schema: `{session_id, role, rig, cost_usd, started_at, ended_at, work_item}`
- Written on session end (SessionEnd hook integration)

### 3. Aggregation commands
- `gt costs` - Live costs from running sessions
- `gt costs --today` - Today's total from ledger
- `gt costs --week` - This week's total
- `gt costs --by-role` - Breakdown by role (polecat, witness, etc.)
- `gt costs --by-rig` - Breakdown by rig

### 4. Hook integration
- Add SessionEnd hook handler that:
  - Captures final cost
  - Writes to ledger
  - Includes work_item if attached

## Non-goals (v2)
- Per-convoy attribution
- Cost warnings/budgets
- Historical trends
- Deacon integration for periodic capture

## Reference
- GitHub issue #24
- docs/agent-compatibility.md (future direction)


Digest: mol-deacon-patrol

Patrol cycle 11: All agents healthy


mol-sync-workspace: Fix 'commits ahead' in report for crew on main


Digest: mol-deacon-patrol

Patrol 155 complete


Implement

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

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


Test message

Testing GGT mail system


Clean dead sessions

Clean dead sessions.

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

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

Preserve audit trail. Only clean sessions confirmed dead.


Session cycling UX: smooth transitions via TUI wrapper

## Problem

Current CLI agent session cycling is painful:
- Shell → CC starts → priming → context loads → ready → work → exit/crash → repeat
- Each cycle is 30-60 seconds of cold boot
- No continuity between shell and agent's inner state
- Raw "session not running, starting..." loop is the baseline

## GGT Advantages (already have)

- Beads: Work state survives session death completely
- Mail: Handoff notes from past-self to future-self
- Prime commands: Structured context reload

## Gap: Transition Mechanics

Ideas to explore when actively using CLI:

1. **In-band cycling** - `/restart` or `/cycle` command, agent handles own restart without dropping to shell

2. **Hot standby** - TUI maintains pre-warmed session in background, switch to already-primed agent

3. **Persistent wrapper** - Bubbletea TUI stays running across session cycles, CC sessions come/go inside it

4. **Session pooling** - Keep 2-3 primed sessions ready, never wait for cold start

## Deferred

Deliberately P4 until we're actively using the simpler CLI and feel the pain firsthand.


HOP: Skill vectors on work items

Add skill embeddings to work items for capability-based matching. See ~/ai/stevey-gastown/hop/CONTEXT.md. Post-v0.1 work.


Add --account flag to gt spawn and gt crew attach

Add --account=<handle> flag. Precedence: GT_ACCOUNT env > --account flag > default from config.


Digest: mol-deacon-patrol

Patrol 4: All agents healthy, routine


CLI: gt refinery commands (start, stop, status, queue)

CLI commands for managing the Refinery agent.

## Commands

```bash
gt refinery start <rig>      # Start refinery for a rig
gt refinery stop <rig>       # Stop refinery
gt refinery status <rig>     # Show refinery status
gt refinery queue <rig>      # Show merge queue
```

## gt refinery start

Starts the Refinery daemon for the specified rig.

Options:
- --foreground: Run in foreground (default: background)
- --auto-merge: Enable auto-merge (default: from config)

## gt refinery stop

Stops a running Refinery. Gracefully finishes current MR if processing.

## gt refinery status

Shows:
- Running state (running/stopped)
- Current MR being processed (if any)
- Queue length
- Last merge time
- Recent activity

## gt refinery queue

Shows the merge queue:
```
Merge queue for 'wyvern':
  1. [pending] Toast/polecat-auth-fix (15m ago)
  2. [pending] Capable/polecat-new-feature (5m ago)

1 merged today, 0 rejected
```

## Implementation

Uses gt-ov2 (Refinery agent) for daemon functionality.


Move disk 4: A → C

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


Digest: mol-deacon-patrol

Patrol 6: all clear, agents healthy


Add event-triggered lifecycle wisps

Commands like `gt town start` should auto-trigger lifecycle wisps.

## Event → Wisp Mapping

| Command | Triggers Wisp |
|---------|---------------|
| gt town start | mol-gastown-boot |
| gt rig add <name> | mol-rig-spinup (param: rig=<name>) |
| gt rig remove <name> | mol-rig-spindown (param: rig=<name>) |
| gt daemon restart | mol-gastown-boot |

## Implementation

1. Command implementation checks for lifecycle proto
2. Auto-slings wisp to Mayor with --wisp flag
3. Mayor picks up via molecule attachment

## Alternative: Explicit Sling

Keep commands simple, require explicit:

```bash
gt town start        # Just starts sessions
gt sling gastown-boot mayor/ --wisp   # Bootstrap with verification
```

This is more transparent - user sees the sling happen.

## Recommendation

Start with explicit sling. Add auto-trigger later once pattern proven.
`gt town start --verified` could trigger the wisp.


Move disk 1: A → B

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol cycle 15: all healthy


Digest: mol-deacon-patrol

Patrol complete: routine, town stable


Digest: mol-deacon-patrol

Cycle 20


Test refile v2

Testing improved refile

(Refiled from bd-eysh)


Move disk 1: A → B

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


Move disk 1: A → B

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


Merge: gt-a95

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


HTTP work client: CloudRun dispatch client

## Overview

HTTP client for dispatching work to Cloud Run and streaming results back.

## Implementation

```go
type WorkClient struct {
    serviceURL string
    httpClient *http.Client  // HTTP/2 enabled
}

func NewWorkClient(serviceURL string) *WorkClient {
    return &WorkClient{
        serviceURL: serviceURL,
        httpClient: &http.Client{
            Transport: &http2.Transport{},
            Timeout:   0,  // No timeout for streaming
        },
    }
}

func (c *WorkClient) DispatchWork(ctx context.Context, req WorkRequest) (<-chan WorkEvent, error) {
    // 1. POST to /work
    // 2. Return channel that streams WorkEvents
    // 3. Close channel when done/error
}
```

## Streaming Reader

```go
func (c *WorkClient) streamEvents(body io.Reader, events chan<- WorkEvent) {
    defer close(events)
    decoder := json.NewDecoder(body)
    for {
        var event WorkEvent
        if err := decoder.Decode(&event); err != nil {
            return
        }
        events <- event
    }
}
```

## Files

- `internal/cloudrun/client.go`

## Dependencies

Depends on: gt-9a2.7 (protocol types)
Used by: gt-9a2.8 (CloudRunOutpost)


Digest: mol-deacon-patrol

Patrol 18: healthy


Merge: gt-g44u.1

branch: polecat/Ace
target: main
source_issue: gt-g44u.1
rig: gastown


mol-code-review: Self-improving code review molecule

Create a code review molecule that enables Gas Town to self-improve through automated PR review. Flywheel: review generates quality checks, discovered issues, pattern learning.


Digest: mol-deacon-patrol

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


mol-deacon-patrol


mol-deacon-patrol minimal formula

Create minimal mol-deacon-patrol formula for tracer bullet.

## Simplified Patrol (v0.1)

```yaml
formula: mol-deacon-patrol-v01
description: Minimal Deacon patrol for tracer bullet.
version: 1

steps:
  - id: inbox-check
    title: Check inbox
    description: |
      Run: gt mail inbox
      Handle any messages.
      Note any spawn requests or status updates.

  - id: spawn-work
    title: Spawn polecat for ready work
    needs: [inbox-check]
    description: |
      Run: bd ready
      If work available and no polecat already working it:
        gt spawn --issue <first-ready> --rig gastown
      If no work: proceed to next step.

  - id: self-inspect
    title: Assess context and decide loop vs cycle
    needs: [spawn-work]
    description: |
      Evaluate whether to loop (reset) or cycle (handoff).

      ## Heuristics

      **Favor LOOP (bd mol reset):**
      - Context < 60%
      - No errors in this cycle
      - Patrol completed normally

      **Favor CYCLE (gt handoff):**
      - Context > 80%
      - Errors encountered
      - Been running > 1 hour without cycle
      - Model suggests refresh would help

      **Action:**
      - If LOOP: bd mol reset mol-deacon-patrol
      - If CYCLE: gt handoff -s "Deacon cycling" -m "Context: X%, cycles: N"
```

## Loop via Reset

After self-inspect, if staying:
```bash
bd mol reset mol-deacon-patrol
```

This resets all steps to pending, current_step to inbox-check.
Deacon immediately continues with fresh patrol cycle.

## Cycle via Handoff

If context high or refresh needed:
```bash
gt handoff -s "Deacon cycling" -m "Context high, cycling for fresh start"
```

Daemon respawns fresh Deacon with mol-deacon-patrol on hook.

## Location

.beads/formulas/mol-deacon-patrol-v01.formula.yaml


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 11: nominal


Digest: mol-deacon-patrol

Patrol 20: all clear - handoff threshold reached


Move disk 2: B → A

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


Move disk 1: A → B

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


Formula parser and YAML schema

Implement formula parsing from YAML:
- Define YAML schema for .formula.yaml files
- Parse steps, compose rules, vars
- Support extends for formula inheritance
- Validate formula structure

Schema should support:
- formula: name
- description: text
- version: number
- type: workflow|expansion|aspect
- vars: variable definitions
- steps: step definitions
- compose: composition rules

**Beads issue: bd-weu8**


Digest: mol-deacon-patrol

Patrol #20: Stable, handoff threshold reached


Digest: mol-deacon-patrol


Refinery Engineer: Role prompting and CLAUDE.md

Create refinery/CLAUDE.md with Chief Merge Engineer role context. Include:
- Role identity and responsibilities
- Decision authority (merge order, test frequency, binary rebuilds)
- Communication patterns (Witness, Deacon)
- Session lifecycle (handoff bead protocol)
- Key commands reference


Move disk 4: A → C

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


Move disk 1: C → A

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


mol-witness-patrol molecule definition

Create mol-witness-patrol in builtin_molecules.go.

## Steps (10 total)
1. inbox-check - Process witness mail (lifecycle, help requests)
2. load-state - Read handoff bead, get nudge counts
3. survey-workers - gt polecat list, categorize by status
4. inspect-workers - tmux capture-pane for each 'working' polecat
5. decide-actions - Apply nudge matrix, queue actions
6. execute-actions - Nudge, kill, or escalate as decided
7. save-state - Update handoff bead with new states
8. generate-summary - Summarize cycle for digest
9. context-check - Check own context usage
10. burn-or-loop - Squash wisp, then loop or cycle session

## Key Behaviors
- Uses wisp storage (.beads-wisp/)
- Reads/writes witness handoff bead for state persistence
- Progressive nudging (3 levels before escalate)
- Pre-kill verification before killing polecats

## Reference
- See prompts/roles/witness.md for protocol details
- See mol-refinery-patrol for similar structure
- Parent epic: gt-aqd8


Digest: mol-deacon-patrol

Patrol cycle 11: nominal (6 steps)


Digest: mol-deacon-patrol

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


bd sync fails when .beads/redirect points to different repo


gt spawn: Not injecting work instructions to session

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

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

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


Move disk 1: A → B

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Refactor: Eliminate state.json, use beads assignee field for polecat state

## Problem

state.json in each polecat worktree duplicates data that should be in beads:
- `issue` field duplicates assignment (should be issue.assignee)
- `state` field duplicates status (derivable from issue.status)
- `name/rig/branch/clone_path` are all derivable from filesystem/git

This violates 'Beads as the data plane' (HOP Decision 001).

## Current State

```json
{
  "name": "Angharad",        // Derivable: basename(cwd)
  "rig": "gastown",          // Derivable: parent dir name
  "state": "working",        // Should be: issue.status
  "clone_path": "/path",     // Derivable: cwd
  "branch": "polecat/X",     // Derivable: git branch
  "issue": "gt-xyz",         // Should be: issue.assignee
  "timestamps": "..."        // Should be in beads history
}
```

## Target State

**Polecat identity**: Derived from worktree path
**Polecat assignment**: `issue.assignee = 'gastown/Angharad'`
**Polecat state**: Derived from issue.status (in_progress = working, closed = done)
**Polecat existence**: Worktree directory exists

## Benefits

1. Single source of truth (no sync issues)
2. Queryable: `bd list --assignee=gastown/Angharad`
3. History tracking via beads
4. Cross-agent coordination via beads sync
5. Simpler code (no state file management)

## Implementation

1. Update `gt spawn` to set issue.assignee instead of writing state.json
2. Update polecat list/status commands to query beads
3. Update Witness to query beads for polecat state
4. Remove state.json read/write code
5. Keep state.json as optional bootstrap cache (perf optimization only)


Move disk 1: B → C

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


mol-deacon-patrol


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

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


Dynamic wisp modification: insert, reorder, bond mid-execution

## Vision

Wisps should be living documents that adapt mid-execution, not static scripts.

## Operations Needed

### bd mol insert
Insert a step into a running wisp:
```bash
bd mol insert <wisp-id> --after <step> --step 'security-gate: Review auth changes'
```

### bd mol reorder
Change step order in a running wisp:
```bash
bd mol reorder <wisp-id> --move process-branch --before current
```

### bd mol bond (to wisp)
Attach an entire molecule to a running wisp:
```bash
bd mol bond mol-weekly-maintenance <wisp-id> --after await-work
```

### bd mol skip
Skip a step (with reason):
```bash
bd mol skip <wisp-id> <step> --reason 'Queue empty, skipping summary'
```

## Use Cases

1. **Hotfix priority**: Reorder queue to process urgent MR first
2. **Security gate**: Insert review step when PR touches sensitive files
3. **Scheduled maintenance**: Bond maintenance mol on schedule
4. **Context adaptation**: Skip steps when they don't apply

## Why This Matters

Engine room problems emerge dynamically. The wisp's flexibility lets agents model situations as they evolve, not execute rigid scripts.

GUPP still applies: whatever's on your hook, you run. But the hook contents can adapt.

## Implementation

This requires Beads changes to support wisp mutation:
- Track step ordering in wisp storage
- Support step insertion/deletion/reordering
- Handle bond-to-wisp (spawn steps into existing wisp)
- Preserve audit trail of modifications


Move disk 2: C → B

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


Move disk 1: C → A

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


request-shutdown

Send shutdown request to Witness.
Wait for termination.

The polecat is now ready to be cleaned up.
Do not exit directly - wait for Witness to kill the session.

Depends: generate-summary


Move disk 1: B → C

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


Work on ga-ct2: Add MR workflow to polecat completion. Wh...

Work on ga-ct2: Add MR workflow to polecat completion. When polecat completes work, auto-create MR to integration branch. When done, submit MR (not PR) to integration branch for Refinery.


Design cross-workspace URI scheme

Define URI format: gt://entity/chain/rig/issue-id. Document resolution semantics for local vs remote references. Update GRAPH-ARCHITECTURE.md with final spec.


Merge: dementus-mjw46vz4

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


Merge: bullet-mjwlbeu5

branch: polecat/bullet-mjwlbeu5
target: main
source_issue: bullet-mjwlbeu5
rig: gastown
agent_bead: gt-gastown-polecat-bullet


Digest: mol-deacon-patrol

Patrol complete: no callbacks, agents healthy, 1 stale lock cleaned


gt mail reply/thread: Conversation support

Add mail conversation features:

- gt mail reply <id> -m 'message' - Reply to a message
- gt mail thread <id> - Show all messages in a thread

Enables back-and-forth communication between agents.


Merge: keeper-mjxpe1ku

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


Phase 4.2: Witness/Refinery patrol molecules

Extend ephemeral patrol pattern to Witness and Refinery.

## Witness Patrol Cycle

mol-witness-patrol-cycle:
1. scan-polecats: Check each polecat status
2. detect-stalls: Find stuck/idle polecats
3. nudge-or-escalate: Take action on stalls
4. log-status: Record cycle results
→ Squash with summary

## Refinery Patrol Cycle

mol-refinery-patrol-cycle:
1. scan-queue: Check merge queue
2. process-ready: Merge ready MRs
3. handle-failures: Deal with conflicts/failures
4. log-status: Record cycle results
→ Squash with summary

## Quiescent Mode

When no work: just log 'no activity' summary.
Witness and Refinery can sleep between cycles until triggered.


Default crew name should be something better than 'main'

When creating a new rig, the default crew worker name is 'main'. This is confusing since:

1. 'main' is also the git branch name
2. It doesn't convey that this is the user's personal workspace
3. Crew names should feel more personal/distinct

Consider alternatives like:
- 'home' - the user's home base
- 'desk' - their personal desk
- 'joe/max/etc' - actual name-based defaults
- Let user pick during rig init


Digest: mol-deacon-patrol

Patrol 13


Digest: mol-deacon-patrol

Patrol 1: All healthy - Mayor OK, 2 witnesses, 2 refineries, 0 polecats, 8 sessions, no callbacks


Digest: mol-deacon-patrol

Patrol cycle 1: All healthy - witnesses, refineries running. No callbacks, no orphans, no pending spawns.


Merge: gt-fpv2p

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


Digest: mol-deacon-patrol

Patrol 11: all clear


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 16: all healthy


Move disk 1: B → C

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


Move disk 2: A → C

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


Move disk 1: C → A

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


Implement gt worktree remove command

Remove a cross-rig worktree.

Usage: gt worktree remove <rig>

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

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


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


sling pin test 2


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.


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.


Digest: mol-deacon-patrol

Patrol 2: all healthy, no incidents


Merge: furiosa-1766987668522

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


#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


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


Move disk 3: B → C

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 9: All agents healthy


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.


Move disk 1: C → A

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


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 7: All healthy, no messages


Merge: rictus-1767079818240

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


Move disk 1: A → B

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


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


Merge: cheedo-mjw70xce

branch: polecat/cheedo-mjw70xce
target: main
source_issue: cheedo-mjw70xce
rig: gastown
agent_bead: gt-gastown-polecat-cheedo


Merge: furiosa-mjuk2tlb

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


Day 2.7a: gt install creates Deacon and Mayor agent beads

Update gt install to create agent beads:

1. After initializing town beads, create:
   - gt-deacon agent bead (role_type: deacon, rig: null, agent_state: idle)
   - gt-mayor agent bead (role_type: mayor, rig: null, agent_state: idle)

2. Use bd create --type=agent or internal beads API

Files:
- internal/cmd/install.go

Moved to gt rig add instead of gt install due to routing constraints. Agent beads need to be in rig beads (not town beads) for daemon to find them via prefix routing. First rig added gets gt-deacon and gt-mayor.


Move disk 1: A → B

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


Formula SDK: Developer Tooling for Workflow Authors

SDK for creating, testing, debugging, and validating formulas.

## Components

### Forge (Creation)
```bash
mol forge new my-workflow        # Scaffold new formula
mol forge extend base-workflow   # Create variant
mol forge lint my-workflow       # Check syntax/style
```

### Lab (Testing)
```bash
mol lab run my-workflow --dry-run   # Mock execution
mol lab test my-workflow            # Run formula tests
mol lab trace my-workflow           # Step-through debug
```

### Validator (Verification)
```bash
mol validate my-workflow                    # Check well-formedness
mol validate my-workflow --protocol=Reviewable  # Check protocol compliance
mol validate my-workflow --schematic=shiny  # Check schematic compatibility
```

### Analyzer (Static Analysis)
```bash
mol analyze my-workflow --deps     # Dependency graph
mol analyze my-workflow --coverage # Step coverage
mol analyze my-workflow --cycles   # Detect cycles
```

## Relationship to Other Concepts

The SDK operates on:
- Formulas (source level)
- Protos (compiled level)
- Molecules (runtime level)

And validates against:
- Protocols (type system)
- Schematics (domain composition)

## Open Questions

1. Bundled vs separate - mol subcommands or formula-kit binary?
2. IDE integration - LSP for formula files?
3. Test harness - how to mock steps? fixtures?

## Related

- docs/formula_evolution.md - "SDK Question" section
- gt-8tmz.30 - Proto debugging tools (subset)
- gt-8tmz.31 - Formula validation (subset)


Digest: mol-deacon-patrol

Patrol cycle 19


Digest: mol-deacon-patrol

Patrol cycle 8: All agents healthy


Move disk 4: A → C

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


Move disk 2: A → C

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


Move disk 2: A → C

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


Move disk 1: A → B

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


MessagingConfig: Add Type field for schema consistency

MessagingConfig lacks a Type field that other config types have (TownConfig has 'town', RigConfig has 'rig', etc). Add Type: 'messaging' for consistency.


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


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

Fix bugs blocking Witness functionality:

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 8: Quiet


Merge: slit-mjtj9dc8

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


Digest: mol-deacon-patrol

Patrol 2: All healthy, no events


MR: gt-test (main)

branch: main
target: main
source_issue: gt-test


Digest: mol-deacon-patrol

Patrol cycle 32: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol complete: gastown witness came online, town healthy


Digest: mol-deacon-patrol

Patrol cycle 7


Digest: mol-deacon-patrol

Patrol 14 complete


Make documentation convoy-first

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

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


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

Patrol 5: All healthy


gt sling pinToHook doesn't set pinned boolean field

## Updated Root Cause Analysis (2025-12-23)

The issue is **NOT** in gt as originally thought. It's in the beads (bd) codebase.

### What happens:
1. `bd pin` correctly sets pinned=1 in SQLite
2. Any subsequent `bd` command (even `bd show`) resets pinned to 0
3. This happens even with `--no-auto-import` and `--sandbox` flags

### Evidence:
```bash
$ bd --no-daemon pin gt-k08o --for=max
📌 Pinned gt-k08o to max's hook

$ sqlite3 beads.db 'SELECT id, pinned FROM issues WHERE id="gt-k08o"'
gt-k08o|1   # ← Correct immediately after pin

$ bd --no-daemon --no-auto-import show gt-k08o
[shows issue without pinned field]

$ sqlite3 beads.db 'SELECT id, pinned FROM issues WHERE id="gt-k08o"'
gt-k08o|0   # ← WRONG\! bd show overwrote it
```

### Where to look:
The bug is likely in one of these beads code paths:
- Some import/hydration running despite --no-auto-import
- WAL mode not flushing before subsequent reads
- Multi-repo or redirect handling corrupting pinned field

### Workaround:
The handoff bead attachment mechanism (AttachMolecule) works correctly.
The pinned field is cosmetic for `bd hook` visibility only.
gt sling correctly uses AttachMolecule for work assignment.

### Next steps:
Create a beads issue to fix this properly in the bd codebase.
This is not a gt issue.

Created beads bug: bd-phtv in ~/gt/beads


Git wrapper: shell out to git

Wrapper for git operations via subprocess.

## Interface

```go
type Git struct {
    workDir string
}

func NewGit(workDir string) *Git

// Core operations
func (g *Git) Clone(url, dest string) error
func (g *Git) Checkout(ref string) error
func (g *Git) Fetch(remote string) error
func (g *Git) Pull(remote, branch string) error
func (g *Git) Push(remote, branch string, force bool) error

// Commit operations
func (g *Git) Add(paths ...string) error
func (g *Git) Commit(message string) error
func (g *Git) CommitAll(message string) error

// Query operations
func (g *Git) Status() (*GitStatus, error)
func (g *Git) CurrentBranch() (string, error)
func (g *Git) HasUncommittedChanges() (bool, error)
func (g *Git) RemoteURL(remote string) (string, error)

// Merge operations
func (g *Git) Merge(branch string) error
func (g *Git) Rebase(onto string) error
func (g *Git) AbortMerge() error
func (g *Git) AbortRebase() error
```

## Implementation

Shell out to git binary via exec.Command. Parse output where needed (Status, CurrentBranch).

## Error Handling

- Wrap git stderr in error messages
- Detect specific failures (merge conflict, auth failure, not a repo)
- Return structured errors for callers to handle

## Testing

- Use temp directories with real git repos
- Test both success and failure paths


mol-deacon-patrol


Implement gt worktree list command

List all worktrees owned by current crew member.

Usage: gt worktree list

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

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

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


Liftoff implementation plan in Beads

## Context

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

## Work Required

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

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

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

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

## Deliverable

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

## References

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


gt-gastown-polecat-testcat5

gt-gastown-polecat-testcat5

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


Digest: mol-deacon-patrol

Patrol 127: All healthy


Digest: mol-deacon-patrol

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


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 13: All clear


Check mail for MR submissions, escalations, messages.

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

Handle shutdown requests, escalations, and status queries.

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


Implement queue:name address type for claim-based mail delivery

Add support for queue:name addresses in the mail router.

SEMANTICS:
- Messages to queue:name create ONE copy in a shared location
- Workers eligible for the queue (per messaging.json) can claim messages
- Claimed message is removed from queue, moved to claimer inbox
- If claimer fails to process, message can be released back to queue

USE CASE:
Polecat completion notifications - Witness OR Deacon should handle, not both.

IMPLEMENTATION:
1. Add isQueueAddress() / parseQueueName() helpers
2. Add sendToQueue() - creates message in queue location
3. Add gt mail claim <queue> - claims oldest unclaimed message
4. Add gt mail release <msg-id> - releases back to queue
5. Track claim state in message metadata

CONFIG (already in messaging.json schema):
queues.cleanup/gastown.workers = [gastown/witness, deacon/]
queues.cleanup/gastown.max_claims = 0


Digest: mol-deacon-patrol

Patrol 12


Patrol formulas: Inconsistent variable placeholder syntax

The patrol formulas use inconsistent syntax for variable placeholders:

## Inconsistency

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

## Expected

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

## Fix

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


bd mail send: pinned column missing from schema

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

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

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

## Error
table issues has no column named pinned

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


Detect abandoned work

**DETECT ONLY** - Check for orphaned state and dispatch to dog if found.

**Step 1: Quick orphan scan**
```bash
# Check for in_progress issues with dead assignees
bd list --status=in_progress --json | head -20
```

For each in_progress issue, check if assignee session exists:
```bash
tmux has-session -t <session> 2>/dev/null && echo "alive" || echo "orphan"
```

**Step 2: If orphans detected, dispatch to dog**
```bash
# Sling orphan-scan formula to an idle dog
gt sling mol-orphan-scan deacon/dogs --var scope=town
```

**Important:** Do NOT fix orphans inline. Dogs handle recovery.
The Deacon's job is detection and dispatch, not execution.

**Step 3: If no orphans detected**
Skip dispatch - nothing to do.

**Exit criteria:** Orphan scan dispatched to dog (if needed).


Move disk 4: C → B

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


Default BD_ACTOR in beads create

BUG: BD_ACTOR env var is only read in --no-db mode and daemon RPC path. Normal direct mode skips BD_ACTOR and falls back to $USER. The comment claims 'Viper handles BD_ACTOR automatically' but there's no actual viper binding. Fix: Add explicit os.Getenv("BD_ACTOR") check in main.go line 441-448, same as the --no-db path at line 352-360.


Session test with rig


Batch work landing report generation

Generate reports on batch work completion.

## Trigger

When all children of an epic are closed, generate a completion report.

## Report Contents

- Epic metadata (ID, title, created by, duration)
- Task summary (completed counts, timing)
- Per-task details (issue, assignee, time taken)
- Git stats (commits merged, lines changed)
- Cleanup stats (branches deleted)

## Output Locations

1. Mail to Mayor - summary report
2. Optional: save to file with --save flag

## Command

```bash
gt report --epic <epic-id> [--save report.md]
```

## Format

Markdown with sections:
- Summary
- Tasks
- Workers
- Timeline

## Note

This replaces the swarm-based reporting (gt-662). Reports are generated from epic/issue data, not from separate swarm state files.

## Reference

PGT: swarm/report.py (for format ideas, ignore swarm ID patterns)


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

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


Move disk 4: C → B

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


Refinery Patrol Cycle


Digest: mol-deacon-patrol

Patrol OK: archived old handoff, all agents up, furiosa on gt-oiv0


Rig management commands for town startup/shutdown


Digest: mol-deacon-patrol

Patrol 19: healthy


Document hookable mail in all role templates and priming

Update documentation for hookable mail beads:

## Role Templates (internal/templates/roles/)
- boot.md.tmpl
- crew.md.tmpl
- deacon.md.tmpl
- mayor.md.tmpl
- polecat.md.tmpl
- refinery.md.tmpl
- witness.md.tmpl

## Priming
- internal/cmd/prime.go output

## Key Documentation Points
1. GUPP applies to mail: 'If hooked, execute'
2. Two use cases: hook existing mail, hook new instructions via gt handoff
3. Execution model: read mail, interpret, execute prose instructions
4. Successor startup: `gt hook` shows mail details, read and act

## Section to Add (adapt per role)
```markdown
## Hookable Mail

Mail beads can be hooked for ad-hoc instruction handoff:
- `gt hook attach <mail-id>` - hook existing mail
- `gt handoff -m "..."` - create and hook new instructions

If you find mail on your hook, GUPP applies: read it, execute the instructions.
```


gt-gastown-polecat-goose

gt-gastown-polecat-goose

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: gt-cbstf
role_bead: gt-polecat-role
cleanup_status: null
active_mr: gt-e246n
notification_level: null


Digest: mol-deacon-patrol

Patrol 157 complete


Digest: mol-deacon-patrol

Patrol 5: all quiet


Move disk 2: B → A

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


gt mail reply: Reply to messages

Add `gt mail reply` command.

```
gt mail reply <id> -m BODY
gt mail reply <id>  # opens editor
```

- Auto-set To: from original sender
- Auto-set Subject: 'Re: <original subject>'
- Set reply_to field to original message ID
- Set thread_id to track conversation

**Implementation:**
- Add `replyCmd` to internal/cmd/mail.go
- Look up original message, extract sender/subject
- Use existing send infrastructure with reply metadata

**Note:** This enables threaded conversations for agent coordination.


Digest: mol-deacon-patrol

Patrol 255 complete: no incidents


Move disk 2: A → C

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


Move disk 4: A → C

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 212: All nominal


Merge: testcat-mjtk387i

branch: polecat/testcat-mjtk387i
target: main
source_issue: testcat-mjtk387i
rig: gastown


Digest: mol-deacon-patrol

Patrol cycle 17: All agents healthy


Move disk 4: A → C

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


Move disk 3: C → A

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


Spawn inject: Enter not submitted after multiline paste

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 142 complete: All agents healthy, no incidents


Rotate logs and prune state

Maintain daemon logs and state files.

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

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

**Step 2: Archive old daemon logs**

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

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

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

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

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 7: All healthy


gt doctor: detect tmux session anomalies (linked panes, etc.)

Add a tmux health check to gt doctor that detects:

1. **Linked panes between sessions** - The bug where gt-deacon and gt-mayor shared pane @283, causing heartbeat crosstalk
2. **Session naming anomalies** - Sessions that don't match expected patterns
3. **Orphaned panes** - Panes in gt-* sessions with no running process

Detection approach:
- List all gt-* sessions
- For each session, get window/pane IDs
- Check for duplicate pane IDs across different sessions
- If found, report which sessions are linked and suggest fix

Auto-fix: Could offer to kill and recreate the offending session.

Reference: gt-rt6g documented a case where this caused the daemon's Deacon heartbeats to appear in the Mayor's input, eating user prompts.


mol-deacon-patrol


Remove polecat state derivation from issue status

**File:** polecat/manager.go (lines 556-599)

**Current behavior:**
- Switch on issue.Status to derive polecat state
- Go decides: open/in_progress → Working, closed → Done

**Fix:**
- Polecat state comes from polecat, not inferred by Go
- Polecat signals state via mail or explicit field
- Or: remove state derivation entirely, just report issue status

**Lines to refactor:**
- manager.go:576-588 (switch statement)

**Priority:** P2 - less critical than daemon/heartbeat logic


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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


gt-gastown-polecat-charlie

gt-gastown-polecat-charlie

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


Move disk 1: C → A

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


Polecat session checkpoint for crash recovery

When polecat session dies, all context is lost.

## Problem
- Session dies (context limit, crash, timeout)
- No record of what files were modified
- No checkpoint of molecule step progress
- Next session has to rediscover state

## Fix
Periodic checkpoint during work:
1. Every N minutes, or on molecule step completion
2. Write checkpoint file: `.polecat-checkpoint.json`
   - Current molecule step
   - Modified files list
   - Last commit SHA
   - Timestamp
3. On session restart, read checkpoint
4. Resume from checkpoint state

## Checkpoint Format
```json
{
  "molecule_id": "mol-xxx",
  "current_step": "gt-abc.2",
  "modified_files": ["internal/foo/bar.go"],
  "last_commit": "abc123",
  "timestamp": "2025-12-30T18:00:00Z"
}
```


Merge: nux-1767087680976

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


Merge: slit-1767059695613

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


Digest: mol-deacon-patrol

Patrol 18: all healthy


Merge: gt-bpiph

branch: polecat/toast-mjtm1hg8
target: main
source_issue: gt-bpiph
rig: gastown


Move disk 1: B → C

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


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


Merge: gt-t9u7

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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


No-tmux mode: naked Claude Code operation without daemon/tmux

## Problem

Tmux is crashing workers. The daemon relies on tmux for:
- Session management (creating/killing panes)
- Nudging agents via SendKeys
- Crash detection via pane-died hooks

When tmux is unstable, the entire Gas Town operation fails.

## Goal

Enable Gas Town to operate without tmux or the daemon, relying solely on:
- Naked Claude Code sessions (terminal or IDE)
- Deacon self-handoff and patrol robustness
- Pinned beads for propulsion (already implemented)
- **Beads as universal data plane** - args, context, everything flows through beads

## Key Insight: Beads Replace SendKeys

Currently --args is injected via tmux SendKeys. In no-tmux mode:
- Store args in the pinned bead description (attached_args field)
- gt prime reads and displays args from pinned bead
- Wisps are infinite ephemeral sticky notes - use them for transient context
- No prompt injection needed - agent discovers everything via bd show

## Degraded Behavior (No-Tmux Mode)

**What still works:**
- Propulsion via pinned beads (agents pick up work on startup)
- Self-handoff (agents can cycle themselves)
- Patrol loops (Deacon, Witness, Refinery keep running)
- Mail system (beads-based, no tmux needed)
- Args passed via bead description

**What is degraded:**
- **No interrupts**: Cannot nudge busy agents mid-task
- **Polling only**: Agents must actively check inbox (no push notifications)
- **Await steps block**: "Wait for human" steps require manual agent restart
- **No crash detection**: pane-died hooks unavailable
- **Manual startup**: Human must start each agent in separate terminal

**Workflow implications:**
- Patrol agents work fine (they poll as part of their loop)
- Task workers need restart to pick up new work
- Cannot redirect a busy worker to urgent task
- Human must monitor and restart crashed agents

## Requirements

1. **gt sling --args stores in bead**: Write args to pinned bead description
2. **gt prime displays args**: Read attached_args from pinned bead
3. **gt spawn --naked**: Assign work without creating tmux session
4. **Documentation**: Explain no-tmux mode and degraded behavior
5. **Deacon self-sustaining**: Must cycle reliably without daemon

## Acceptance Criteria

- Can assign work with args without tmux
- Agent discovers args via gt prime / bd show on startup
- Deacon patrol runs indefinitely via self-handoff
- Workers started manually pick up pinned work
- Documentation explains what works vs degraded in no-tmux mode


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, no lifecycle requests, cleaned 3 abandoned wisps


Update templates with molecule navigation workflow

Update all agent templates to use new molecule navigation commands.

## Commands to integrate
- bd mol current: orientation after startup/handoff (bd-sal9)
- bd close --continue: seamless step transitions (bd-ieyy)

## Templates to update

### prompts/roles/polecat.md
- Add bd mol current to 'Finding Your Work' section
- Replace manual 3-command dance with bd close --continue
- Update 'Working Through Steps' section

### prompts/roles/crew.md
- Add molecule navigation to workflow section
- Show bd mol current for session startup

### prompts/roles/refinery.md
- Update patrol step transitions to use --continue

### prompts/roles/witness.md
- Update patrol step transitions to use --continue

### prompts/roles/deacon.md
- Update patrol step transitions to use --continue

## Key message
The Propulsion Principle: close a step, immediately get handed the next.
No friction, no forgetting, no 3-command dance.

## Blocked by (Beads features)
- bd-sal9: bd mol current
- bd-ieyy: bd close --continue

BLOCKED 2025-12-23 00:17: Waiting for beads features (bd mol current, bd close --continue) to be implemented. Notified mayor.


Document merge queue architecture

Update docs/architecture.md with:

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

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


Merge: toast-1767146237529

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


Digest: mol-deacon-patrol

Patrol 123: All healthy


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy.


Refinery: event-driven merge queue

## Problem
Refinery only acts on explicit requests, no queue management.

## ZFC-Compliant Solution
Add steps to `mol-refinery-patrol.formula.toml`:

```toml
[[step]]
id = "check-merge-requests"
title = "Process merge queue from inbox"
description = """
1. Check inbox for MERGE_READY messages: gt mail inbox
2. For each merge request:
   - Read branch name from message
   - Add to local queue (track in state.json or temp file)
3. Process queue in order:
   - git fetch origin
   - git checkout main && git pull
   - git merge --no-ff origin/polecat/<name>
   - If conflict: mail Mayor with details, skip
   - If success: git push && delete remote branch
4. For each merged branch:
   - gt mail send <rig>/witness -s "MERGED: polecat/<name>" -m "Branch merged successfully"
   - Delete the MERGE_READY mail
"""
depends_on = ["inbox-check"]
```

## Queue State
Refinery agent tracks queue in `state.json`:
```json
{
  "merge_queue": ["polecat/foo", "polecat/bar"],
  "last_merged": "polecat/baz"
}
```

## Why This Works
- Refinery Claude agent runs formula
- Agent handles conflicts with judgment
- Mail is coordination primitive
- State persists in agent's state.json

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


Add bulk session stop command (gt session stop --all)

When decommissioning a rig, need to stop multiple sessions one at a time. A --all or --rig flag would allow: gt session stop --rig gastown


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


Max expansion depth limit (default 5)

Add maxExpansionDepth config (default 5) to prevent runaway nested expansions. This still allows massive work generation but with a safety bound. Note: distinguish compile-time cooking (produces proto with placeholders) vs runtime cooking (produces mol with real issue IDs). Compile-time is for modeling/estimation/contractor handoff.


Merge: gt-o3is

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


Implement announce:name address type for bulletin-board messaging

Add support for announce:name addresses for read-only bulletin boards.

SEMANTICS:
- Messages to announce:name create ONE copy in shared location
- All eligible readers can read (no claiming, no removal)
- Messages retained up to retain_count, oldest pruned
- No inbox pollution - readers check the announce channel explicitly

USE CASE:
Low urgency broadcast that does not need ack, e.g. clean up your branches.

IMPLEMENTATION:
1. Add isAnnounceAddress() / parseAnnounceName() helpers
2. Add sendToAnnounce() - creates message in announce location
3. Add gt mail announces - list available announce channels
4. Add gt mail read-announce <channel> - read messages from channel
5. Add retention pruning on new message

CONFIG (already in messaging.json schema):
announces.alerts.readers = [@town]
announces.alerts.retain_count = 100


mol-witness-patrol

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

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

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

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

## The Christmas Ornament Shape

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


Move disk 3: A → B

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


mol-deacon-patrol


Clean up deprecated gt mol command examples in molecule.go

## Task

The molecule.go file contains example strings that reference deprecated gt mol commands.

## Deprecated References Found

1. `gt molecule instantiate mol-xyz` → should reference `bd mol pour`
2. `gt mol list --catalog` → should reference `bd formula list`
3. `gt mol bond mol-polecat-arm` → should reference `bd mol bond`

## Location

`internal/cmd/molecule.go` (multiple lines)

## Context

The gt mol help already correctly redirects:
```
For beads data operations (listing, showing, creating molecules), use bd:
  bd formula list    List molecule protos (replaces gt mol catalog)
  bd mol show        Show molecule details (replaces gt mol show)
  bd mol pour        Instantiate molecule (replaces gt mol instantiate)
  bd mol bond        Bond molecules together (replaces gt mol bond)
```

But the example strings in the code still show the old patterns.

## Fix

Update the example strings to use the current bd mol patterns.


Move disk 2: B → A

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


Move disk 3: C → A

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


Merge: nux-mjwny9w0

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


Merge: nux-1767079896198

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


Merge: gt-caih

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


Move disk 1: A → B

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


Deacon tmux status bar: heartbeat timing and patrol state

## Problem

The deacon shows patrol output but lacks real-time observability:
- No indication of when last heartbeat occurred
- No indication of when next heartbeat is scheduled
- No visibility into current patrol step

## Desired Behavior

The tmux status bar for gt-deacon should show:

```
⛪ Deacon | ❤ 2m ago | ⏰ 3m | 📍 health-scan (3/7)
```

Components:
- **Role icon**: ⛪ (deacon identity)
- **Last heartbeat**: ❤ 2m ago (time since last heartbeat file update)
- **Next heartbeat**: ⏰ 3m (time until daemon would poke)
- **Current step**: 📍 health-scan (3/7) (current patrol atom, step N of M)

## Implementation

1. **Read heartbeat.json** for last update time
2. **Calculate next poke** based on daemon interval (default 5m)
3. **Read current wisp** from .beads-wisp/ to get patrol progress
4. **Update tmux status** periodically or on state change

Options:
- tmux status-right with shell script
- gt deacon status --tmux for formatted output
- Hook into patrol step completion

## Related

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


attached_args: Extract processExists function to reduce duplication

Extract duplicated processExists function to shared package.

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

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

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

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

import "os"

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

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


Digest: mol-deacon-patrol

Patrol 209: All nominal


Create molecules catalog directory structure

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

## Structure

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

## PROTO.md Format

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

# mol-gastown-boot

Town bootstrap molecule.

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

## Catalog Loading

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

This enables file-based proto development with beads tracking.