Merge: nux-1767138828269

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


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 166/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.


execute-actions

Send nudges, process shutdowns, escalate as decided.

Needs: decide-actions


Refinery patrol: Add sibling-check step

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

## Implementation

1. Add `sibling-check` step to mol-refinery-patrol (early in cycle)
2. Use `gt peek <rig>/witness 20` to check Witness output
3. Look for signs of health:
   - Recent activity (tool calls, log messages)
   - No error stack traces
   - Responsive to pings
4. If Witness seems stuck:
   - Send status request mail
   - Note for potential escalation
   - Don't block Refinery work

## Acceptance
- Refinery checks Witness each patrol cycle
- Anomalies logged
- Non-blocking (Refinery continues even if Witness is down)


Update architecture documentation

Update all documentation to reflect refinery-as-worktree model.

## Files to update
- docs/architecture.md (if exists)
- CLAUDE.md references to refinery
- mayor/rig/docs/*.md - any refinery docs
- wisp-architecture.md - add MR wisp details
- README files mentioning clone vs worktree

## Key messages
- Refinery is worktree, not clone
- Polecat branches stay local
- Only main pushed to origin
- MRs are wisps (ephemeral)


Merge: gt-odvf

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


Handoff mail not delivered to mayor inbox

Town log shows predecessor handed off at 12:59:33 with message about gt-7psb8, but gt mail inbox shows 0 messages. The handoff context was lost.

Reproduction:
1. Mayor runs gt handoff with -s 'context'
2. New mayor session starts
3. gt mail inbox shows empty

Expected: Handoff mail in inbox

(Moved from hq-zs2t8)


Merge: nux-1767059693217

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


End-of-cycle inbox hygiene

Verify inbox hygiene before ending patrol cycle.

**Step 1: Check inbox state**
```bash
gt mail inbox
```

Inbox should be EMPTY or contain only just-arrived unprocessed messages.

**Step 2: Archive any remaining processed messages**

All message types should have been archived during inbox-check processing:
- WITNESS_PING → archived after acknowledging
- HELP/Escalation → archived after handling
- LIFECYCLE → archived after processing

If any were missed:
```bash
# For each stale message found:
gt mail archive <message-id>
```

**Goal**: Inbox should have ≤2 active messages at end of cycle.
Deacon mail should flow through quickly - no accumulation.


Digest: mol-deacon-patrol

Patrol 23: Quick cycle, no changes. All agents healthy.


Digest: mol-deacon-patrol

Patrol 7: clear


mol-gastown-boot: Mayor-driven town bootstrap

Mayor bootstraps Gas Town via a verification-gated lifecycle molecule.

## Vision

When user says "boot up gas town", Mayor slings `mol-gastown-boot` and executes it.
Each step has **action + verification** - steps stay open until outcome is confirmed.

## Key Principles

1. **No daemon-based timeouts** - Mayor keeps trying until verified
2. **Verification-gated steps** - Not "command ran" but "outcome confirmed"
3. **gt peek for verification** - Capture session output to detect stalls
4. **gt nudge for recovery** - Reliable message delivery to unstick agents
5. **Parallel where possible** - Witnesses can start in parallel
6. **Ephemeral execution** - Boot is a wisp, squashed to digest

## Proto Catalog

Town maintains a catalog of protos at `~/gt/molecules/`:

```
~/gt/molecules/
├── lifecycle/
│   ├── gastown-boot/       # Full town bootstrap
│   ├── rig-spinup/         # Add a rig at runtime
│   ├── rig-spindown/       # Remove a rig gracefully
│   └── agent-restart/      # Restart single agent
├── patrol/
│   ├── deacon-patrol/      # Deacon health loop
│   ├── witness-patrol/     # Witness polecat loop
│   └── refinery-patrol/    # Refinery merge loop
└── work/
    ├── polecat-work/       # Standard issue workflow
    ├── code-review/        # Pluggable review
    └── feature/            # Feature development
```

## mol-gastown-boot Structure

```
mol-gastown-boot (proto)
├── ensure-daemon       # Verify daemon running
├── ensure-deacon       # Start deacon, verify patrol active
├── ensure-witnesses    # Parallel: all rig witnesses
│   ├── ensure-gastown-witness
│   └── ensure-beads-witness
├── ensure-refineries   # Parallel: all rig refineries
│   ├── ensure-gastown-refinery
│   └── ensure-beads-refinery
└── verify-town-health  # Final gt status check
```

## Step Template

Each step in description includes action + verification:

```markdown
## Step: ensure-deacon

### Action
gt deacon start

### Verify
1. Session gt-deacon exists: `tmux has-session -t gt-deacon`
2. Not stalled: `gt peek deacon/` does NOT show "> Try"
3. Recent heartbeat: deacon/heartbeat.json < 2 min old

### On Stall
gt nudge deacon/ "Start patrol."
Wait 30s, re-verify.

### On Fail
Log error, continue to next step (town can run with degraded deacon)
```

## Event-Triggered Lifecycle

Beyond manual slinging, events can trigger lifecycle wisps:

| Event | Triggers |
|-------|----------|
| `gt town start` | mol-gastown-boot wisp |
| `gt rig add <name>` | mol-rig-spinup wisp |
| `gt rig remove <name>` | mol-rig-spindown wisp |
| Agent crash detected | mol-agent-restart wisp |

## Parameterization (Future)

For rig-spinup/spindown, need to pass rig name:

```bash
gt sling rig-spinup mayor/ --param rig=newproject
```

Molecule steps interpolate `${rig}` in their descriptions.

## Related Issues

- gt-lx3n: Witness startup bond
- gt-j6s8: Refinery startup bond
- gt-rana: Patrol System epic
- gt-sye: Mayor startup protocol


Merge: keeper-mjwcc4ik

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


Formula validation specification

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

Deferred: post-launch polish


Digest: mol-deacon-patrol

Patrol 11: Quick cycle, all quiet


gt spawn pins mol-polecat-work

Enhance gt spawn to automatically pin mol-polecat-work to new polecats.

## Current Behavior

gt spawn --issue gt-xxx creates polecat with issue in mail but no molecule.

## New Behavior

gt spawn should:
1. Create fresh worktree (existing)
2. Initialize polecat beads (existing)
3. Bond mol-polecat-work with issue as variable
4. Pin the molecule to polecat hook
5. Create polecat session

## Molecule Bonding

```bash
bd mol bond mol-polecat-work --var issue_id=gt-xxx --var rig=gastown
```

Creates .beads/molecules/mol-polecat-work-<hash>.state.yaml

## Hook Pinning

```bash
bd pin mol-polecat-work-<hash> --for polecat/<name>
```

Creates .beads-wisp/hook-polecat-<name>.wisp.yaml pointing to molecule

## Files

- internal/spawn/spawn.go - Add mol-polecat-work bonding
- Or: internal/cmd/spawn.go depending on structure


Merge: nux-mjw3mn8o

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


Find abandoned work

Find abandoned work.

Scan for orphaned state:
- Issues marked in_progress with no active polecat
- Polecats that stopped responding mid-work
- Merge queue entries with no polecat owner
- Wisp sessions that outlived their spawner

```bash
bd list --status=in_progress
gt polecats --all --orphan
```

For each orphan:
- Check if polecat session still exists
- If not, mark issue for reassignment or retry
- File incident beads if data loss occurred


Molecule Workflow Engine: Composable Crystallized Workflows

# Epic: Molecule Workflow Engine

**Vision**: Molecules are crystallized, composable, nondeterministic-idempotent workflow templates. Any worker can pick up where any other worker was interrupted and continue along the molecule.

**Christmas Target**: Full molecule-based workflow engine operational by Dec 25, 2025.

## The Core Concepts

1. **Molecule**: Read-only workflow template (beads issue with type=molecule)
2. **Atom/Step**: Individual work unit with prose instructions
3. **Bond**: Dependency between steps
4. **Polymer/Derived**: Molecule composed from other molecules
5. **Instance**: Concrete beads created when molecule is attached to work

## Key Features Needed

### 1. Molecule Composition (Includes Directive)
Molecules can include other molecules:
\`\`\`markdown
## Molecule: gastown-polecat
Includes: mol-engineer-in-box

## Step: install-binary
Build and install the local gt binary.
Needs: submit
\`\`\`

### 2. Standard Molecules
- mol-install-go-binary: Single step to build/install gt
- mol-gastown-polecat: engineer-in-box + install-binary

### 3. Spawn Integration
\`gt spawn --issue <id> --molecule <mol-id>\` creates molecule instance then starts polecat on first ready step.

### 4. Nondeterministic Idempotence
- Steps are atomic (pending → in_progress → completed)
- Any worker can pick up any ready step
- Step timeout/recovery for stuck workers

## Success Criteria
- [ ] Polecats can be spawned with mol-gastown-polecat
- [ ] Derived molecules work end-to-end
- [ ] 10+ polecat swarm completes molecule workflows
- [ ] install-go-binary step runs after successful merges


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


mol-deacon-patrol

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

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


Deacon session cycling: first step of rounds

First step of every Deacon wake cycle: check if a fresh session is needed.

## Why First

Token costs are quadratic with session length. A Deacon running for hours
accumulates massive context. Better to cycle early and often.

## Implementation

At wake, before doing anything else:

1. Check context budget estimate (conversation turns, tool calls, etc.)
2. If budget is low (e.g., >50% consumed), request cycle:
   - Write handoff mail to self with current state
   - Request lifecycle: cycle via daemon
   - Daemon kills session, starts fresh
   - New session reads handoff mail, continues

## Decision Criteria

- Conversation turns > N (configurable, default 50?)
- Explicit "context feels heavy" signal from Claude
- Time since last cycle > M hours (configurable, default 4?)
- Forced cycle on certain events (e.g., major config change)

## State to Preserve in Handoff

- Current health status
- Pending lifecycle requests (in flight)
- Plugin state (last run times, outcomes)
- Any active timers

## Relation to Daemon

The Deacon requests its own cycle via the same lifecycle mechanism:
```
gt mail send deacon/ -s "LIFECYCLE: deacon/ requesting cycle" -m "..."
```

Daemon sees this, kills gt-deacon session, respawn loop restarts it.


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.


gt done: Notify Witness with exit outcome

When polecat runs gt done, it should send mail to Witness:

```
gt mail send <rig>/witness -s 'POLECAT_DONE <name>' -m 'Exit: COMPLETED
Issue: <issue-id>
MR: <mr-id>
Branch: <branch>'
```

Exit types:
- COMPLETED: Work done, MR submitted
- ESCALATED: Hit blocker, needs human
- DEFERRED: Work paused, issue still open

This enables Witness patrol to:
1. See completion in inbox-check step
2. Verify git state is clean
3. Kill session and prune worktree
4. Close the polecat lease in its patrol wisp

Paired with gt-r6td (spawn notification) - together they bracket polecat lifecycle.


Digest: mol-deacon-patrol

Patrol 152: All healthy


Digest: mol-deacon-patrol

Patrol 2: all clear, systems healthy


Digest: mol-deacon-patrol

Patrol 1: All 3 rigs healthy, 17 sessions running, no issues


Move disk 2: A → C

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


Self-mail should suppress tmux notification

When sending mail to yourself (e.g., mayor sending to mayor/), the tmux notification shouldn't fire.

**Rationale:**
- Self-mail is intended for future-you (next session handoff)
- Present-you just sent it, so you already know about it
- The notification is redundant/confusing in this case

**Fix:**
Suppress tmux notification when sender == recipient address.


Update refinery to read local branches

Refinery manager needs to access polecat branches locally instead of fetching from origin.

## Changes
- internal/refinery/manager.go - remove origin fetch for MR branches
- internal/refinery/engineer.go - local branch access
- Remove DeleteRemoteBranch calls (branches are local now)
- Update merge workflow to work with local refs

## Key insight
All worktrees share the same .git - refinery can see polecat/nux branch directly.


Digest: mol-deacon-patrol

P9: stable


Session: gt-gastown-test completed gt-f7jxr


Digest: mol-deacon-patrol

Patrol complete: both rigs healthy, handoff threshold reached


Platform of Platforms (POP) Foundation

Design and implementation of the Platform Adapter Layer for HOP. Enables multiple work platforms to integrate with the universal work ledger. See ~/gt/docs/hop/PLATFORM-OF-PLATFORMS.md for full architecture.


Digest: mol-deacon-patrol

Patrol 20: all quiet - handoff cycle


Move disk 2: B → A

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


Move disk 1: B → C

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


gt mail archive/purge: Archive management

Add `gt mail archive` and `gt mail purge` commands.

### gt mail archive
```
gt mail archive [--older-than DAYS] [--all-read] [--dry-run]
```
- Move messages from inbox.jsonl to archive.jsonl
- Default: archive read messages older than 7 days

### gt mail purge
```
gt mail purge [--older-than DAYS] [--dry-run] [--force]
```
- Permanently delete from archive.jsonl
- Confirm unless --force

**Implementation:**
- Add to internal/cmd/mail.go
- Add Archive(), Purge() to internal/mail/mailbox.go
- Create archive.jsonl in same directory as inbox.jsonl


Mol Mall: Formula Package Registry

A package registry for sharing and discovering formulas, schematics, and protocols.

## Concept

Like npm/Maven/Go modules but for workflow definitions.

```
mol-mall.io/
├── @gastown/           # Official Gas Town formulas
│   ├── shiny
│   ├── polecat-work
│   └── release
├── @acme-corp/         # Enterprise org (private)
│   └── compliance-review
├── @linus/             # Individual publisher
│   └── kernel-review
└── community/          # Unscoped public formulas
    └── towers-of-hanoi
```

## Resolution Hierarchy

```
1. Project:  ./.beads/formulas/          # Project-specific
2. Rig:      ~/gt/<rig>/.formulas/       # Rig-wide
3. Town:     ~/gt/.formulas/             # Town-wide (mayor stdlib)
4. User:     ~/.gastown/formulas/        # Personal collection
5. Mall:     mol-mall.io/                # Published packages
```

## Package Manifest

```toml
[package]
name = "shiny"
version = "1.2.0"
description = "Engineer in a Box"
authors = ["Gas Town <gastown@example.com>"]
license = "MIT"

[dependencies]
"@gastown/review-patterns" = "^2.0"
```

## Distribution Scenarios

1. **Celebrity Formulas**: Expert-curated workflows (e.g., Linus kernel review)
2. **Enterprise Compliance**: Private company formulas
3. **Standard Library**: @gastown/* blessed defaults
4. **Community Ecosystem**: Varying quality, needs ratings/verification

## Open Questions

1. Versioning semantics - SemVer? Breaking change rules?
2. Security model - sandboxing? signing? permissions?
3. Private registries - self-hosted? authentication?
4. Lock files - formulas.lock format?

## Related

- docs/formula_evolution.md - package ecosystem parallel section
- gt-8ws7o - Schematic (can be published)
- gt-y3jb9 - Protocol (can be published)


Digest: mol-deacon-patrol

Patrol cycle 6: all healthy


Digest: mol-deacon-patrol

Patrol 9 complete


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 20: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy


gt-polecat-gastown-testcat

gt-polecat-gastown-testcat

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


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 cycle 29: All healthy, no incidents


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.


Day 1.6: Update gt mol status to use hook slot

Migrate gt mol status from:
- Query(status=pinned AND assignee=me)
To:
- Read agent bead → check hook_bead field

This eliminates hook ambiguity.

Parent: gt-d0jqp


Digest: mol-deacon-patrol

Patrol cycle 9: All healthy, 4 polecats


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Cycle 12


Move disk 2: B → A

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Routine patrol, town stable


Centralize session name construction patterns

Session name patterns like fmt.Sprintf("gt-%s-<role>", rigName) scattered across files:
- witness.go:287
- refinery.go:383
- start.go:275
- crew_helpers.go:68-70

Also: sessionToAgentID logic duplicated in sling.go:365-391 and handoff.go:374-402.

Suggestion: Create session_names.go with WitnessSessionName(), RefinerySessionName(), CrewSessionName() functions plus AgentIdentity type with FromSessionName()/ToSessionName() methods.


self-review

Review your own changes. Look for:
- Bugs and edge cases
- Style issues
- Missing error handling
- Security concerns

Fix any issues found before proceeding.

Depends: implement


Move disk 3: B → C

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


Digest: mol-deacon-patrol

Patrol 10


Test MR

branch: test-branch
target: main
source_issue: gt-test
rig: gastown


Move disk 1: A → B

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


VC Pattern Integration: Bring validated ideas to Gas Town

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

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

Child tasks track each pattern to integrate.


Digest: mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol complete: town quiet, all healthy


Digest: mol-deacon-patrol

Patrol cycle 45: All healthy


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 5: nominal


Clean up duplicate patrol protos (gt-qflq, gt-iep9)

There are duplicate protos for patrol molecules:

## Duplicates

| Old Proto | New Proto | Name |
|-----------|-----------|------|
| gt-qflq | mol-witness-patrol | mol-witness-patrol |
| gt-iep9 | mol-deacon-patrol | mol-deacon-patrol |

The old gt-* prefix protos were created before the formula cooking system.
The new mol-* prefix protos were created by `bd cook`.

## Action

1. Close or delete the old gt-* protos
2. Update any references to use the new mol-* protos
3. Verify `bd mol list` shows clean output

## Root Cause

The bd cook command uses the formula name as the proto ID (mol-*),
not the project prefix (gt-*). This is probably correct behavior,
but means we have legacy protos to clean up.


Hookable mail beads: Ad-hoc instruction handoff

## Summary
Enable mail beads to be hooked, providing a mechanism for ad-hoc instruction handoff that complements structured molecules.

## Two Use Cases
A. **Hook existing mail**: `gt hook attach <mail-id>` - for backlog mail that becomes priority
B. **Hook new instructions**: `gt handoff -m "..."` auto-hooks the mail it creates

## Current Gap
- Molecules (GUPP+MEOW): Structured work, hookable, machine-guided execution
- Issues: Hookable via mol wrapper
- Mail: Contains ad-hoc instructions but NOT hookable - relies on successor checking inbox

## Proposed Behavior

### gt hook attach <bead-id>
Already exists but should work for ANY bead type including mail:
```bash
gt hook attach hq-abc123  # Works for mail, issues, mols
```

### gt handoff (enhanced)
```bash
gt handoff -s "Swarm execution" -m "1. Create convoy..."
# Creates mail bead
# Auto-hooks the mail
# Respawns session
```

### Successor Startup
```bash
gt hook
# Shows: 🪝 Hook: hq-xxx (mail from mayor/)
#        Subject: 🤝 HANDOFF: Swarm execution
#        Run: gt mail read hq-xxx
```

GUPP applies: If hooked, execute (read mail, follow instructions).

## Execution Models
| Hooked Type | Execution |
|-------------|-----------|
| Molecule | Cook formula, follow steps |
| Issue | Claim and complete task |
| Mail | Read, interpret, execute prose |

## Documentation Required
- [ ] All role CLAUDE.md files
- [ ] Priming docs (gt prime output)
- [ ] gt handoff --help
- [ ] Hook system docs

## Implementation
1. Ensure `gt hook attach` accepts any bead type
2. Enhance `gt hook` display for mail beads
3. Update `gt handoff` to auto-hook mail
4. Update startup hooks to handle mail on hook


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


Digest: mol-deacon-patrol

Patrol 241 complete: 3 witnesses, 3 refineries healthy; 6 polecats active; 1 dog idle; no orphans; no incidents


Move disk 1: B → C

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


bd mol current: soft cursor showing current/next step

Add bd mol current command for molecule navigation orientation.

## Usage

bd mol current [mol-id]

If mol-id given, show status for that molecule.
If not given, infer from in_progress issues assigned to current agent.

## Output

You're working on molecule gt-abc (Feature X)

  [checkmark] gt-abc.1: Design
  [checkmark] gt-abc.2: Scaffold
  [checkmark] gt-abc.3: Implement
  [arrow] gt-abc.4: Write tests [in_progress] <- YOU ARE HERE
  [circle] gt-abc.5: Documentation
  [circle] gt-abc.6: Exit decision

Progress: 3/6 steps complete

## Key behaviors
- Shows full molecule structure with status indicators
- Highlights current in_progress step
- If no in_progress, highlights first ready step
- Works without explicit cursor tracking (inferred from state)

## Implementation notes
- Query children of mol-id
- Sort by dependency order
- Find first in_progress or first ready
- Format with status indicators

## Beads feature
This is a bd command - needs implementation in beads repo.


Test2

Testing gt mail


gt rig reset: clear stale mail on reset/land

## Problem

When resetting or landing a rig/town, stale mail messages can confuse agents on startup. Old handoff messages, daemon notifications, and inter-agent mail should be cleaned up as part of reset.

## Current State

- `gt rig reset` exists but doesn't clear mail
- Stale messages accumulate (e.g., daemon SHUTDOWN messages)
- Agents may read outdated context on startup

## Proposed Behavior

`gt rig reset` and `gt town reset` should:
1. Close all open messages (`--type=message`) in the relevant beads
2. Optionally preserve pinned handoff beads (clear content, keep bead)
3. Log what was cleaned up

```bash
gt rig reset gastown          # Clears gastown mail
gt rig reset gastown --mail   # Only clear mail, keep other state
gt town reset                 # Clears all town-level mail
gt town reset --all           # Clears mail in all rigs too
```

## Implementation

1. Query `bd list --type=message --status=open`
2. Close each with reason 'Cleared during reset'
3. For pinned handoffs: `bd update <id> --description=''` instead of close


gt daemon: Background service management

## Summary

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

## Architecture

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

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

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

## Commands

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

## Daemon Loop

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

## Lifecycle Request Handling

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

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

## Poke Protocol

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

## Lifecycle Hierarchy

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

## Related Issues

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


Execute registered plugins

Execute registered plugins.

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

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

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

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

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

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


Refinery: Non-blocking delegation via bead-gates

## Problem: Refinery Blocks on Delegation

Current flow when rebase fails:
1. Refinery creates conflict-resolution task
2. Refinery BLOCKS waiting for resolution
3. Queue backs up behind stuck MR

## Solution: Gate-Based Non-Blocking Delegation

When rebase fails:
1. Create conflict-resolution task (existing: gt-si8rq.3)
2. Create bead-gate waiting for that task to close
3. Add gate as blocker to MR bead
4. **Continue to next MR** (do not block)
5. When gate closes → MR unblocks → re-enters ready queue

```
MR Queue:  [MR-A] [MR-B] [MR-C]
              │
              ▼
         Rebase fails
              │
    ┌─────────┴─────────┐
    ▼                   ▼
Create conflict    Create gate
task (polecat)     (blocks MR-A)
    │                   │
    │                   ▼
    │              Continue to MR-B
    │              (non-blocking!)
    ▼
Polecat resolves
    │
    ▼
Task closes → Gate closes → MR-A unblocks
```

## Implementation

### In Refinery handleConflict():
```go
// Create conflict task (existing)
conflictTask := createConflictTask(mr, conflict)

// NEW: Create gate
gate := bd.GateCreate{
    Type:    "bead",
    AwaitID: conflictTask.ID,
    Timeout: "2h",
}
gateID := bd.CreateGate(gate)

// NEW: Block MR on gate
bd.DepAdd(mr.ID, gateID)

// NEW: Continue to next MR (dont block)
return nil  // not an error, just deferred
```

### Gate Resolution
When conflict task closes:
1. Gate auto-closes (bead-gate behavior)
2. MR bead unblocks (dep satisfied)
3. MR appears in `bd ready --type=merge-request`
4. Refinery picks it up in next patrol

## Benefits
- Queue keeps moving (no single-MR blockage)
- Multiple conflicts can be in-flight
- Priority ordering still respected
- Uses existing gates infrastructure

## Related
- gt-4u49x: Merge-slot gate (serializes actual merges)
- gt-si8rq.3: Conflict task creation (existing)
- bd-4k3c: Gate bead creation (existing)


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy


Digest: mol-deacon-patrol

Patrol 3: Quiet


Overseer Crew: User-managed persistent workspaces

## Overview

Crew workers are the overseer's (human's) personal workspaces within a rig. Unlike polecats which are witness-managed and ephemeral, crew workers are:

- **Persistent**: Not auto-garbage-collected
- **User-managed**: Overseer controls lifecycle
- **Long-lived identities**: dave, emma, fred - recognizable names
- **Gas Town integrated**: Mail, handoff mechanics work
- **Tmux optional**: Can work in terminal directly

## Directory Structure

```
<rig>/
  polecats/       # Managed workers (witness controls)
  refinery/       # Merge queue processor
  witness/        # Pit boss
  crew/           # Overseer's personal workspaces
    dave/         # Full clone, persistent
    emma/         # Full clone, persistent
    fred/         # Full clone, persistent
```

## Key Differences from Polecats

- Location: crew/ instead of polecats/
- Lifecycle: User-managed, not witness-managed
- Auto-cleanup: Never (polecats auto-cleanup on swarm land)
- Issue assignment: Optional (polecats require it)
- Tmux: Optional (polecats require it)
- Mail & Handoff: Yes for both
- Identity: Persistent (polecats are ephemeral)

## CLI Commands

- gt crew add <name> [--rig <rig>] - Create crew workspace
- gt crew list [--rig <rig>] - List crew workspaces
- gt crew at <rig>/<name> - Attach to workspace (start session)
- gt crew attach <name> - Attach (infer rig from cwd)
- gt crew refresh <name> - Handoff + restart (context cycling)
- gt crew remove <name> [--force] - Remove workspace
- gt crew status [<name>] - Show workspace status

## Design Notes

- Crew workers use full git clones (not worktrees)
- Optional beads integration via BEADS_DIR
- Mail-to-self handoff works for context cycling
- No witness monitoring or nudging
- No automatic issue assignment required

## Background

Users often maintain separate repo clones for serial agent work. This is tedious to set up manually. Crew workspaces bring these into Gas Town's infrastructure while keeping user control.


Digest: mol-deacon-patrol

Cycle 198: Nominal


Merge: gt-znma3

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


Day 1.1b: Add type=role to bead schema

Add role as a valid bead type in the schema.

Role beads define agent behavior:
- Priming instructions (from current CLAUDE.md content)
- default_molecule field
- capabilities list

This enables Day 1.5 (creating role beads from CLAUDE.md).

Must be done alongside type=agent schema work.


Move disk 6: C → B

Move disk 6 from peg C to peg B. (Move 96/1023)


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

Patrol 13: quiet


Digest: mol-deacon-patrol

Patrol 12: Routine


Move disk 1: B → C

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


Add isAnnounceAddress() and parseAnnounceName() helpers to router.go

Add announce address detection to internal/mail/router.go.

PATTERN TO FOLLOW:
Look at isListAddress() and parseListName() at lines 53-60 as the template.

IMPLEMENTATION:
1. Add isAnnounceAddress(address string) bool - returns true if address starts with 'announce:'
2. Add parseAnnounceName(address string) string - extracts announce name after 'announce:'
3. Add var ErrUnknownAnnounce = errors.New("unknown announce channel")

FILE: internal/mail/router.go
TESTS: Add tests in internal/mail/router_test.go

Small, focused task - just address detection, not delivery.


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)


Support numeric shortcuts in mail read (e.g., 'mail read 1')

When inbox shows numbered messages like:
* 1. gm-19b29031...  2025-12-16  mayor  Subject...
* 2. gm-19b26d51...  2025-12-16         Subject...

Users should be able to run 'gt mail read 1' instead of needing the full message ID 'gt mail read gm-19b29031f6a172206'.

Implementation:
- Track inbox message order in display
- Map numeric indices to actual message IDs
- Accept both numeric shortcuts and full IDs in 'mail read' command


mol-deacon-patrol


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 9: All healthy


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 cycle 5: All 6 agents healthy


gt nudge should accept partial/fuzzy session names

Currently gt nudge requires the exact tmux session name (e.g., gt-gastown-crew-max). Should be more forgiving:

1. Accept partial matches when unambiguous (e.g., 'max' → gt-gastown-crew-max)
2. Accept shorthand like 'gastown/max' or 'crew/max'
3. Show helpful error with suggestions when ambiguous

Examples that should work:
- gt nudge max '...' → matches gt-gastown-crew-max
- gt nudge gastown/max '...' → matches gt-gastown-crew-max
- gt nudge beads-dave '...' → matches gt-beads-crew-dave


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 16: All healthy, gastown refinery queue at 3


Deacon patrol: Backup check for idle polecats that should be nuked

## Context
Witness is responsible for nuking polecats after completion (gt-xqh3y).
Deacon should have a backup check in case witness fails.

## Deacon Patrol Step
During patrol, check for polecats that are:
- State: idle
- Session: not running
- No hooked work
- Last activity > N minutes ago

These are zombies that witness should have nuked. Deacon should:
1. Log warning about witness failure
2. Nuke the polecat directly
3. Optionally notify mayor of witness issue

## Defense in Depth
Primary: Witness nukes after POLECAT_DONE
Backup: Deacon patrol catches stragglers


Chemistry UX commands from Beads

Waiting on Beads repo to implement chemistry UX sugar commands (bd pour, bd wisp, bd hook, --pour flag). These are nice-to-have polish items, not blockers for core functionality.

See: gastown/mayor/rig/docs/chemistry-design-changes.md


Mail system: message types and threading

GGT mail system needs message types and threading like PGT.

## 1. Message Types
Add to internal/mail/types.go:
```go
type MessageType string
const (
    TypeTask         MessageType = "task"         // Required processing
    TypeScavenge     MessageType = "scavenge"     // Optional first-come work
    TypeNotification MessageType = "notification" // Informational
    TypeReply        MessageType = "reply"        // Response to message
)

// Update Message struct
type Message struct {
    // existing fields...
    Type     MessageType `json:"type"`
    ThreadID string      `json:"thread_id,omitempty"`
    ReplyTo  string      `json:"reply_to,omitempty"`
}
```

## 2. Priority Levels
Expand from 2 to 4:
```go
type Priority string
const (
    PriorityLow    Priority = "low"
    PriorityNormal Priority = "normal"
    PriorityHigh   Priority = "high"
    PriorityUrgent Priority = "urgent"
)
```

## 3. CLI Updates
internal/cmd/mail.go:
- Add --type flag to send: `gt mail send ... --type task`
- Add --reply-to flag: `gt mail send ... --reply-to <msg-id>`
- Add thread command: `gt mail thread <thread-id>`

## 4. Threading Logic
NewMessage() should auto-generate thread_id if not a reply.
Reply messages inherit thread_id from original.

## Files to Modify
- internal/mail/types.go: Add types, expand Priority
- internal/mail/mailbox.go: Thread filtering
- internal/cmd/mail.go: CLI flags and thread command

## PGT Reference
gastown-py/src/gastown/mail/message.py

## Acceptance Criteria
- [ ] Messages have type field (default: notification)
- [ ] 4 priority levels supported
- [ ] Reply creates thread with shared thread_id
- [ ] gt mail thread <id> shows conversation


Move disk 4: C → B

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


Move disk 3: A → B

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


Merge: toecutter-mjwlby4g

branch: polecat/toecutter-mjwlby4g
target: main
source_issue: toecutter-mjwlby4g
rig: gastown
agent_bead: gt-gastown-polecat-toecutter


Day 1.2: Add agent-specific fields to schema

Add fields for agent beads:
- hook_bead: reference to current work (0..1 cardinality)
- role_bead: reference to role definition (1)
- state: agent-reported state (idle|running|stuck|stopped)

Parent: gt-d0jqp

Re-opened: Close reason referenced non-existent commit b5c69507. Agent fields not yet implemented in bd CLI.


Digest: mol-deacon-patrol

Patrol 71: Routine


inbox-check

Process witness mail: lifecycle requests, help requests.

```bash
gt mail inbox
```

Handle by message type:
- LIFECYCLE/Shutdown: Queue for pre-kill verification
- Blocked/Help: Assess if resolvable or escalate
- HANDOFF: Load predecessor state
- Work complete: Verify issue closed, proceed to pre-kill

Record any pending actions for later steps.
Mark messages as processed when complete.


E2E Phase 2 observability test

End-to-end test of Phase 2 observability:

Test scenario:
1. Sling work to polecat
2. Watch gt feed for polecat activity
3. Polecat completes, signals done
4. Watch gt feed for MQ events (merge_started, merged)
5. gt status shows queue depth changes
6. Swarm status visible in gt swarm status

All observable without checking .runtime/*.json files.

Success = glass cockpit is lit.


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

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


Polecat .beads/ contamination from stale branches

**Fixed in commit 8699b7b**

## Problem

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

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

## Root Cause

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

## Fix

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


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

Patrol 17: All healthy


Digest: mol-deacon-patrol

Patrol #15: All healthy


Move disk 6: A → C

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

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

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

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

## The Christmas Ornament Shape

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

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

## Phases

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

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

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

## Dynamic Arms

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

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

## Activity Feed

This design enables real-time visibility:

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

## Storage

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

## Dependencies

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

Labels: [template, christmas-ornament]


gt nudge: support no-arg invocation with default message

Currently gt nudge requires a message argument:

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

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

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


Move disk 2: B → A

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


test pin issue


Digest: mol-deacon-patrol

Patrol 125: All healthy


Digest: mol-deacon-patrol

Patrol 31: all quiet


Move disk 2: B → A

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


Move disk 1: B → C

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


mol-deacon-patrol


Delete hook functions from internal/wisp

Delete from internal/wisp/io.go:
- WriteSlungWork
- ReadHook
- BurnHook
- HasHook
- ListHooks
- HookPath

Keep: EnsureDir, WispPath, writeJSON (used by other things)


Merge: toast-mjw7062w

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


Remove unused style helper functions

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


Merge: gt-nq3pr

branch: polecat/testcat6-mjtkcfjm
target: main
source_issue: gt-nq3pr
rig: gastown


Move disk 3: B → C

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


Move disk 1: C → A

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


Move disk 1: B → C

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


Move disk 2: B → A

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


Deacon keepalive: quiet daemon during rounds

Replace tmux-poke interrupts with a keepalive file the daemon respects.

## Problem

Current daemon pokes Deacon via tmux SendKeys every ~5 minutes if heartbeat
is stale. This can INTERRUPT the Deacon mid-work, especially during long
plugin execution or health remediation.

## Solution

Deacon writes a keepalive file at start of rounds:
```json
{
  "timestamp": "2025-12-20T15:30:00Z",
  "expected_duration_minutes": 10,
  "action": "executing mol-deacon-rounds"
}
```

Daemon reads this and backs off:
- If keepalive is fresh AND within expected_duration: skip poke
- If keepalive is stale OR past expected_duration: poke (fallback)

## Files

- `{townRoot}/deacon/keepalive.json` - Written by Deacon
- Daemon already reads `{townRoot}/deacon/heartbeat.json` - similar pattern

## Deacon Behavior

1. Start of rounds: write keepalive with expected duration
2. End of rounds: write heartbeat (existing), clear/update keepalive
3. If rounds take longer than expected: Deacon gets one poke, squelches it

## Daemon Changes

Modify `pokeDeacon()` in daemon.go:
1. Check keepalive.json freshness and expected_duration
2. If within bounds: skip poke, log "Deacon active"
3. If past bounds: poke as fallback

## Worst Case

Deacon crashes mid-rounds without clearing keepalive:
- Daemon waits until expected_duration expires
- Then pokes, triggering respawn loop
- Max delay: expected_duration (configurable, default 10-15 min)

## Configuration

In pinned kernel bead:
```yaml
config:
  rounds_expected_duration_minutes: 10
```


Session ended: gt-gastown-nux


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 7: Quiet


Digest: mol-deacon-patrol

Patrol 7: routine, all healthy


Digest: mol-deacon-patrol

Patrol 11: Quiet


Polecats go off-task instead of working pinned bead

During swarm execution, polecats frequently stop working on their assigned task (pinned bead) and start doing other things like:
- Asking about other polecats
- Checking mail
- Monitoring swarm status
- Working on unrelated issues

Expected: Polecat receives task via gt sling, works on it until completion, signals done.
Actual: Polecat gets distracted and stops working on assigned task.

Root cause hypothesis: CLAUDE.md instructions don't strongly enforce 'work your hook' behavior. Need clearer polecat template that emphasizes single-task focus.


Integration test: agent waits for CI via gate

End-to-end test of the gate workflow.

## Test Scenario
1. Agent creates gate: bd gate create --await gh:run:123 --timeout 5m --notify beads/dave
2. Agent writes handoff and exits
3. Deacon patrol checks gate condition
4. (Mock) GitHub run completes
5. Deacon notifies waiter and closes gate
6. New agent session reads mail and resumes

## Test Requirements
- Mock GitHub API responses
- Test timeout path
- Test multiple waiters
- Verify mail notifications sent

## Moved from beads
Originally bd-rl5t. Tests Deacon patrol which is in gastown.


Merge: gt-svdsy

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


Digest: mol-deacon-patrol

Patrol 13: Quiet


Digest: mol-deacon-patrol

Patrol cycle 25: All healthy, no incidents


Hook reading in gt prime

Enhance gt prime to check and display hook contents.

## Current Behavior

gt prime loads context:
- Reads CLAUDE.md
- Injects beads workflow info
- Shows status

## New Behavior

After loading context, check hook:

```go
// In prime.go
func checkHook(agent string) {
    wispPath := ".beads-wisp/hook-" + agent + ".wisp.yaml"
    if wisp := readWisp(wispPath); wisp != nil {
        // Inject hook info into prime output
        showSlungWork(wisp)
    }
}
```

## Output Format

When hook has slung work:

```markdown
## Your Hook

You have work assigned:

**Bead:** gt-xxx
**Title:** Fix authentication bug
**Priority:** P1

Context from previous session:
> Continue where I left off...

**BEGIN WORK NOW.** Claim it with:
  bd update gt-xxx --status=in_progress
```

## Files Modified

- cmd/gt/prime.go - Add hook checking
- internal/wisp/hook.go - Hook reading utilities


Move disk 1: B → C

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


gt install command: Create workspace structure

Create Gas Town workspace structure.

## Command

```
gt install [path]
```

If path omitted, uses current directory.

## Created Structure

```
<path>/
├── config/
│   ├── town.json      # {"type": "town", "version": 1, ...}
│   └── rigs.json      # {"version": 1, "rigs": {}}
│
└── mayor/
    ├── CLAUDE.md      # Mayor role prompting (from template)
    ├── mail/
    │   └── inbox.jsonl  # Empty inbox
    └── state.json     # Initial mayor state
```

## Implementation

```go
func Install(path string, opts InstallOptions) error

type InstallOptions struct {
    TownName string  // defaults to directory name
    Force    bool    // overwrite existing
}
```

## Steps

1. Validate path (exists, writable)
2. Check not already a town (unless --force)
3. Create config/ directory
4. Write town.json with name and timestamp
5. Write empty rigs.json
6. Create mayor/ directory structure
7. Write CLAUDE.md from template
8. Create empty inbox.jsonl
9. Write initial state.json

## Error Cases

- Path does not exist: Create it (like mkdir -p)
- Already a town: Error unless --force
- Permission denied: Clear error message
- Inside existing town: Warn (nested towns not recommended)

## Templates

Mayor CLAUDE.md comes from embedded template (see gt-u1j.20).


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 7: All agents healthy


Merge: organic-mjwjck2f

branch: polecat/organic-mjwjck2f
target: main
source_issue: organic-mjwjck2f
rig: gastown
agent_bead: gt-gastown-polecat-organic


Digest: mol-deacon-patrol

Patrol 4: routine, all healthy


gt mq status: detailed MR view

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

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

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

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


Move disk 4: B → A

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


Digest: mol-deacon-patrol

Patrol 5: OK


Move disk 2: C → B

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


mol-polecat-arm: Add nudge_text variable definition

The mol-polecat-arm formula references `{{nudge_text}}` in the execute step but doesn't define it in the variables section.

## Current variables section

```yaml
variables:
  - name: polecat_name
    required: true
  - name: rig
    required: true
```

## Missing

```yaml
  - name: nudge_text
    required: false
    default: "How's progress? Need any help?"
    description: Text to send when nudging the polecat
```

## Usage in formula

```bash
tmux send-keys -t gt-{{rig}}-{{polecat_name}} "{{nudge_text}}" Enter
```

## Fix

Add nudge_text to the variables section with a sensible default.


gt crew at fails to detect existing crew session

## Summary
`gt crew at` started a new Claude session instead of attaching to an existing one for the same crew worker.

## Reproduction
1. Have a crew worker (joe) running in gastown/crew/joe (PID 27526 on tty s030)
2. Run `gt crew at` from the same directory (gastown/crew/joe)
3. Expected: Attach to existing session on s030
4. Actual: Started a brand new Claude session (PID 67618 on s026)

## Evidence
```
# Old joe still running:
PID 27526 on s030: /Users/stevey/gt/gastown/crew/joe (started 10:22AM)

# New joe spawned by 'gt crew at':
PID 67618 on s026: /Users/stevey/gt/gastown/crew/joe (started 10:39AM)
```

## Impact
- Duplicate crew workers cause confusion
- User expected to attach to existing session, not spawn a second one
- The original session was still functional (just stuck in feed display)

## Likely cause
`gt crew at` probably doesn't check for running Claude processes in the crew directory before spawning a new one. It should:
1. Check for existing tmux sessions for this crew worker
2. Check for running `claude` processes with cwd matching the crew directory
3. If found, attach to existing session instead of spawning new one


Session ended: gt-gastown-warboy


Deacon patrol molecules stored in wrong beads location

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


Digest: mol-deacon-patrol

Patrol cycle 1: all healthy, 3 rigs, 6 agents, no incidents


Move disk 5: C → A

Move disk 5 from peg C to peg A. (Move 368/1023)


Digest: mol-deacon-patrol

Patrol 5: quick pass


Merge: gt-ay1r

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


Move mol run semantics from bd into gt spawn

Currently gt spawn shells out to bd mol run for the pour+assign+pin combo. This blurs the architectural boundary between bd (data layer) and gt (orchestration layer).

## Current State
- bd mol run = bd pour + bd update --status=in_progress + bd pin --for me
- gt spawn calls: exec.Command("bd", "mol", "run", ...)

## Proposed Change
Move the combo logic into gt spawn directly:
1. gt spawn calls bd pour (create issues from template)
2. gt spawn calls bd update --status=in_progress (claim work)
3. gt spawn calls bd pin (set pinned flag)
4. gt spawn does session/tmux orchestration

This keeps bd as pure data operations and gt as the orchestration layer.

## Why
- Cleaner separation of concerns
- bd mol run feels like orchestration but it's in the data layer
- gt should own the "start a workflow" semantics

## Coordination
beads side will deprecate bd mol run once gt no longer depends on it.


Move disk 6: B → A

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


Digest: mol-deacon-patrol

Patrol 141: All agents healthy, 4 polecats working, no issues


Move disk 2: B → A

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


gt prime: Refinery context detection and output

Update gt prime to detect Refinery role:
- Detect from directory: refinery/rig/ = Refinery
- Show handoff bead reference
- Show merge queue status
- Show polecat branches with unmerged commits
- Show last actions summary


Test: Polecat lifecycle validation (auto-close)

Simple test task: Read this issue, print 'Lifecycle test passed', then close this issue with bd close. No code changes needed.


Move disk 1: C → A

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


Document BD_ACTOR format convention

Document the canonical BD_ACTOR format:
- Town level: mayor, deacon
- Rig level: {rig}/witness, {rig}/refinery
- Workers: {rig}/crew/{name}, {rig}/polecats/{name}

Currently only defined in lifecycle.go:807-829. Should be in docs and CLAUDE.md for agents to reference.

Also document the attribution model:
- GIT_AUTHOR_NAME = BD_ACTOR (agent identity, who did the work)
- GIT_AUTHOR_EMAIL = overseer email (who owns the work)
- created_by = BD_ACTOR (beads field)


Digest: mol-deacon-patrol

Patrol 149 complete


Create session name helper functions in internal/session

attached_args: Session name helper functions

Create helper functions for consistent session name construction.

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

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

import "fmt"

const Prefix = "gt-"

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

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


Merge: gt-3x0z.1

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


Merge: toast-mjtm1hg8

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


Digest: mol-deacon-patrol

Patrol 1: All checks passed, no incidents. Witness/Refinery healthy, 1 dog idle, no polecats.


Digest: mol-deacon-patrol

Patrol 67: Routine


Digest: mol-deacon-patrol

Patrol 9: All healthy


Move disk 2: C → B

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


Move disk 1: C → A

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


Agent monitoring and status inference

Agent monitoring with status inference from activity, like PGT.

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

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

## Activity Detection

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

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

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

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

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

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

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


Clean dead sessions

Clean dead sessions.

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

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

Preserve audit trail. Only clean sessions confirmed dead.


Digest: mol-deacon-patrol

Patrol 14: nominal


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 1: A → B

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


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

Patrol 9: quiet


Digest: mol-deacon-patrol

Patrol cycle 23: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol 12: All healthy


Pinned beads architecture implementation

Implement the pinned beads architecture from docs/pinned-beads-design.md

Phases:
1. Doctor checks for hook validation
2. Dashboard visibility (gt hooks, gt dashboard)
3. Protocol enforcement (self-pin, audit trail)
4. Documentation updates


Move disk 2: C → B

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


Move polecat pending tracking from Deacon to Witness

Problem: gt deacon pending handles polecat observation at the wrong level. Hierarchy should be Witness→polecats, Deacon→Witnesses.

Solution:
1. Add gt witness pending - shows pending polecats in this rig
2. Route POLECAT_STARTED mail to Witness (not just Deacon)
3. Deacon keeps backup role but does not directly manage polecats

Depends on gt-0yqqw (messaging infrastructure) for proper routing.


Move disk 4: A → C

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


Digest: mol-deacon-patrol

Patrol 12: all quiet


Day 2.3: Agent writes state on lifecycle events

Agents update their bead state using bd agent state command:
- On startup: bd agent state gt-<role> running
- On shutdown: bd agent state gt-<role> stopped
- On stuck: bd agent state gt-<role> stuck

State is self-reported, not inferred.

Implementation: Wire up agent lifecycle hooks (SessionStart, SessionEnd, health checks) to call bd agent state.

Parent: gt-d0jqp


gt mail inbox shows wrong identity when run from deacon directory

When running 'gt mail inbox' from ~/gt/deacon/, it shows 'Inbox: mayor/' instead of 'Inbox: deacon/'. The role detection works (deacon checks in correctly), but mail identity detection is broken.


Human escalation: notify overseer when self-heal fails

Lightweight escalation extracted from Deacon epic (gt-5af).

**Implementation**: Config in town.json or similar:
```yaml
escalation:
  contact: steve@example.com  # or slack webhook
  triggers:
    - daemon_cant_restart
    - session_missing_5min
```

**Trigger points**:
- Go daemon can't restart a session after N attempts
- Agent detects it's stuck and can't recover
- Witness can't reach polecat

**Mechanism**:
- Simple: `gt mail send --human` already exists
- Enhanced: email/slack via external script

**Weight**: Small config + one code path in daemon
**Value**: High for unattended operation - human gets notified instead of silent failure


Digest: mol-deacon-patrol

Patrol cycle 19: All 6 agents healthy


Refactor sling to hook plus handoff

Replace gt sling with gt hook (durability) and gt handoff bead (hook+restart)


Move disk 4: A → C

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 6: 9 sessions healthy


gt: Write town-level activity signal in PersistentPreRun

Extend gt's existing keepalive infrastructure to also write a town-level activity file.

Currently gt writes to <workspace>/.runtime/keepalive.json (per-rig).
Add a second write to ~/gt/daemon/activity.json (town-level).

The keepalive package already has TouchInWorkspace(). Add a new function
TouchTownActivity() that writes to the town daemon directory.

Call both in root.go's PersistentPreRun.


Digest: mol-deacon-patrol

Patrol 3: all healthy


Move disk 2: C → B

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


Digest: mol-deacon-patrol

P14: stable


Digest: mol-deacon-patrol

Patrol 46: All healthy


Move disk 4: C → B

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


mol-deacon-patrol


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

Patrol 2: All healthy, no actions


Digest: mol-deacon-patrol

Patrol 13: Quiet


Digest: mol-deacon-patrol

Patrol cycle 40: All healthy, 20 cycles complete - handoff per heuristic


Digest: mol-deacon-patrol

Patrol cycle 13: all healthy


Unify gt sling and gt spawn with --args support

## Summary

Complete the unification: `gt sling` becomes THE way to assign work. Remove top-level `gt spawn`.

## Current State (Partially Done)

- `gt sling` auto-spawns polecats when target is a rig
- `gt sling --args` stores args in bead (no-tmux mode, gt-vc3l4)
- `gt spawn` still exists with flags not yet in sling

## Remaining Work

### 1. Move spawn-only flags to sling

| Flag | Current | Action |
|------|---------|--------|
| `--naked` | spawn only | Move to sling |
| `--create` | spawn only | Move to sling |
| `--molecule` | spawn only | Move to sling |
| `--force` | spawn only | Move to sling |
| `--account` | spawn only | Move to sling |
| `--no-start` | spawn only | Evaluate if needed |

### 2. Remove top-level gt spawn

- Keep `gt spawn pending` as subcommand if still needed
- Remove `gt spawn` from root commands
- Update all docs and CLAUDE.md references

### 3. Unified UX Design

Target resolution (smart defaults):
```bash
gt sling gt-abc                    # Self (current agent)
gt sling gt-abc crew               # Crew worker in current rig
gt sling gt-abc gastown            # Auto-spawn polecat in rig
gt sling gt-abc gastown/Toast      # Specific polecat
gt sling gt-abc mayor              # Mayor
```

Key flags:
```bash
gt sling gt-abc --args "patch release"   # Natural language context
gt sling gt-abc --naked                  # No-tmux mode (manual start)
gt sling gt-abc --create                 # Create polecat if missing
gt sling gt-abc --molecule mol-review    # Use specific workflow
```

### 4. Update Witness/Refinery/Deacon

These agents currently use `gt spawn`. Update to use `gt sling`:
- Witness: spawning polecats for work
- Refinery: spawning merge workers
- Deacon: any spawn logic

## Acceptance Criteria

- [ ] All spawn flags available in sling
- [ ] `gt spawn` removed (or hidden/deprecated)
- [ ] Witness uses `gt sling <rig>` for polecat work
- [ ] Docs updated
- [ ] Both human and agent UX is clean


Digest: mol-deacon-patrol

Patrol 7: Routine


mol-sync-workspace: Add explicit gt prime / bd prime in assess-state


Digest: mol-deacon-patrol

Cycle 190: 10-cycle checkpoint, all agents healthy


Digest: mol-deacon-patrol

Patrol 3: Routine


Move disk 1: C → A

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


gt-gastown-polecat-bravo

gt-gastown-polecat-bravo

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


Digest: mol-deacon-patrol

Patrol 18: All healthy


Digest: mol-deacon-patrol

Patrol 208: All nominal


README: Add beads (bd) as prerequisite

CRITICAL: gt calls bd via exec.Command for sling, cook, gate, etc. but beads is not listed in Prerequisites. Users following Quick Start will fail.

Fix:
1. Add 'beads (bd)' to Prerequisites with install link
2. Move Prerequisites section BEFORE Quick Start
3. Add version requirements for each dep


Digest: mol-deacon-patrol

P18: stable


Merge: slit-mjw3n5iw

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


Digest: mol-deacon-patrol

Patrol 11: All healthy, dave now running


load-context

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

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


Digest: mol-deacon-patrol

Patrol 20: All healthy, cycling session


Merge: dementus-1767087772272

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


Digest: mol-deacon-patrol

Patrol 3: all healthy


Witness: auto-nuke polecats after merge

## Problem
Polecats linger after merge. Manual cleanup required.

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

```toml
[[step]]
id = "cleanup-merged-polecats"
title = "Remove polecats after merge"
description = """
1. Check inbox for MERGED messages from refinery: gt mail inbox
2. For each MERGED notification:
   - Extract polecat name from message
   - Verify branch is actually gone: git branch -r | grep polecat/<name>
   - Kill session if running: tmux kill-session -t gt-<rig>-<polecat>
   - Remove worktree: gt polecat remove <rig>/<polecat> --force
   - Delete the MERGED mail
3. Log cleanup in state.json
"""
depends_on = ["check-ready-branches"]
```

## Why This Works
- Witness agent receives MERGED signal from refinery (mail)
- Agent verifies before acting (checks branch really gone)
- Agent runs gt/tmux commands
- No daemon code

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


Move disk 1: C → A

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


Move disk 2: B → A

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


Merge: rictus-1767059698035

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


Digest: mol-deacon-patrol

Patrol 146 complete: All healthy


Default polecat names: Mad Max theme instead of AdjectiveNoun

Current default naming for new polecats uses AdjectiveNoun convention.
Since rigs already provide namespacing, we can use more thematic names.

Suggestion: Use Mad Max / Fury Road character and vehicle names as defaults.
Examples: Furiosa, Nux, Slit, Morsov, Toast, Rictus, Warboy, etc.

Could also include:
- War Rig parts: Guzzler, Tanker, Pursuit
- Citadel roles: Imperator, Blackthumb, Organic
- Wasteland terms: Chrome, Witness, Shiny

Implementation:
- Add name generator in internal/polecat/ or similar
- Use when --create flag is used without explicit name
- Cycle through pool to avoid duplicates within a rig


Digest: mol-deacon-patrol

P13: stable


Digest: mol-deacon-patrol

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


Move disk 8: A → C

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


Move disk 1: C → A

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


Step recovery: timeout and release

Implement recovery mechanism for stuck molecule steps.

## Problem
When a worker dies mid-step, the step stays in_progress forever.
Need timeout/release mechanism for nondeterministic idempotence.

## Solution
1. Track step start time (claimed_at timestamp)
2. Timeout: After 30 min in_progress, step returns to pending
3. Manual release: bd release <step-id>

## Implementation Options

### Option A: Beads-level timeout
- Add claimed_at field to issues
- bd ready excludes items in_progress < 30 min
- bd ready includes items in_progress > 30 min (auto-recovery)

### Option B: Daemon-level timeout
- Daemon watches in_progress items
- Moves back to pending after timeout

### Option C: Manual only (MVP)
- bd release <id> manually moves in_progress → pending
- Document recovery procedure
- Witness can automate for polecats

## Recommendation
Start with Option C (manual) for Christmas. Add Option A later.

## Acceptance
- [ ] bd release command works
- [ ] Stuck steps can be recovered
- [ ] Documented recovery procedure


Digest: mol-deacon-patrol

Patrol 14: All clear


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 19


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

Patrol 12: All healthy


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol complete: cleaned 2 orphaned processes, 3 stale locks, all agents healthy


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

Variables:
- gt-test123 - The source issue ID being worked on


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

Patrol 20: All healthy


Create mol-gastown-polecat derived molecule

Create the standard Gas Town polecat workflow molecule.

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

Includes: mol-engineer-in-box

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

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

Needs: submit
\`\`\`

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

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

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 5: Routine


Move disk 2: C → B

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


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

Patrol 8: All healthy


Digest: mol-deacon-patrol

Cycle 10


gt swarm: Not discovering tasks from epic dependents

gt swarm create/start shows '0 tasks loaded' even when epic has dependents.

Repro:
1. Create epic gt-hw6
2. Create tasks and add deps: bd dep add gt-xxx gt-hw6
3. gt swarm create gastown --epic gt-hw6 --worker Toast
4. Swarm shows 'Tasks: 0'

Expected: Swarm should discover tasks that depend on the epic.
Actual: Shows '(no tasks loaded)'


Digest: mol-deacon-patrol

Patrol cycle 6: All quiet.


Day 1.5: Create role beads from CLAUDE.md content

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

Each role bead contains priming instructions and default_molecule.

Parent: gt-d0jqp


Add NODE_OPTIONS crash logging to claude invocations

## Background

Investigation in bd-6df0 found that NODE_OPTIONS can enable Node.js crash reporting for Claude Code:

```bash
NODE_OPTIONS="--report-on-fatalerror --report-uncaught-exception --report-directory=$HOME/.claude/crash-reports"
```

## Proposal

Modify gt to set NODE_OPTIONS when spawning claude sessions. Key locations in gastown:

- `internal/cmd/up.go` - deacon, witness, crew, polecat spawning
- `internal/cmd/start.go` - refinery, crew spawning
- `internal/cmd/mayor.go` - mayor spawning
- `internal/cmd/handoff.go` - handoff respawning
- `internal/cmd/crew_helpers.go` - execClaude()
- `internal/daemon/lifecycle.go` - daemon-managed spawns

## Implementation

1. Create helper function to build NODE_OPTIONS string
2. Set env var before each claude invocation
3. Ensure ~/.claude/crash-reports/ directory exists
4. Optionally add `gt doctor` check to clean old reports

## Benefits

- Crash diagnostics without user config changes
- All gt-managed sessions automatically covered
- Reports available for debugging unexpected terminations


Digest: mol-deacon-patrol

Patrol 3: All clear


Move disk 2: A → C

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


Mail system: JSONL inbox, delivery, tmux injection

Refactor mail system to wrap bd mail commands.

## Status

Current implementation uses JSONL files directly. Now that Beads mail is available (gt-r01 closed), refactor to use bd mail as the backend.

## Implementation

Replace internal/mail/* with thin wrappers around bd CLI:

```go
// Send wraps: bd mail send <to> -s <subject> -m <body>
func (r *Router) Send(msg *Message) error

// List wraps: bd mail inbox --json
func (m *Mailbox) List() ([]*Message, error)

// Get wraps: bd mail read <id> --json
func (m *Mailbox) Get(id string) (*Message, error)

// MarkRead wraps: bd mail ack <id>
func (m *Mailbox) MarkRead(id string) error
```

## Address Translation

GGT addresses → Beads recipients:
- `mayor/` → `mayor`
- `<rig>/refinery` → `<rig>-refinery`
- `<rig>/<polecat>` → `<rig>-<polecat>`

## Tmux Notification

Keep the tmux injection for --notify flag. After bd mail send, optionally inject notification into tmux session.

## Migration

No migration needed - bd mail creates messages as beads issues with type=message. Old JSONL inboxes can be ignored or cleaned up.

## Dependencies

- gt-r01: CLOSED (Beads mail available)
- gt-u1j.4: Tmux wrapper (for notifications)


Digest: mol-deacon-patrol

Patrol 20: quiet, handoff threshold reached


Connection interface: Protocol for local/remote ops

Abstract interface for local vs remote (SSH) operations.

## Concept

Enable Gas Town to manage rigs on remote machines via SSH. The Connection interface abstracts whether operations happen locally or remotely.

## Interface

```go
type Connection interface {
    // Identification
    Name() string
    IsLocal() bool

    // File operations
    ReadFile(path string) ([]byte, error)
    WriteFile(path string, data []byte, perm os.FileMode) error
    MkdirAll(path string, perm os.FileMode) error
    Remove(path string) error
    Stat(path string) (os.FileInfo, error)
    Glob(pattern string) ([]string, error)

    // Command execution
    Exec(cmd string, args ...string) ([]byte, error)
    ExecDir(dir, cmd string, args ...string) ([]byte, error)

    // Tmux (for session management)
    TmuxNewSession(name, dir string) error
    TmuxKillSession(name string) error
    TmuxSendKeys(session, keys string) error
    TmuxCapturePane(session string, lines int) (string, error)
}
```

## Implementations

- LocalConnection (gt-f9x.8): Direct file/exec operations
- SSHConnection (future): Operations via SSH

## Usage

```go
func NewRigManager(conn Connection, ...) *RigManager

// Operations work the same regardless of connection type
rm.DiscoverRigs()  // uses conn.Glob, conn.ReadFile
```

## Design Notes

- Connection obtained from MachineRegistry (gt-f9x.9)
- Default is always local
- SSH connection requires machine config (host, key, user)


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 16: routine


Polecat Lifecycle Events: Refinery-Witness Coordination

## Problem

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

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

## Solution: Two-Event Lifecycle

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

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

## Village Sibling Watch

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

## Recovery

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


Digest: mol-deacon-patrol

Patrol 103: All agents healthy, no incidents


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.


Move disk 1: B → C

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


Move disk 1: B → C

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


Move disk 5: C → A

Move disk 5 from peg C to peg A. (Move 848/1023)


Digest: mol-deacon-patrol

P20: stable - handoff triggered


Digest: mol-deacon-patrol

Patrol 9: Routine


mol-sync-workspace: Add vars for build/test commands


Move disk 2: A → C

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


loop-or-exit

Decision: burn and loop if context low, exit for respawn if context high.


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.


Rename Engineer in Box to Shiny

Rename mol-engineer-in-box to mol-shiny (or just 'shiny').

Mad Max reference - the canonical 'right way to engineer'.
Update all references in docs and code.


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 16: Routine


Digest: mol-deacon-patrol

Patrol complete: all agents healthy


Merge: dementus-mjw46vz4

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


Move disk 7: A → B

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


Polecats should auto-cleanup after MR submission

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

## Desired Flow

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

## Implementation Options

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

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

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

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


Move disk 1: A → B

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Cycle 9


mol-outpost-assign: Intelligent work routing to outposts

The federation design shows outposts.yaml with a static policy section. Simple preference ordering is fine as config, but intelligent work routing should be a molecule.

Current static approach:
```yaml
policy:
  default_preference: [local, gce-burst, cloudrun-burst]
```

Cases requiring cognition:
- "This is a long-running research task, route to VM not CloudRun"
- "This touches sensitive code, keep local"
- "These 5 issues are related, batch them to same outpost"
- "CloudRun cost is high today, prefer local even if slower"

## Molecule: outpost-assign
Intelligent work-to-outpost routing.

## Step: classify-work
Analyze the issue/work item:
- Expected duration (quick fix vs multi-hour)
- Resource requirements
- Sensitivity/security tier
- Related work (same epic?)

## Step: check-capacity
Query outpost status:
- Current load on each
- Cost accrued today
- Health status

## Step: select-outpost
Choose optimal outpost based on:
- Work classification
- Capacity/cost
- Policy constraints
Needs: classify-work, check-capacity

## Step: emit-assignment
Record decision in beads for audit.
Needs: select-outpost

## Notes
- This molecule is invoked by Mayor/Witness when spawning
- Simple cases can short-circuit to static policy
- Full analysis only for ambiguous cases


Enhance Mayor CLAUDE.md with GGT milestone tracking

Update ~/ai/CLAUDE.md (Mayor startup context) with:

1. GGT Self-Hosting Milestone section
   - Track progress toward gt replacing town
   - Key blockers: gt-h5n (merge queue), gt-974 (daemon)
   - What "self-hosting" means (GGT working on itself)

2. Recent Architecture Decisions
   - Engineer = role, Refinery = place
   - Merge queue in Beads (not branch discovery)
   - Session restart protocol

3. Transition Plan
   - Current: use town commands (PGT)
   - Target: use gt commands (GGT)
   - Switch criteria: gt-b1g closed

Keep it concise - Mayor context should be quick to scan.


CRITICAL: ProcessMRFromQueue not implemented - Refinery merge logic stubbed

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


Digest: mol-deacon-patrol

Patrol complete: inbox empty, polecats healthy (furiosa/nux idle), witness/refinery running, no orphans


Move disk 1: A → B

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


Phase 1.4: Basic patrol runner in Deacon

Deacon CLAUDE.md and prime context for patrol execution.

## Deacon Context
- Update Deacon CLAUDE.md with patrol instructions
- On wake: check pinned bead for attachment
- If attached: resume molecule from current step
- Execute steps, close each when done
- On final step: burn molecule, go naked

## gt prime Enhancement
- Detect if agent has attached molecule
- Show molecule progress in prime output
- Include patrol-specific instructions

Depends: gt-rana.3


Check convoy completion

Check convoy completion status.

Convoys are coordination beads that track multiple issues across rigs. When all tracked issues close, the convoy auto-closes.

**Step 1: Find open convoys**
```bash
bd list --type=convoy --status=open
```

**Step 2: For each open convoy, check tracked issues**
```bash
bd show <convoy-id>
# Look for 'tracks' or 'dependencies' field listing tracked issues
```

**Step 3: If all tracked issues are closed, close the convoy**
```bash
# Check each tracked issue
for issue in tracked_issues:
    bd show <issue-id>
    # If status is open/in_progress, convoy stays open
    # If all are closed (completed, wontfix, etc.), convoy is complete

# Close convoy when all tracked issues are done
bd close <convoy-id> --reason "All tracked issues completed"
```

**Note**: Convoys support cross-prefix tracking (e.g., hq-* convoy can track gt-*, bd-* issues). Use full IDs when checking.


Digest: mol-deacon-patrol

Patrol 2: All healthy, no incidents


Glass Cockpit: See WTF is happening

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

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

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

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

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


gt-mayor

gt-mayor

role_type: mayor
rig: null
agent_state: stopped
hook_bead: null
role_bead: gt-mayor-role
cleanup_status: has_stash
active_mr: gt-z4lxc
notification_level: null


Move disk 2: A → C

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


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 494/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 1: A → B

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


Digest: mol-deacon-patrol

Patrol cycle 18: routine


Digest: mol-deacon-patrol

Patrol 6: Quick cycle, all quiet


Merge: gt-lnji

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


Digest: mol-deacon-patrol

Patrol 1: inbox clear, witness/refinery healthy, no orphans, no plugins


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 #14: Stable


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.


Direct test

Testing direct bd create


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 4: All healthy


test pin fix 2