Witness patrol: Add sibling-check for Refinery

Witness should check on Refinery health as part of patrol (village sibling watch).

## Implementation

1. Add `sibling-check` step to mol-witness-patrol
2. Use `gt peek <rig>/refinery 20` to check Refinery output
3. Check Refinery queue status: `gt mq list <rig>`
4. Look for:
   - Refinery session alive
   - Queue processing (if items present)
   - No stuck MRs (same MR in_progress for too long)
5. If Refinery seems stuck:
   - Send nudge or status request
   - Consider escalation to Deacon

## Acceptance
- Witness checks Refinery each patrol cycle
- Can detect stuck Refinery
- Provides backup oversight for merge queue


Digest: mol-deacon-patrol

Patrol 17


Deacon health checks too frequent - disturbs idle agents

Deacon is sending health checks to mayor every few seconds even when idle. This defeats the purpose of the patrol system - agents should NOT be disturbed when there's nothing going on.

Proposed fix:
1. Reduce health check frequency (e.g., every 60s instead of every 5s)
2. Or: Only health check agents that have active work (hooked molecules)
3. Or: Mayor shouldn't be health-checked at all since it's human-managed

The deacon should be silent/invisible when the town is healthy.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


implement

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

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

Depends: load-context


gt mol step done: Auto-continue molecule on step completion

## Summary

Implement `gt mol step done <step-id>` command that enables polecats to close a molecule step and automatically continue to the next step without waiting for witness orchestration.

## Problem

Currently, when a polecat completes a molecule step:
1. Polecat sends POLECAT_DONE to witness
2. Witness (in patrol cycle) eventually reads mail
3. Witness spawns next step
4. **Minutes of latency possible**

Polecats also forget to close beads steps (using internal TodoWrite instead), breaking the activity feed.

## Solution

`gt mol step done <step-id>` handles everything:

1. Close the beads step (`bd close <step-id>`)
2. Extract molecule ID from step (bd-mol-xga.1 → bd-mol-xga)
3. Find next ready step (dependency-aware)
4. If next step exists:
   - Update hook file to point to next step
   - Write handoff context
   - tmux respawn-pane (fresh claude session)
5. If molecule complete:
   - Clear hook
   - Send POLECAT_DONE to witness
   - Exit session

## Key Insight

Step-to-step transitions are **mechanical**, not **cognitive**. No AI needed in the critical path. Pure Go automation.

## Related Commands

- `gt mol next <mol-id>` - Show next ready step(s)
- `gt mol progress <mol-id>` - Already exists

## Polecat Protocol Update

```markdown
When your hook contains a molecule step:
1. Read the step: `bd show <step-id>`
2. Execute the work described
3. When complete: `gt mol step done <step-id>`

That is it. Do NOT manually close steps. Do NOT work multiple steps.
```

## Benefits

- **Instant step transitions** (~5-10s vs minutes)
- **Activity feed works** (steps closed as completed)
- **Witness freed up** (safety net only, not critical path)
- **Fresh context per step** (better attention, no accumulated confusion)


Use atomic write pattern for state files

attached_args: Atomic write pattern for state files

Prevent data loss from concurrent state file writes using atomic write pattern.

## Files to modify
- internal/witness/manager.go
- internal/refinery/manager.go
- internal/crew/manager.go
- internal/swarm/manager.go

## Problem
State is saved directly to file - if process crashes mid-write, file corrupts.

## Implementation
Replace direct writes with atomic pattern:
```go
func atomicWriteJSON(path string, v interface{}) error {
    data, err := json.MarshalIndent(v, "", "  ")
    if err != nil {
        return err
    }
    tmpFile := path + ".tmp"
    if err := os.WriteFile(tmpFile, data, 0644); err != nil {
        return err
    }
    return os.Rename(tmpFile, path)  // Atomic on POSIX
}
```

## Acceptance criteria
- [ ] atomicWriteJSON helper created (in internal/util or similar)
- [ ] All 4 manager saveState methods use atomic writes
- [ ] .tmp files cleaned up on success
- [ ] go test ./... passes
- [ ] Manual test: state files survive kill -9


Digest: mol-deacon-patrol

Patrol 7: Quiet


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

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


mol-deacon-patrol


Test: gt rig add initializes rig correctly

Validate rig setup:

## Test cases
- [ ] Rig directory created with mayor/rig structure
- [ ] Rig beads initialized with correct prefix
- [ ] routes.jsonl updated with new rig route
- [ ] Rig appears in rigs.json
- [ ] bd commands work from rig context

## Prerequisites
- Requires test git repo (create temp or use fixture)


Move disk 1: B → C

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


gt polecat: add 'done' or 'finish' command to transition from working to idle

When a polecat finishes work but session wasn't properly cleaned up, there's no way to reset it from 'working' state back to 'idle'.

Tried:
```
gt polecat sleep gastown/Angharad
Error: sleeping polecat: polecat is not active (state: working)
```

The sleep command only works on 'active' polecats, not 'working' ones.

Had to manually edit state.json to reset:
```
jq '.state = "idle" | .issue = ""' state.json
```

Need a command like:
```
gt polecat done gastown/Angharad   # working -> idle
gt polecat finish gastown/Angharad # working -> idle
gt polecat reset gastown/Angharad  # any state -> idle (force)
```


Move disk 2: C → B

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


Move disk 1: A → B

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


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.


Digest: mol-deacon-patrol

Patrol 13: clear


Move disk 1: B → C

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


Link MR bead to agent bead for traceability

MR bead and agent bead are separate with no cross-reference.

## Problem
- MR bead tracks: branch, target, source_issue
- Agent bead tracks: state, hook_bead, cleanup_status
- No link between them

When something goes wrong, hard to trace which polecat created which MR.

## Fix
1. MR bead should include agent_bead field
2. Agent bead should include active_mr field
3. On gt done: update both to reference each other
4. On merge: clear both references

## Benefits
- Traceable: given MR, find polecat
- Traceable: given polecat, find MR
- Orphan detection: MR without agent = stale


Move disk 2: A → C

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


Digest: mol-deacon-patrol

P18: stable


Digest: mol-deacon-patrol

Patrol 13: quiet


Digest: mol-deacon-patrol

Patrol 1: All clear - inbox empty, agents healthy, no orphans


list: static mailing list lookup

Static mailing list support via config file.

## Deliverables

1. Load lists from ~/gt/config/lists.json
2. Parse list:name syntax in router
3. Fan-out at send time (same as @group)
4. Error handling for unknown list names

## Example
```bash
gt mail send list:oncall -s "Alert" -m "System down"
# Expands to: mayor/, gastown/witness, beads/witness
# Creates 3 message copies
```

## Dependencies
- Config directory (gt-i6jvc)

## Acceptance
- list:oncall resolves to configured members
- Each member gets own message copy
- Unknown list returns clear error


Witness: Escalate dormant polecats with unpushed work (don't auto-nuke)

Witness escalation for dormant polecats should distinguish between safe-to-nuke and needs-recovery.

## Problem
Witness detected 4 dormant polecats with unpushed commits (hq-ww5ev) but by the time Mayor processed the mail, the polecats were nuked during cleanup, losing work.

## Fix
1. Witness dormancy check should read cleanup_status from agent bead
2. If has_unpushed or has_uncommitted: mark as NEEDS_RECOVERY, escalate
3. If clean: safe to nuke
4. NEVER auto-nuke polecats with unpushed work

## Escalation Format
Subject: RECOVERY_NEEDED <polecat>
Body includes: unpushed commit SHAs, branch name, issue ID


Immediate daemon notification on lifecycle request

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

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

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

## Proposed Solutions

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

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

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

Recommend Option A for simplicity.

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


Digest: mol-deacon-patrol

Patrol 68: Routine


Refinery not processing merge-requests - stale MRs accumulating

Discovered 15 stale merge-request issues in beads rig that were never processed by the refinery. These appear to be from polecat branches that completed work but the refinery didn't pick up the merge-requests.

Closed issues:
- bd-r06v, bd-bhg7, bd-754r, bd-fcl1, bd-3zzh
- bd-bijf, bd-5rj1, bd-kptp, bd-rdzk, bd-ibl9
- bd-gfo3, bd-aq3s, bd-x2bd, bd-s1pz, bd-h27p

Need to investigate:
1. Why refinery isn't picking up merge-requests
2. Whether the polecat branches have valid work to merge
3. Add monitoring/alerting for stale MRs


Move disk 3: B → C

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


Tmux wrapper: session operations

Wrapper for tmux session operations via subprocess.

## Interface

```go
type Tmux struct{}

func NewTmux() *Tmux

// Session lifecycle
func (t *Tmux) NewSession(name, workDir string) error
func (t *Tmux) KillSession(name string) error
func (t *Tmux) HasSession(name string) (bool, error)
func (t *Tmux) ListSessions() ([]string, error)

// Session interaction
func (t *Tmux) SendKeys(session, keys string) error
func (t *Tmux) CapturePane(session string, lines int) (string, error)
func (t *Tmux) AttachSession(session string) error

// Window operations (if needed)
func (t *Tmux) SelectWindow(session string, index int) error
```

## Session Naming

Convention: `gt-<rig>-<polecat>` (e.g., `gt-wyvern-Toast`)

## Implementation

- Shell out to tmux binary
- CapturePane uses `tmux capture-pane -p -t <session> -S -<lines>`
- SendKeys uses `tmux send-keys -t <session> '<keys>' Enter`

## Error Handling

- "no server running": tmux not started (not an error for HasSession)
- "session not found": session doesn't exist
- Wrap all tmux errors with context

## Environment

Requires TMUX_TMPDIR or uses default socket. Don't assume tmux is running.


Obsolete beads issues need cleanup

Found obsolete issues that should be closed or fixed:

Test artifacts to close:
- gt-nriy: Test: Alpha to Beta (message test)
- gt-gswn: Integration test (test artifact)
- gt-54kn: Test: New Router

Broken dependencies (reference non-existent gt-test123):
- gt-vhby: implement
- gt-tvos: load-context
- gt-lwuu.2: implement (template variable unresolved)

CloudRun references (non-existent /deploy/cloudrun/):
- gt-9a2.6, gt-9a2.7, gt-9a2.11

Review and close/update these before launch.


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 39: all quiet


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 16: routine


Add godoc comments to exported functions

Several exported functions lack godoc comments. While not critical, adding documentation would improve code maintainability. Focus on:

- Public API functions in each package
- Exported types and their methods
- Functions that have non-obvious behavior

Can be addressed incrementally as code is touched.


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 7: All healthy.


Move disk 3: A → B

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


Digest: mol-deacon-patrol

Patrol 6: All clear


Move disk 2: B → A

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


Test Patrol Parent

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

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

Original description:
Test parent for Christmas Ornament pattern


Digest: mol-deacon-patrol

Patrol cycle 11: nominal (6 steps)


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 7: routine, all healthy


Work on ga-lzh: Add gt witness attach command. Allow atta...

Work on ga-lzh: Add gt witness attach command. Allow attaching to witness session for a rig, similar to gt mayor attach. When done, submit MR (not PR) to integration branch for Refinery.


Digest: mol-deacon-patrol

Patrol 63: Routine, all healthy


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy, handoff threshold reached


Batch wisp squashing in Deacon maintenance

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

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


Digest: mol-deacon-patrol

Patrol 17 complete


Digest: mol-deacon-patrol

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


Move disk 1: A → B

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


Move disk 1: B → C

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


Move disk 5: A → B

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


Digest: mol-deacon-patrol

Patrol 9: Routine


Polecat: Conflict resolution workflow

New workflow for polecats handling conflict-resolution tasks.

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

## Workflow
1. Read task metadata
2. Fetch the branch: `git fetch origin <branch>`
3. Checkout: `git checkout -b temp-resolve origin/<branch>`
4. Attempt rebase: `git rebase origin/main`
5. Resolve conflicts (Claude judgment)
6. Run tests
7. Force-push: `git push --force origin <branch>`
8. Close conflict-resolution task
9. Original MR automatically re-enters queue

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


Failure handling: assign back to worker, add labels

Handle merge failures appropriately.

Failure types and actions:
| Failure     | Action                                      |
|-------------|---------------------------------------------|
| conflict    | Add needs-rebase label, assign to worker    |
| tests_fail  | Add needs-fix label, assign to worker       |
| build_fail  | Add needs-fix label, assign to worker       |
| flaky_test  | Retry once, then treat as tests_fail        |
| push_fail   | Retry with backoff, escalate if persistent  |

Actions:
1. bd update <id> --status=open --assignee=<worker>
2. bd update <id> --labels=<failure-label>
3. Send mail to worker explaining failure
4. Log failure details

Reference: docs/merge-queue-design.md#handling-failures


Move disk 2: A → C

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


Move disk 5: A → B

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


Clean dead sessions

Clean dead sessions and orphaned state.

Run `gt doctor --fix` to handle all cleanup:

```bash
# Preview what needs cleaning
gt doctor -v

# Fix everything
gt doctor --fix
```

This handles:
- **orphan-sessions**: Kill orphaned tmux sessions (gt-* not matching valid patterns)
- **orphan-processes**: Kill orphaned Claude processes (no tmux parent)
- **wisp-gc**: Garbage collect abandoned wisps (>1h old)

All cleanup is handled by doctor checks - no need to run separate commands.


Digest: mol-deacon-patrol

Patrol 19


Move disk 3: A → B

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


Move disk 1: B → C

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


Merge: rictus-1766959789036

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


Update polecat CLAUDE.md with molecule workflow

Add molecule execution guidance to polecat context:

## What to Add

### Molecule Awareness
- Polecats execute Wisps (ephemeral molecule instances)
- The work assignment mail includes molecule context
- Current step is tracked in the wisp

### Workflow Protocol
1. Read assignment (includes molecule ID and current step)
2. Execute current step
3. Update step status via bd mol step
4. Generate summary when all steps complete
5. Run bd mol squash to compress wisp into digest

### Key Commands
- bd mol show <wisp-id> - view current molecule state
- bd mol step <wisp-id> --status=complete - mark step done
- bd mol squash <wisp-id> --summary='...' - complete molecule

### Summary Generation
When completing work, generate a summary that:
- Lists what was accomplished
- Notes any deviations from the plan
- Captures key decisions made
- This becomes the permanent digest


Summarize this patrol cycle.

Summarize this patrol cycle.

Include:
- Branches processed (count, names)
- Test results (pass/fail)
- Issues filed (if any)
- Branches skipped (with reasons)
- Any escalations sent

This becomes the digest when the patrol is squashed.

instantiated_from: mol-refinery-patrol
step: generate-summary


Digest: mol-deacon-patrol

Patrol 5: 3 rigs healthy


Epic: Refinery Engineer Autonomy

Make Refinery Engineer fully autonomous:

## Goal
Refinery can run indefinitely, processing all polecat work through merge queue, cycling sessions as needed, without human intervention.

## Key Components
1. Role prompting (CLAUDE.md, templates)
2. Handoff mechanism (pinned beads)
3. Context detection (gt prime)
4. Communication protocol (Witness, Deacon)
5. Future: Merge orchestration plugins

## Success Criteria
- Refinery starts, reads handoff, knows what to do
- Processes merges sequentially with conflict resolution
- Cycles sessions cleanly via Deacon
- Communicates results to Witness
- No work left behind


gt done: Require pushed branch before MR creation

gt done currently creates MR bead without verifying the branch is pushed.

## Problem
Polecat can run `gt done` with unpushed commits. MR bead references a branch that doesn't exist on remote. Work is lost when polecat is nuked.

## Fix
In done.go runDone():
```go
// Before creating MR bead
status, err := g.CheckUncommittedWork()
if status.UnpushedCommits > 0 {
    return fmt.Errorf("branch has %d unpushed commits; run 'git push' first", status.UnpushedCommits)
}
```

## Already Have
- `computeCleanupStatus()` checks this but only reports, doesn't block
- Just need to make it a hard error


Move disk 6: A → C

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol cycle 3: all systems nominal


Digest: mol-deacon-patrol

Patrol 9: All healthy


Digest: mol-deacon-patrol

Patrol 10: 3 rigs healthy


Dynamic arm bonding in witness patrol

Witness survey step uses bd mol bond to attach mol-polecat-arm for each active worker. Variables: worker name, rig. Arms become children of the patrol molecule. Requires on_complete/for_each runtime support.


Update Refinery to use Beads merge queue

Replace branch discovery with Beads queue in the Refinery module:

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

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

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


Digest: mol-deacon-patrol

Patrol 14: healthy


Move disk 1: B → C

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


Digest: mol-deacon-patrol

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


gt rig info: Show detailed rig information

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

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 12: Mayor OK, 11 sessions


Plugin: Plan-to-Epic converter

## Purpose

Help users create beads epics from various planning inputs.

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

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

## Implementation Options

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

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

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

## Axiom

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

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

## Priority

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

## Note

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


Digest: mol-deacon-patrol

Patrol 1: All healthy, no messages, no orphans


Merge: nux-mjui76op

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


Digest: mol-deacon-patrol

Patrol 1: Closed 2 complete convoys (heartbeat fix, refinery fix). All 3 rigs healthy. 12 polecats active. No zombies, no orphans, inbox clear.


Merge: capable-mjxdb1vx

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


Move disk 1: B → C

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


mol-deacon-patrol


Move disk 2: C → B

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


Add Deacon heartbeat mechanism

Deacon writes deacon/heartbeat.json on each wake. Go daemon reads it to decide whether to poke. Add heartbeat read/write helpers.


Formula Molecules: Guzzoline production for Gas Town

## Vision

Gas Town executes work. But it also needs to PRODUCE work - structured, high-quality guzzoline on demand. **Formula Molecules** are recipes that spawn structured convoys.

## Core Insight

A formula is a molecule template that:
1. Takes input (a PR, a design problem, a codebase)
2. Spawns multiple polecats with specific focuses
3. Each leg produces structured output
4. Synthesis step combines into unified deliverable

Gas Town becomes both consumer AND producer of guzzoline.

## Example Formulas

### Design Convoy Formula
Input: Feature request or problem statement
Legs (parallel):
- API design polecat
- Data model polecat
- UX/ergonomics polecat
- Scalability polecat
- Security polecat
Synthesis: Unified design doc with tradeoffs

### Code Review Convoy Formula
Input: PR or file set
Legs (parallel):
- Correctness: Does it work?
- Performance: Any bottlenecks?
- Security: Vulnerabilities?
- Elegance: Clean design?
- Resilience: Error handling?
- Style: Convention compliance?
- Smells: Anti-patterns?
- Legacy: Respects existing patterns?
Synthesis: Categorized review with priority issues

### Other Formula Ideas
- Test Coverage Convoy: Unit, integration, edge cases, error paths
- Documentation Convoy: API docs, user guide, examples, changelog
- Migration Convoy: Database, API, config, rollback plan
- Incident Response: Root cause, timeline, fix, prevention

## Mol Mall

Library/marketplace of formulas:
```bash
gt formula list              # Available formulas
gt formula show code-review  # Formula details
gt formula run code-review --pr=123  # Execute formula → convoy
gt formula create my-review  # Create custom formula
```

## Technical Design

### Formula Structure (in beads)
```yaml
id: formula-code-review
type: formula
name: Code Review
inputs:
  - name: target
    type: pr | files | branch
legs:
  - name: correctness
    focus: "Verify logical correctness and edge cases"
    output: findings.md
  - name: security
    focus: "Identify security vulnerabilities"
    output: findings.md
  # ...
synthesis:
  inputs: all leg outputs
  output: review-summary.md
```

### Execution Model
1. `gt formula run` creates convoy with formula reference
2. Spawns polecats for each leg (parallel where possible)
3. Each polecat gets leg-specific prompt + shared context
4. Outputs collected as bead attachments or slots
5. Synthesis polecat reads all outputs, produces final deliverable
6. Convoy lands with unified result

### Dependencies
- Leg outputs feed synthesis (internal convoy deps)
- Formula can specify leg ordering if needed
- Parallel by default, sequential where required

## Open Questions

1. Where do formulas live? Town-level beads? Separate formula registry?
2. How to version/share formulas across towns?
3. Leg output format standardization?
4. Human checkpoints between legs or only at end?
5. Partial formula runs (skip some legs)?
6. Formula composition (formula that includes other formulas)?

## Why This Matters

Gas Town currently waits for humans to create work. With formulas:
- Mayor can invoke structured reviews on any PR
- Design work follows consistent methodology
- Quality processes are repeatable and scalable
- Work generation becomes as automated as work execution

**Guzzoline factory, not just guzzoline consumer.**


Move disk 1: B → C

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


Move disk 3: A → B

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


Digest: mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol cycle 16: routine


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 21 complete. Detected 2 orphaned polecats (nux, rictus), escalated to Mayor. All 3 rigs healthy (beads, gastown, wyvern). No convoys, gates, or plugins.


Digest: mol-deacon-patrol

Patrol 204: Fast pass, all nominal


Merge: nux-mjwny9w0

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


Move disk 2: B → A

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


Exclude deacon from tmux rig count in status displays

Deacon is a town-level patrol agent, not a project rig. It shows up in tmux session counts alongside actual rigs (gastown, beads, wyvern), which is confusing.

Fix: Status/tmux reporting should exclude deacon from rig counts. Deacon is infrastructure, not a workspace.

Affected: Any status displays that count tmux sessions as rigs.


Fanout gate: waits-for children aggregation

Formalize the fanout gate pattern where a step waits for all dynamically-bonded children.

## Current State

Formulas already use this pattern informally:

    step: aggregate
    waits_for: "all-children"

But it is not in the algebra spec or implemented in the cooker.

## Proposed Syntax

    step: aggregate
    needs: [survey-workers]
    waits-for: children-of(survey-workers)

Or simpler:

    step: aggregate
    needs: [survey-workers]
    waits-for: all-children

## Semantics

- Step cannot start until ALL children of the referenced step have completed
- Children are dynamically bonded via for-each (gt-8tmz.8)
- This is the "aggregation" half of the Christmas Ornament pattern
- If no children were bonded, the gate passes immediately

## Use Cases

**Witness Patrol:**
- survey-workers bonds N polecat-arms
- aggregate waits for all arms to complete
- Then proceeds to save-state

**Refinery Patrol:**
- Less common (sequential processing), but useful for parallel test runs

## Relationship to gate

This is a variant of gate where the condition is "all children complete" rather than
an arbitrary expression. Could be implemented as:

    gate:
      condition: "children-of(survey-workers).all(status == complete)"

But dedicated syntax is cleaner for this common pattern.

## Dependencies

- Depends on gt-8tmz.8 (for-each creates the children)
- Depends on gt-8tmz.4 (gate infrastructure)


Move disk 4: A → C

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


Digest: mol-deacon-patrol

Patrol 16: All clear


Move disk 1: A → B

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 3: C → A

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


Move disk 3: A → B

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


Self-test

Testing gt mail works


mol-polecat-arm

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.

## Variables

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

## Steps

### capture
Capture recent tmux output for this polecat.

```bash
tmux capture-pane -t gt-{{rig}}-{{polecat_name}} -p | tail -50
```

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

### assess
Categorize polecat state.

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

### load-history
Read nudge history for this polecat from patrol state.

```
nudge_count = state.nudges[{{polecat_name}}].count
last_nudge_time = state.nudges[{{polecat_name}}].timestamp
```

Needs: assess

### decide
Apply the nudge matrix to determine action.

| 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

### execute
Take the decided action.

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

**pre-kill-verify**:
```bash
cd polecats/{{polecat_name}}
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: {{polecat_name}} 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

This data feeds back to the patrol's aggregate step.

Labels: [template, christmas-ornament, polecat-arm]


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

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


Refinery startup: bond mol-refinery-patrol on start

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

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

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

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

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

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


Track operational stats as entity/audit beads

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

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

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

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


Merge: nux-mjtj9d8q

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


mol-deacon-patrol


Crew worker wolf in gastown


Merge: rictus-mjtnzt6k

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


gt feed --follow: Town-level activity stream

Town-native command for aggregated activity feed.

Wraps bd activity --town with Gas Town conveniences:
- gt feed --follow         # Stream all rig activity
- gt feed --rig gastown    # Filter to specific rig
- gt feed --convoy hq-xxx  # Filter to convoy's tracked issues

Essential for Mayor/Deacon visibility into cross-rig work.

Depends on: bd-dx6e (bd activity --town)
Related: hq-7h8jx (Convoy System epic in town beads)


Digest: mol-deacon-patrol

Patrol 5: All green


Move disk 5: B → C

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


Show actor only when not redundant with bead ID

Currently the feed shows actor even when obvious:

  [10:17:37] ✓ gt-s6r44 completed · ... @gastown/crew/max

The actor should be omitted when:
- The bead ID already identifies the agent (gt-crew-gastown-joe)
- The action makes the actor obvious (created by = actor)

Format should be:
  {timestamp} {symbol} {issue-id} {action} · {title} [@actor if not obvious]

Part of epic gt-u7dxq


Move disk 2: A → C

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


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


Digest: mol-deacon-patrol

Patrol 11: All agents healthy, cleaned 18 stale wisps


Move disk 2: B → A

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


gt polecat nuke: Refuse if unpushed commits or open MR

Agent prompts can be ignored. Code cannot.

`gt polecat nuke` should REFUSE to delete a polecat if:
1. Worktree has unpushed commits
2. Polecat has open MR beads
3. Polecat has work on hook

This is enforcement in code, not just instructions. The command itself should be safe.

Use existing `computeCleanupStatus()` in done.go as reference.


Move disk 1: C → A

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


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.


Merge: toast-mjw7062w

branch: polecat/toast-mjw7062w
target: main
source_issue: toast-mjw7062w
rig: gastown
agent_bead: gt-gastown-polecat-toast


Move disk 2: B → A

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


Move disk 1: A → B

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


gt spawn: polecats report success but no work actually happens

## Problem

gt spawn polecats have multiple silent failure modes:

### Failure Mode 1: No gt prime
- Claude starts at prompt and waits for input
- SessionStart hook doesn't auto-run 'gt prime'
- Without gt prime, polecats don't pick up work

### Failure Mode 2: No git push (CRITICAL)
- Polecat commits code locally
- Polecat closes the beads issue
- Polecat sends POLECAT_DONE
- **But code is never pushed to remote branch**
- When worktree is cleaned up, commits are lost forever
- Issue appears closed but no code exists

## Evidence

testcat on bd-d28c:
- Reported 'Work Complete' with commits 7d3447b9, cd87e541
- Closed bd-d28c
- Submitted MR bd-yx22
- But: `grep -r 'TestCreateTombstone' cmd/bd/*.go` returns nothing
- No polecat/testcat branch on remote

## Required Fixes

1. Polecats MUST push their branch before closing issues
2. Witness MUST verify branch exists on remote before cleanup
3. gt spawn should auto-nudge 'gt prime'
4. Consider: Polecat handoff should fail if unpushed commits exist

## Verification Protocol for Witness

Before accepting POLECAT_DONE:
```bash
# 1. Verify branch pushed
git branch -r | grep polecat/<name>

# 2. Verify code exists
grep -r '<expected_function>' path/to/files

# 3. Only then cleanup
```


Merge: gt-5wb7

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


Digest: mol-deacon-patrol

Patrol 103: All agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol 9: quick pass


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 2: all clear, systems healthy


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

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


Move disk 1: C → A

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


Merge: toast-1767079830359

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


Digest: mol-deacon-patrol

Patrol cycle 59: All healthy


Move disk 2: C → B

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


Move disk 2: A → C

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


Merge: gt-3x0z.3

branch: polecat/rictus
target: main
source_issue: gt-3x0z.3
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.

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


Digest: mol-deacon-patrol


Phase 2.3: Polecat CLAUDE.md molecule workflow protocol

Update polecat prompting for molecule-based work.

## CLAUDE.md Updates

Add section on molecule workflow:

```markdown
## Molecule Workflow

When assigned a molecule (check gt prime output):

1. Follow molecule steps in order
2. Mark steps complete: bd mol step complete <step-id>
3. Before signaling done:
   a. Generate summary of work performed
   b. Run: bd squash <molecule-root> --summary "<your summary>"
4. Then signal done as normal

### Summary Guidelines

Your summary should include:
- What was the task?
- What did you do?
- What was the outcome?
- Any issues or follow-ups?

Keep it to 2-4 sentences. This becomes the permanent record.
```


Deacon: Hierarchical health-check orchestrator

Replace daemon heartbeats with Deacon - an AI agent that keeps Gas Town running.

## Core Concept

The Deacon is a **Claude agent** (not just a Go process) that:
- Lives at town root in gt-deacon session
- Has its own mailbox (deacon/ identity in town beads)
- Is poked by a minimal Go daemon every ~60s (if idle)
- Monitors Mayor and Witnesses proactively
- Handles lifecycle requests (restart/cycle) from Mayor, Witnesses, AND Crew

## Architecture

```
Minimal Go Daemon (just watches Deacon)
         |
         v
     Deacon (Claude agent)
         |
    +----+----+
    v         v
  Mayor    Witnesses --> Polecats (Witness-managed)
    |         |
    +----+----+
         |
      Crew (lifecycle only, not monitored)
```

## Deacon Responsibilities

**Proactive monitoring:**
- Mayor health (tmux session, keepalive freshness)
- Witness health (tmux sessions, keepalive freshness)

**Reactive lifecycle:**
- Process restart/cycle requests from Mayor, Witnesses, Crew
- Kill session, create new, prime, verify startup

**Escalation:**
- Mail human (configurable) if issues can't be resolved

## Key Files

- ~/gt/DEACON.md - Role context
- ~/gt/deacon/ - State directory
  - heartbeat.json - Written each wake cycle (daemon checks this)
  - state.json - Health tracking, last scan results
- ~/gt/.beads/ - Town beads with deacon/ mail identity

## Wake Cycle

1. Write heartbeat (prevents daemon from poking)
2. Check mail (lifecycle requests)
3. Quick health scan (Mayor, Witnesses)
4. Process lifecycle requests
5. Remediate unhealthy agents
6. Update state

## Session Patterns

- Deacon: gt-deacon
- Mayor: gt-mayor
- Witness: gt-<rig>-witness
- Crew: gt-<rig>-<name> (e.g., gt-gastown-max)

## Relation to Policy Beads

Future: Deacon behavior configurable via policy beads (gt-3zw).
Initial implementation uses sensible defaults.


Merge: rictus-mjuic92c

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


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.


Digest: mol-deacon-patrol

Patrol 12: OK


Digest: mol-deacon-patrol

Patrol 4: all healthy


Polecat template not found for non-gastown rigs

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

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


Move disk 1: A → B

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


Day 2.2: Remove PID/tmux state inference

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

Daemon becomes pure transport layer.

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

Parent: gt-d0jqp

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


Digest: mol-deacon-patrol

Patrol 145 complete: All healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


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

Patrol 16: All healthy


Digest: mol-deacon-patrol

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


Move disk 2: B → A

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol #8: nominal


attached_args: Remove os.Exit calls from Cobra RunE handlers

Replace os.Exit() calls with proper error returns in Cobra commands.

## Files to modify
- internal/cmd/mail.go (lines 546, 554, 561, 808-812)
- Any other files with os.Exit in RunE

## Problem
Some RunE handlers call os.Exit() directly:
```go
RunE: func(cmd *cobra.Command, args []string) error {
    ...
    os.Exit(1)  // BAD: bypasses Cobra error handling
}
```

## Fix
Return errors instead:
```go
RunE: func(cmd *cobra.Command, args []string) error {
    ...
    return fmt.Errorf("not in workspace")
}
```

## Acceptance criteria
- [ ] No os.Exit calls inside RunE functions
- [ ] Errors returned with proper context
- [ ] grep -n 'os.Exit' internal/cmd/*.go shows no RunE matches
- [ ] go build ./... passes
- [ ] Commands still exit with correct codes


Move disk 2: C → B

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


Move disk 1: B → C

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


gt sling: Make target path parsing more forgiving

Current parsing rejects valid-looking paths like 'gastown/nux' or 'gastown/polecats/nux'.

Should accept:
- gastown/nux (polecat)
- gastown/Nux (polecat, case-insensitive)
- gastown/polecats/nux (explicit)
- gastown/crew/max (crew)
- gastown (auto-spawn)

The help says 'gastown/Toast' works but it doesn't. Parser is too strict.


Merge: nux-mjw3mn8o

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Quick patrol: no messages, all healthy


Ephemeral protos: Remove proto-as-bead storage, cook inline

## Summary

Refactor the molecular chemistry stack so protos are ephemeral in-memory data structures, not persisted beads with `[template]` labels.

## Current State

```
Formula (.formula.json)  → cook → Proto (bead with [template]) → pour/wisp → Mol/Wisp
```

Protos are stored as beads issues with `labels: ["template"]`, polluting the DB with template definitions that duplicate the formula files.

## Target State

```
Formula (.formula.json)  → pour/wisp (cook inline) → Mol/Wisp
```

Protos exist only as in-memory data structures during the cook→pour/wisp pipeline. Formula catalog IS the proto library.

## Changes Required

1. **Remove template bead storage** - `bd cook` no longer writes to DB
2. **`bd cook` becomes preview** - outputs proto JSON to stdout (like --dry-run)
3. **`bd pour`/`bd wisp` cook inline** - take formula name, cook on the fly
4. **`bd mol bond` accepts formula names** - cooks inline when bonding templates
5. **Remove `[template]` label handling** - no more template beads
6. **Update docs** - molecular-chemistry.md, molecule-algebra.md

## Benefits

- No DB pollution from template beads
- Single source of truth (formulas in .beads/formulas/)
- Simpler mental model: formulas → instances
- Faster (no DB round-trip for protos)

## Deferred

Staged parameterization (proto currying) - punt until someone needs it:
```bash
bd cook mol-feature --var team=backend  # Partially bound proto
bd pour <proto-id> --var priority=high  # Further binding
```

## Depends On

- gt-8tmz (Molecule Algebra) core work should be mostly complete first

## Context

Discussion: Mayor session 2025-12-25, ultrathink on proto storage


bd list --parent: filter by parent issue

Add --parent flag to bd list to filter issues by parent.

Example:
```bash
bd list --parent=gt-h5n --status=open
```

Would show all open children of gt-h5n.

Useful for:
- Checking epic progress
- Finding swarmable work within an epic
- Molecule step listing


Digest: mol-deacon-patrol

Patrol #10: All healthy


Move disk 1: A → B

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Move disk 3: B → C

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


Digest: mol-deacon-patrol

Patrol #12


Digest: mol-deacon-patrol

Patrol 10: full check, all healthy


Mayor notification levels (Do Not Disturb mode)

## Problem

Mayor needs notification level control like iOS Do Not Disturb:
- **Verbose**: gt nudge tmux messages for mail, convoy events, escalations
- **Normal**: Important events only (convoy landed, escalations)
- **Muted/DND**: Silent - batch notifications for later review

## Use Cases

1. Running a swarm: Mute notifications, check convoy status manually
2. Waiting for work: Verbose - get nudged when mail arrives
3. Deep coordination: Normal - only interruptions that need attention

## Design Considerations

### Beads Data Plane Integration
- Notification preferences should be a bead slot (persistent across sessions)
- Events are already beads (mail, convoy status changes)
- Need event classification: urgency levels on beads?
- gt nudge should check notification level before firing

### State Location
- Mayor agent bead has slots for persistent state
- `notification_level`: verbose | normal | muted
- Could also have per-event-type overrides

### Commands
```bash
gt dnd on              # Mute notifications
gt dnd off             # Resume normal
gt dnd status          # Show current level
gt notify verbose      # All notifications
gt notify normal       # Default
gt notify muted        # DND mode
```

### Event Classification
Which events are which urgency?
- P0: Escalations from Witness, critical failures
- P1: Convoy landed, work completed
- P2: New mail, status updates
- P3: Informational (can always batch)

### Open Questions
1. Should DND auto-disable after convoy lands?
2. Per-convoy notification preferences?
3. How to surface batched notifications when DND ends?
4. Integration with tmux status line vs nudge popups?


Multiple merge/landing models documented without clarification

Architecture describes three different merge models:

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

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

This is confusing for users trying to understand the system.


stderr suppression hides critical errors

Multiple files set cmd.Stderr = nil:
- prime.go
- up.go
- orphans.go
- daemon.go

This hides git errors and command failures.

Should capture stderr for debugging and log when errors occur,
rather than suppressing entirely.


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.


gt feed: Add convoy dashboard panel for in-progress and recently-landed

## The Insight

Convoys are now the most important unit of work for certain Gas Town users.
The convoy-landing feed is THE view of feature work and fixes actually shipping.

## Current State

gt feed shows:
- Agent tree (top panel): agents by role
- Event stream (bottom panel): issue/molecule activity

Missing: **Convoy status panel**

## Proposed Enhancement

Add a convoy panel showing:

```
┌─🚚 Convoys─────────────────────────────┐
│ IN PROGRESS                            │
│  hq-qrfz4  cv-startup      2/4 ●●○○   │
│  hq-wvqi6  Boot+Polish     3/5 ●●●○○  │
│                                        │
│ RECENTLY LANDED (24h)                  │
│  hq-abc12  Auth refactor   ✓ 2h ago   │
│  hq-def34  API cleanup     ✓ 5h ago   │
└────────────────────────────────────────┘
```

## Components

1. **In-progress convoys**: Open convoys with progress bars (completed/total)
2. **Recently landed**: Convoys that closed in last 24h (configurable)
3. **Quick stats**: Total in-flight, landed today, etc.

## Integration Options

A) New panel in existing TUI (3-panel layout)
B) Dedicated `gt convoy feed` or `gt convoy watch` command
C) Both - convoy panel in main feed + dedicated convoy view

## Why This Matters

The agent tree shows WHO is working.
The event stream shows WHAT is happening.
The convoy panel shows WHAT IS SHIPPING.

For stakeholders, the convoy view is the most important - "what features landed today?"


Digest: mol-deacon-patrol

Cycle 300: All healthy, refinery queue 7


Digest: mol-deacon-patrol

Patrol 13: All clear


Digest: mol-deacon-patrol

Patrol 4: all clear


Digest: mol-deacon-patrol

Patrol cycle 24: All healthy, no incidents


Merge execution: merge, test, push

Implement the actual merge execution.

Steps:
1. git checkout <mr.target>
2. git merge <mr.branch> --no-ff -m 'Merge <branch>: <title>'
3. If config.run_tests:
   - Run test_command (from config)
   - If failed: git reset --hard HEAD~1, return Failure(tests_failed)
4. git push origin <mr.target>
5. Return Success(merge_commit=HEAD)

Configuration:
- run_tests: bool (default true)
- test_command: string (default 'go test ./...')

Handle push failures with retry logic.

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


Fix failing beads tests: TestIntegration and TestPolecatWorkMolecule


Digest: mol-deacon-patrol

Patrol 12: All healthy, no messages


Digest: mol-deacon-patrol

Patrol 11: Quiet


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy


Verify refinery patrol loop executes

Verify refineries run their patrol formula:

1. Check refinery session: `gt session status gastown/refinery`
2. If not running: `gt session start gastown/refinery`
3. Watch refinery: `tmux attach -t gt-gastown-refinery`
4. Verify it handles:
   - Checking for pending MRs
   - Processing merge queue
   - Reporting results

Test for both rigs: gastown and beads.


Phase 1: Slinging Handoff

# Phase 1: Slinging Handoff

The restart-and-resume loop. This is the fundamental propulsion mechanism.

## What It Does

```bash
gt sling gt-xxx
```

1. Creates a wisp on the agent's hook containing the bead
2. Sends handoff mail (optional context)
3. Triggers session restart (daemon SIGUSR1 or direct respawn)
4. Fresh Claude wakes up
5. SessionStart hook runs `gt prime`
6. Agent reads hook → finds the slung bead
7. Agent executes the work

## Why Wisp, Not Mol

The sling is ephemeral scaffolding. It says "run this bead" - nothing more.
Once the work is picked up, the wisp can be burned. No permanent record needed
for the handoff wrapper itself; the actual work is tracked in the bead.

## Implementation

### gt sling command

```go
// cmd: gt sling <bead-id> [-s subject] [-m message]
func sling(beadID string, subject, message string) {
    // 1. Create wisp on hook
    //    - Creates .beads-wisp/hook-<agent>.wisp.yaml
    //    - Contains: bead_id, slung_at, context

    // 2. Optional: send handoff mail
    //    - gt mail send <self> -s "🤝 HANDOFF: <subject>" -m "<message>"

    // 3. Trigger restart
    //    - For crew: just exit (human restarts)
    //    - For polecats: signal daemon (SIGUSR1)
    //    - For deacon: signal daemon (SIGUSR1)
}
```

### Hook Reading in gt prime

```go
// In gt prime, after loading context:
func checkHook(agent string) *SlungWork {
    wispPath := ".beads-wisp/hook-" + agent + ".wisp.yaml"
    if exists(wispPath) {
        return parseWisp(wispPath)
    }
    return nil
}
```

### Agent Response to Slung Work

When agent wakes and finds slung work:

1. Read the wisp: `hook-<agent>.wisp.yaml`
2. Get the bead ID
3. Show the bead: `bd show <bead-id>`
4. Begin working on it
5. Burn the wisp (it's been picked up

## Files Changed

-  - New command
-  - Wisp creation/reading
-  - Hook check on startup
- Role CLAUDE.md files - Instructions for hook processing

## Acceptance Criteria

- [ ]  creates wisp on hook
- [ ] Agent restart picks up the slung work
- [ ] Work begins automatically (no human nudge)
- [ ] Wisp is burned after pickup
EOF
)


Digest: mol-deacon-patrol

Patrol 2: all healthy, no incidents


Digest: mol-deacon-patrol

Patrol 148 complete


Digest: mol-deacon-patrol

Patrol cycle 39: All healthy, no incidents


Move disk 5: B → C

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


mol-deacon-patrol


Handle callbacks from agents

Handle callbacks from agents.

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

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

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


Move disk 3: B → C

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


Digest: mol-deacon-patrol

Patrol 15: All healthy, no messages


Digest: mol-deacon-patrol

Patrol 9: healthy


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 11


Refactor gt swarm to use beads backing

Migrate gt swarm commands from .runtime/swarms.json to beads molecules.

Current gt swarm stores state in .runtime/swarms.json - violating discovery over tracking.
The refactored version should use bd swarm create/status to work with beads molecules.

Implementation:
- gt swarm create calls bd swarm create
- gt swarm status calls bd swarm status
- gt swarm list queries bd list --mol-type=swarm
- Remove .runtime/swarms.json dependency

CROSS-RIG DEPENDENCIES (must complete first in beads repo):
- bd-oxgi: mol_type schema field
- bd-fa1q: bd swarm create command
- bd-5x0j: bd swarm status command

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


Consolidate duplicate formatAge functions in feed TUI

formatConvoyAge in convoy.go is nearly identical to formatAge in view.go. Consolidate into one shared function.


Day 3.4: Refinery processes MERGE_READY mail

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

Parent: gt-hwka3


Merge: slit-mjw18vx8

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


Digest: mol-deacon-patrol

Patrol cycle 18: All agents healthy


Digest: mol-deacon-patrol

Patrol 19: Routine


Digest: mol-deacon-patrol

Patrol cycle 8: all nominal


Move disk 2: C → B

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


Digest: mol-deacon-patrol

P16: stable


Bubbletea TUI dashboard

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


Digest: mol-deacon-patrol

Patrol 88: All healthy


Digest: mol-deacon-patrol

Patrol #6: Routine


Refinery needs branch visibility: Convert to worktree or push branches

The refinery cannot see polecat branches because it is a separate clone, not a worktree.

## Problem
- Polecats are worktrees of mayor/rig (correct, per gt-4u5z)
- Refinery is still a separate clone at refinery/rig (not converted)
- Polecat branches are local to mayor/rig, invisible to refinery

## Decision (2025-12-25)
**Use a shared bare repo as the single git source of truth.**

```
gastown/
├── .repo.git/           ← Bare repo (no working tree, invisible base)
├── mayor/rig/           ← Worktree (human workspace)
├── polecats/
│   └── Toast/           ← Worktree on polecat/Toast
├── refinery/rig/        ← Worktree on main (can see all branches!)
└── crew/max/            ← Worktree or separate clone (TBD)
```

**Why bare repo:**
- No working directory to accidentally work in
- Standard git pattern (how servers work)
- All worktrees share branch visibility
- Refinery on main can merge polecat branches directly

## Implementation
1. Create `.repo.git` as bare clone
2. Convert refinery to worktree of .repo.git on main
3. Convert polecats to worktrees of .repo.git
4. Optionally convert mayor/rig (or keep as worktree)
5. Update gt rig init for new rigs
6. Write migration for existing rigs

## Evidence
Tracer bullet 2025-12-23: Refinery could not see polecat/tracer until pushed to origin.


Digest: mol-deacon-patrol

Patrol cycle 4: all healthy


Move disk 3: C → A

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


Merge: keeper-1767106012994

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


Digest: mol-deacon-patrol

Patrol cycle 5: routine, healthy


Add stale-attachments doctor check

Add gt doctor check for work stale on hook without progress.

Check: stale-attachments
Warning if: Attached molecule has no activity for >24h
Suggestion: Check agent status, consider nudge or reassignment


Digest: mol-deacon-patrol

Patrol: dave handoff (vision docs, 7 design gaps filed), furiosa tracer bullet on gt-oiv0, all agents up


Digest: mol-deacon-patrol

Patrol 10: healthy


Digest: mol-deacon-patrol

Patrol 15: Quiet


gt handoff: Auto-hook mail when created with -m flag

Enhance `gt handoff` to auto-hook the mail bead it creates:
```bash
gt handoff -s "Title" -m "Instructions..."
# Creates mail bead hq-xxx
# Hooks it automatically
# Respawns session
```

Implementation in internal/cmd/handoff.go


Digest: mol-deacon-patrol

Cycle 11: quiet


Witness: Update polecat monitoring for ephemeral model

Update Witness to handle truly ephemeral polecats.

## Current Behavior
- Witness monitors polecats until MR merged
- 'Rebase needed' mail sent to polecats

## New Behavior
- Witness marks polecat as 'recyclable' after MR submit
- Witness can dispatch conflict-resolution tasks
- Witness doesn't wait for merge to recycle polecat

## Changes to mol-witness-patrol.formula.toml
- Detect 'MR submitted' state
- Mark polecat recyclable
- Handle conflict-resolution dispatch

## Polecat States
```
spawning → working → mr_submitted → recyclable → recycled
```

## Considerations
- Don't recycle sandbox until branch pushed
- Or: Keep sandbox, just recycle session


Digest: mol-deacon-patrol

Patrol cycle 8: all healthy


Merge: rictus-mjw3nj1a

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


Digest: mol-deacon-patrol

Cycle 4: healthy, refinery started


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.


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 110: All healthy


Digest: mol-deacon-patrol

Patrol 157: All healthy


Digest: mol-deacon-patrol

Patrol 13: all healthy


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


Move disk 2: B → A

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


Test2

Testing gt mail


Move disk 3: C → A

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


Move disk 2: B → A

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


Merge: gt-odvf

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


Exponential backoff for idle patrol agents

## Problem

Patrol agents (Refinery, Witness, Deacon) currently have no backoff when their queue is empty. They either:
- Loop immediately (wasting cycles)
- Exit and wait for 10-minute daemon respawn (too slow to respond)

## Solution: Feed-Driven Backoff

### The Pattern (from PRIMING.md)

> "Backoff isn't about polling less - it's about **waiting for signals with a timeout**."

Agents subscribe to `bd activity --follow` and wake on any beads mutation. The timeout increases exponentially during idle periods.

### Data Flow

```
bd/gt mutations → .events.jsonl → feed curator → .feed.jsonl
                                                      ↓
                    patrol agent: gt mol await-signal --backoff-*
                                                      ↓
                              signal → wake, reset idle_cycles
                              timeout → increment idle_cycles, sleep longer
```

### Backoff Formula

```
timeout = min(base × multiplier^idle_cycles, max)
```

| Idle Cycles | Timeout |
|-------------|---------|
| 0 | 30s |
| 1 | 1m |
| 2 | 2m |
| 3 | 4m |
| 4+ | 5m (capped) |

### Agent State Storage

Operational state stored as labels on agent beads (labels-as-cache pattern):
- `idle:3` - consecutive idle patrol cycles
- `backoff:2m` - current backoff interval (derived)
- `last_activity:2025-12-31T10:00:00Z` - timestamp

### Implementation Layers

**Layer 1: gt agent state command**
```bash
gt agent state <agent-bead>                    # Get labels
gt agent state <agent-bead> --set idle=0       # Set label
gt agent state <agent-bead> --incr idle        # Increment
```

**Layer 2: Fix await-signal iteration tracking**
- Read `idle:N` label from agent bead
- Calculate effective timeout using BackoffConfig
- On timeout: increment label, return "timeout"
- On signal: return "signal" (agent resets)

**Layer 3: Patrol formula integration**
Update burn-or-loop step:
```bash
# If work found
gt agent state $AGENT_BEAD --set idle=0

# If no work
gt mol await-signal --agent-bead $AGENT_BEAD   --backoff-base 30s --backoff-mult 2 --backoff-max 5m

# After 10 consecutive max-timeout cycles, exit for fresh session
```

**Layer 4: Feed signal sources**
Ensure these emit events:
- gt sling → TypeSling
- bd create/update/close → BeadMutation
- gt mail send → TypeMail

### ZFC Compliance

| Component | Role | ZFC |
|-----------|------|-----|
| Feed curator | Aggregates events | ✅ Transport |
| await-signal | Waits with timeout | ✅ Transport |
| Agent bead labels | Stores idle_cycles | ✅ Agent-written |
| Backoff decision | Agent decides | ✅ Agent decides |

Go code provides mechanics. **Agent decides** parameters, reset, and exit.

### Existing Infrastructure

- Feed Curator: internal/feed/curator.go ✅
- BackoffConfig: internal/beads/molecule.go ✅
- await-signal cmd: internal/cmd/molecule_await_signal.go (needs fix)
- Agent Beads: internal/beads/beads.go ✅
- Labels pattern: docs/operational-state.md ✅

### Exit Strategy

After N consecutive max-interval cycles (e.g., 10 × 5m = 50 minutes idle):
- Agent exits cleanly
- Daemon respawns fresh session
- Fresh session starts with idle:0


Digest: mol-deacon-patrol

Patrol 6: healthy


Digest: mol-deacon-patrol

Patrol 18: Quiet


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 2: all clear, 9 sessions healthy


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 4: nominal


gt status is slow - needs performance optimization


CLI: workspace commands (init, add, list)

GGT needs workspace management commands beyond install.

## Commands (beyond gt-f9x.3 install)

### gt workspace list
List all rigs in current workspace.
```
gt workspace list [--json]
```
Essentially `gt rig list` but framed as workspace view.

### gt workspace add
Add existing rig to workspace (alternative to gt rig add).
```
gt workspace add <git-url> [--name NAME]
```

### gt onboard
Interactive first-time setup wizard.
```
gt onboard
```
- Prompts for workspace location
- Creates structure via gt install
- Offers to add first rig

## Note
May be redundant with gt-f9x.3 (install) and gt-u1j.16 (rig commands).
Consider if this is needed or should be closed as covered by those.

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


CLI: worker status reporting commands

Worker status reporting CLI for polecats to report progress.

## Commands

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

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

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

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

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

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

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

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

## New File
internal/cmd/worker.go

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

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


Digest: mol-deacon-patrol

Patrol cycle 19


Witness handoff bead state persistence

Implement state persistence for Witness across wisp cycles.

## Problem
Wisps burn between cycles, but Witness needs to remember:
- Which workers have been nudged
- How many times (nudge_count)
- When was last nudge
- Last observed activity

## Solution
Witness handoff bead with worker_states field:

```json
{
  "id": "gt-witness-state",
  "type": "handoff",
  "assignee": "<rig>/witness",
  "pinned": true,
  "worker_states": {
    "furiosa": {
      "issue": "gt-123",
      "nudge_count": 2,
      "last_nudge": "2024-12-22T10:00:00Z"
    }
  },
  "last_patrol": "2024-12-22T10:05:00Z"
}
```

## Implementation
1. On patrol start: bd show <witness-handoff-id> to load state
2. During patrol: update in-memory state
3. On save-state step: bd update to persist
4. State survives wisp burn/squash

## Depends on
- gt-83k0 (mol-witness-patrol definition)


Digest: mol-deacon-patrol

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


Merge: gt-qsvq

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


Move disk 2: A → C

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


Formula cycle detection during cooking

Detect and error on circular extends chains during bd cook. E.g., if formula A extends B extends A, cooking should fail with clear error message pointing to the cycle.


Move disk 4: A → C

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


Witness swarm landing protocol

Witness responsibilities for swarm landing cleanup.

## Trigger

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

## Landing Protocol

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

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

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

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

## Code at Risk Handling

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

## Reference

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


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


Digest: mol-deacon-patrol

P19: stable


Digest: mol-deacon-patrol

Patrol 6: Quiet


Digest: mol-deacon-patrol

Cycle 182: All agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol cycle 6: All healthy


Move disk 1: A → B

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


Implement gt worktree create command

Create worktree in target rig for cross-rig work.

Usage: gt worktree <rig>

Behavior:
1. Detect current identity (gastown/crew/joe)
2. Compute worktree path: ~/gt/<rig>/crew/<source-rig>-<name>/
3. If worktree doesn't exist:
   - git worktree add <path> main
   - Set up .git config for identity preservation
4. cd to worktree (or print path for user to cd)
5. Preserve BD_ACTOR, GT_ROLE, etc.

Edge cases:
- Worktree already exists → just enter it
- Rig doesn't exist → error with helpful message
- No crew identity → error (must be crew to use this)


Digest: mol-deacon-patrol

Patrol 16: all clear


gt polecat git-state command for pre-kill verification

Add git-state subcommand to gt polecat for Witness pre-kill verification.

## Usage
```bash
gt polecat git-state <rig>/<polecat>
```

## Output
```
Git State: gastown/furiosa

  Working Tree: clean | dirty
  Uncommitted:  0 files | N files (list)
  Unpushed:     0 commits | N commits ahead
  Stashes:      0 | N stashes

  Verdict: CLEAN (safe to kill) | DIRTY (needs cleanup)
```

## JSON output (--json flag)
```json
{
  "clean": true,
  "uncommitted_files": [],
  "unpushed_commits": 0,
  "stash_count": 0
}
```

## Used by
- Witness pre-kill verification (mol-witness-patrol)
- Manual cleanup checks

## Implementation
- Check git status in polecat worktree
- Check git log origin/main..HEAD
- Check git stash list


Digest: mol-deacon-patrol

Patrol 5: All healthy, no messages


Digest: mol-deacon-patrol

Patrol 10: quiet


Move disk 4: C → B

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


Molecular Chemistry Cleanup: Fix inaccurate molecule depictions

## The Correct Model

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

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

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

## What's Wrong

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

---

## MAJOR ISSUES

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

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

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

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

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

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

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

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

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

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

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

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

---

## MEDIUM ISSUES

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

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

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

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

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

**Files:** Various docs and templates

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

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

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

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

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

### 7. manager.go (UPDATE)

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

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

---

## IMPLEMENTATION ORDER

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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 6: All healthy


Digest: mol-deacon-patrol

Patrol cycle 18: all healthy


decide-actions

Apply nudge matrix and queue actions.

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

Needs: inspect-workers


Digest: mol-deacon-patrol

Cycle 8


Implement meta-formula generator in parser

Implement the generator that expands meta-formulas into concrete formulas.

## Implementation

1. Detect type: meta-formula in parser
2. Evaluate for-each values
3. For each value, instantiate the formula template
4. Substitute {var} placeholders with current value
5. Return list of generated Formula structs

## API

    func (p *Parser) ExpandMetaFormula(mf *MetaFormula) ([]*Formula, error)

## Edge Cases

- Empty values list: return empty slice
- Duplicate generated names: error
- Nested meta-formulas: error (not supported initially)


Digest: mol-refinery-patrol

Patrol: empty queue, inbox clean, no orphaned MRs


Digest: mol-deacon-patrol

Patrol 58: All healthy


gt mail: Cross-level routing is broken

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


Refinery for gastown - processes merge queue.

role_type: refinery
rig: gastown
agent_state: dead
hook_bead:
role_bead: gt-refinery-role

Marked dead by daemon at 2026-01-02T02:35:24-08:00 (was running, last update too old)


Merge: gt-5af.6

branch: polecat/Slit
target: main
source_issue: gt-5af.6
rig: gastown


gt spawn/crew setup should create .beads/redirect for worktrees

Crew clones and polecats need a .beads/redirect file pointing to the shared beads database (../../mayor/rig/.beads). Currently:

- redirect files can get deleted by git clean
- not auto-created during gt spawn or worktree setup
- missing redirects cause 'no beads database found' errors

Found missing in: gastown/joe, beads/zoey (after git clean)

Fix options:
1. gt spawn creates redirect during worktree setup
2. gt prime regenerates missing redirects
3. bd commands auto-detect worktree and find shared beads

This should be standard Gas Town rig configuration.


Move disk 2: B → A

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


gt session restart/status: Complete session management

Add missing session subcommands:

- gt session restart <rig> <polecat> - Restart a session (stop + start)
- gt session status <rig> <polecat> - Show session status details

status should show:
- Running state
- Uptime
- Current activity
- Last output timestamp


Digest: mol-deacon-patrol

Patrol 8: Quiet


Digest: mol-deacon-patrol

Patrol 12: all healthy


Digest: mol-deacon-patrol

Patrol 8


Remove markdown molecule heresy from ~/gt/molecules/

The ~/gt/molecules/lifecycle/*.md files are outdated heresy - molecule definitions should only exist as formula.toml files in .beads/formulas/. Remove the markdown specs and update any docs that reference them.


Maintain dog pool

Ensure dog pool has available workers for dispatch.

**Step 1: Check dog pool status**
```bash
gt dog status
# Shows idle/working counts
```

**Step 2: Ensure minimum idle dogs**
If idle count is 0 and working count is at capacity, consider spawning:
```bash
# If no idle dogs available
gt dog add <name>
# Names: alpha, bravo, charlie, delta, etc.
```

**Step 3: Retire stale dogs (optional)**
Dogs that have been idle for >24 hours can be removed to save resources:
```bash
gt dog status <name>
# Check last_active timestamp
# If idle > 24h: gt dog remove <name>
```

**Pool sizing guidelines:**
- Minimum: 1 idle dog always available
- Maximum: 4 dogs total (balance resources vs throughput)
- Spawn on demand when pool is empty

**Exit criteria:** Pool has at least 1 idle dog.


Move disk 3: A → B

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


Recreate beads rigs with fresh clones

## Problem

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

## Tasks

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

## Rigs to recreate

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

## Source

Clone from beads repo (need to confirm remote URL)


Merge: slit-mjvtz18y

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


bd cook command: Formula to Proto

Implement the 'bd cook' command that transforms formulas into protos.

Usage: bd cook <formula-file> [options]
       bd cook .beads/formulas/*.formula.yaml

Process:
1. Parse formula YAML (uses formula parser)
2. Resolve extends (formula inheritance)
3. Expand macros (expansion rules)
4. Apply aspects (cross-cutting concerns)
5. Generate flat proto bead

Output:
- Creates proto bead in .beads/ with mol-prefix
- Proto has all steps pre-expanded
- Proto is ready for pour/wisp instantiation

**Beads issue: bd-wa2l**


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 4: A → C

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


Digest: mol-deacon-patrol

Patrol 115: All healthy


Digest: mol-deacon-patrol

Patrol 146 complete: All healthy


CLI: witness commands (start, stop, status)

Witness daemon CLI commands.

## Commands

### gt witness start
Start the witness daemon for a rig.
```
gt witness start <rig> [--interval <seconds>]
```
- Starts background daemon process
- Default heartbeat interval: 30s
- Logs to <rig>/witness/witness.log

### gt witness stop
Stop the witness daemon.
```
gt witness stop <rig>
```
- Graceful shutdown
- Completes current heartbeat cycle

### gt witness status
Show witness status.
```
gt witness status <rig> [--json]
```
Output:
- Running/stopped
- Last heartbeat time
- Polecats being monitored
- Recent nudges/escalations

### gt witness logs
View witness logs.
```
gt witness logs <rig> [--follow] [--lines <n>]
```
- --follow: Continuous output (like tail -f)
- --lines: Number of lines (default 50)

## Daemon Management

Witness runs as background process:
- PID stored in <rig>/witness/witness.pid
- Uses nohup for persistence
- Logs structured JSON events

## Implementation

```go
var witnessCmd = &cobra.Command{Use: "witness"}
witnessCmd.AddCommand(startCmd, stopCmd, statusCmd, logsCmd)
```

Start launches daemon via exec, status reads PID file and pings process.


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.


Digest: mol-deacon-patrol

Patrol 5: quick pass


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 15: all clear


Digest: mol-deacon-patrol

Patrol 17: routine


Direct test

Testing direct bd create


Daemon: integration test with real lifecycle

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

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


Digest: mol-deacon-patrol

Patrol 2: Routine, all healthy


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

Remove bd mol spawn entirely from vocabulary.

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

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

See bd-XXX for Beads-side removal.


Patrols: Cyclic molecules for autonomous maintenance

## Vision

Patrols are **cyclic molecules** - workflow loops that give Gas Town its autonomous nervous system. While regular molecules are DAGs that terminate, patrols loop forever, performing maintenance tasks at varying cadences.

This is the "steam engine" of Gas Town: converting episodic Claude sessions into continuous autonomous operation.

## Core Concepts

### 1. Cyclic Molecules

Regular molecule:     A -> B -> C -> done
Patrol molecule:      A -> B -> C --+
                      ^             |
                      +-------------+

Patrols have a loop_to field specifying where to restart.

### 2. Cooldown-Aware Steps (Atoms)

Steps encode their own cadence. When patrol reaches a step:
1. Check: now - last_run > cooldown?
2. If yes: execute, update last_run
3. If no: skip (immediately close)

The patrol runner is simple - steps self-skip. Complexity distributed into atoms.

### 3. The Beacon

The heartbeat that fires patrol triggers:
- Internal ticker in Deacon (goroutine)
- Or external cron firing gt deacon tick
- Or mail-based triggers

Without beacon, nothing proactive happens.

### 4. Session Reset as Patrol Step

Connects to auto-handoff (gt-bcwn). Session reset is a patrol step, not a separate mechanism.

### 5. Multi-Role Patrols

Each supervisor has its own patrol:

**Deacon patrol:** health-check (30s), session-gc (5m), beacon-tick (10s)
**Witness patrol:** orphan-scan (10m), stuck-check (2m), molecule-progress (1m)
**Refinery patrol:** queue-check (30s), pr-status (1m), merge-ready (30s)

### 6. Cadence Tiers

- Critical (10-30s): Health checks
- Active (1-5m): Progress, nudges
- Maintenance (10-30m): Orphans, GC
- Periodic (1h+): Reports

### 7. Best-Effort Scheduling

Not real-time - more like cron. No hard deadlines. Catch-up, dont pile-up.
Priority preemption (mail interrupts patrol). Graceful degradation under load.

## Open Questions

1. State persistence: Beads (self-describing) or file (faster)?
2. Interruption: How does urgent mail preempt patrol?
3. Error recovery: Backoff? Escalate? Circuit breaker?
4. Coordination: Can patrols send mail to trigger other patrols?

## Related

- gt-bcwn: Auto-handoff (session reset is a patrol step)
- Molecule system (patrols extend molecules with loops)
- Deacon lifecycle management

## Metaphor

Claude was fire. Claude Code was steam. Gas Town is the steam engine. Beads is the train tracks.

The steam engine converts episodic combustion into continuous rotary motion.
Gas Town converts episodic Claude sessions into continuous autonomous work.


Digest: mol-deacon-patrol

Patrol 7


Digest: mol-deacon-patrol

Patrol cycle 19: All healthy


Digest: mol-deacon-patrol

Patrol cycle 19: All 6 agents healthy