Move disk 2: A → C

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


Move disk 2: B → A

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


Molecule Algebra: Work Composition DSL

Implement the molecule algebra - a declarative language for composing, transforming, and executing structured work. Enables mechanical composition without AI.

The Three Phases: Rig → Cook → Run

- **Rig**: Source-level composition (formula YAML with extends/compose)
- **Cook**: Instantiation (formula → proto → mol/wisp)
- **Run**: Execution (agents complete steps)

Two Composition Operators:
- **Rig** operates on formulas (source level)
- **Bond** operates on artifacts (protos, mols, wisps)

Key components:
- Formulas: YAML source with composition rules (.formula.yaml)
- Cook: Pre-expand macros/aspects to flat proto
- Phase verbs (pour, wisp)
- Bond: Artifact-level polymorphic composition
- Composition operators (sequence, parallel, branch, loop, gate)
- Advice operators (before, after, around - Lisp style)
- Expansion operators (macros like Rule of Five)
- Aspects (AOP cross-cutting concerns)

See docs/rig-cook-run.md for the lifecycle spec.
See docs/molecule-algebra.md for full algebra specification.
Example formulas in .beads/formulas/


Move disk 2: C → B

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


gt done --exit: Self-terminate polecat session after MR submission

## Problem

Polecats finish work, call `gt done`, and then sit idle at Claude prompt waiting for Witness to kill them. This wastes money (idle Claude sessions still cost).

## Solution

Add `--exit` flag to `gt done` that:
1. Submits MR to merge queue (existing behavior)
2. Sends POLECAT_DONE to Witness (existing behavior)
3. Exits the Claude session immediately (new)

```bash
gt done --exit  # Submit MR and exit session
```

## Implementation

In `internal/cmd/done.go`:
1. Add `--exit` flag
2. After successful MR submission and witness notification:
   - Print final status
   - Call `os.Exit(0)` OR run `/exit` command

## Notes

- Witness still receives POLECAT_DONE and handles cleanup (nuke worktree) async
- No waiting = no idle sessions = no wasted money
- Session exit is safe because all work is pushed and MR submitted before exit


Digest: mol-deacon-patrol

Patrol 1 complete. All agents healthy. No callbacks, convoys, spawns, gates, orphans. 3 rigs monitored.


Test Patrol Parent

Test parent for Christmas Ornament pattern


Digest: mol-deacon-patrol

Patrol 9: All agents healthy, 1 orphan process cleaned, no mail


CLI: names commands for polecat naming pool

Polecat naming pool for auto-generated names.

## Commands

### gt names generate
```
gt names generate [--count N]
```
Generate N names from pool.

### gt names add
```
gt names add <name>...
```
Add custom names to pool.

### gt names list
```
gt names list
```
Show available and used names.

### gt names reset
```
gt names reset [--keep-used]
```
Reset pool to defaults.

## Config File
<rig>/town/naming.json:
```json
{
  "enabled": true,
  "auto_refill": true,
  "refill_threshold": 5,
  "pool": {
    "available": ["Toast", "Nux", "Capable", ...],
    "used": ["Alice", "Bob"]
  }
}
```

## Default Pool
Mad Max themed: Toast, Nux, Capable, Furiosa, Immortan, etc.

## Integration
gt polecat add calls naming pool if no name given:
```go
if name == "" {
    name, err = naming.Generate(rigPath)
}
```

## New Package
internal/naming/
├── pool.go     # Pool management
└── defaults.go # Default name lists

## Acceptance Criteria
- [ ] Auto-generate names on polecat add
- [ ] Track used vs available
- [ ] Auto-refill when low
- [ ] Custom names addable


Infrastructure formulas for dog tasks

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


Digest: mol-deacon-patrol

Cycle 6: quiet


Digest: mol-deacon-patrol

Patrol #9


Digest: mol-deacon-patrol

Patrol 12: all healthy


End-to-end swarm integration test

Full integration test for swarm lifecycle.

Test scenario:
1. Create a small epic with 3-4 issues and dependencies
2. Run bd swarm validate - should pass
3. Run gt swarm create with the epic
4. Verify swarm molecule created with mol_type=swarm
5. Run gt swarm status - verify ready front
6. Simulate issue completion (bd close)
7. Verify ready front advances
8. Complete all issues
9. Verify swarm auto-closes

Can be manual test documented in test file, or automated.

Dependencies: gt-kc7yj.2 (Witness integration), gt-kc7yj.3 (completion detection)


Digest: mol-deacon-patrol

Patrol 11: All healthy.


Design: Collapse mail into beads

## Proposal

Replace the separate mail system (JSONL inboxes) with beads issues using a naming convention.

## Rationale

If all state should be in beads (work items, swarm state, dependencies), why have a separate system for messages? Mail is just:
- Handoffs (agent → self)
- Commands (Mayor → Refinery)
- Escalations (Witness → Mayor)

These can all be beads issues with a special prefix.

## Design

### Convention
- Messages use `@-` prefix: `@-witness-1734012345`
- Assignee = recipient
- Status: open = unread, closed = read/acknowledged
- Priority 0 = urgent

### Commands (thin wrappers)
```bash
gt mail send witness -s "Subject" -m "Body"
  → bd create --prefix=@ --title="Subject" --assignee=witness --description="Body"

gt mail inbox
  → bd list --prefix=@ --assignee=$(gt whoami) --status=open

gt mail read @-abc
  → bd show @-abc && bd close @-abc
```

### Notification
Daemon watches for new `@-` issues and pokes relevant sessions.
Or: agents poll on heartbeat (simpler).

## What We Remove
- `mail/inbox.jsonl` files
- Mail JSONL read/write code
- Separate delivery mechanism

## What We Keep
- `gt mail` CLI (as wrapper)
- Handoff semantics
- Notification (via daemon or polling)

## Benefits
- One system, one sync, one query interface
- All communication in git history
- Simpler architecture

## Risks
- Beads prefix filtering must be efficient
- Namespace collision with user prefixes
- Performance for high-frequency messages (probably fine for handoffs)

## Decision Point
Do we need first-class mail support in beads (`bd mail` commands) or is convention sufficient?


burn-or-loop

Squash wisp and decide: loop or cycle session.

If context low: spawn new wisp and loop
If context high: handoff and request cycle

Needs: generate-summary


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.


Merge: toast-1767146237529

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


Digest: mol-deacon-patrol

Patrol 96: All healthy


Digest: mol-deacon-patrol

Patrol 20: All healthy - handoff threshold reached


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

Patrol 4: All healthy


Clean up deprecated gt mol command examples in molecule.go

## Task

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

## Deprecated References Found

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

## Location

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

## Context

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

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

## Fix

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


Digest: mol-deacon-patrol

Patrol 117: All healthy


Formula schema: Define formula.toml structure

Define the formula file format in .beads/formulas/:
- formula name and description
- input parameters (pr, branch, files)
- legs array with name, focus, output
- synthesis config
- dependencies between legs

Reference: gt-ubqeg.1 epic description for schema ideas.
Create example formula: code-review.formula.toml


mol-deacon-patrol


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


Merge fix/spawn-beads-path branch to main

Branch has gt nudge command; main has notification deduplication. Both valuable.

Key insight: Only ~10 commits diverged each way in mayor/rig.
- Branch: 9509afa feat(nudge): Add gt nudge command (MISSING from main)
- Main: d2fccd5 slot-based notification deduplication (KEEP)

Merge plan:
1. git merge fix/spawn-beads-path --no-ff
2. Keep nudge.go from branch
3. Keep notification.go from main
4. Merge tmux.go (both NudgeSession AND SendKeysReplace)
5. go build && go test
6. Deploy to ~/.local/bin/gt


Digest: mol-deacon-patrol

Patrol 2: All healthy. 3 rigs, 6 agents. No incidents.


Preflight molecule: verify baseline health before work

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

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

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

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

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

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


Move disk 1: C → A

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


Recover stale polecat work: 4 branches with unpushed commits

During observation of polecat workflow, found 4 polecats with unpushed work:

## Branches Pushed (preserved)
- polecat/capable: 3 commits (molecule catalog, doctor orphan detection, gt done)
- polecat/dementus: 4 commits (Witness MVP, handoff fixes)
- polecat/furiosa: 2 commits (bulk polecat removal, spawn handoff)
- polecat/rictus: 1 commit (molecule docs)

## Action Required
1. Review each branch for merge-worthiness
2. Either:
   a. Create PRs for valuable work
   b. OR discard if superseded
3. After decision, clean up polecats properly

## Root Cause
Polecats were not cleaned up after previous work sessions. This is exactly why we need:
- gt-u1k: gt shutdown should fully cleanup polecats
- gt-8v8: Refuse to lose uncommitted work
- gt-9nf: Always create fresh polecats


Digest: mol-deacon-patrol

Patrol 5: 3 polecats working


Beads witness sends HEALTH_OK to mayor instead of deacon

The beads/witness is responding to deacon health checks by sending to 'mayor/deacon' or 'mayor/' instead of 'deacon/'.

Current behavior:
gt mail send mayor/deacon -s "HEALTH_OK" ...

Expected behavior:
gt mail send deacon/ -s "HEALTH_OK" ...

The gastown witness was fixed and now correctly sends to deacon/. The beads witness needs the same fix.


Digest: mol-deacon-patrol

Patrol 82: 3 rigs healthy, 6 agents pinged, no incidents


Digest: mol-deacon-patrol

Patrol 1: All healthy - Mayor OK, 2 witnesses OK, 2 refineries OK, 1 polecat active (furiosa). No lifecycle requests or orphans.


Digest: mol-deacon-patrol

Patrol 18: all healthy


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 137: All healthy


gt-witness-gastown

gt-witness-gastown

role_type: witness
rig: gastown
agent_state: running
hook_bead: null
role_bead: gt-witness-role
cleanup_status: null


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 12


CRITICAL: gt doctor orphan-processes kills active crew sessions

## Problem

The deacon's patrol runs `gt doctor --fix` which includes an orphan-processes check. This check is incorrectly identifying ACTIVE crew sessions as orphaned and killing them.

## Impact

- Crew workers are being killed mid-session
- Work is lost
- The deacon is currently disabled until this is fixed

## Root Cause

The orphan-processes detection logic in `internal/doctor/` doesn't properly identify crew workers. It likely:
1. Doesn't recognize the `gt-<rig>-<name>` session pattern for crew
2. Or misidentifies the Claude process as orphaned when it has a valid tmux parent

## Workaround

The patrol formula was updated to instruct deacon not to run `--fix` if orphan-processes reports any PIDs. But this workaround failed - the deacon still killed crew.

## Fix Required

1. Update `internal/doctor/identity_check.go` or `branch_check.go` to properly detect crew sessions
2. Add crew session patterns to the valid session detection
3. Add test coverage for crew worker scenarios

## Files

- internal/doctor/identity_check.go
- internal/doctor/branch_check.go
- internal/cmd/doctor.go

## Related

- Commit 3452b041 attempted to fix via formula instructions but failed
- The digest hq-yedg claimed to file gt-vj5zc but never did


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:
- {{issue}} - The source issue ID being worked on


Move disk 3: C → A

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


Digest: mol-deacon-patrol

Patrol 18: all healthy, handled 1 handoff msg


Digest: mol-deacon-patrol

Patrol #12: Stable


Digest: mol-deacon-patrol

Patrol 12: All healthy


Digest: mol-deacon-patrol

Patrol cycle 6: All healthy


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

Work on gt-role-template: Refine witness/CLAUDE.md role template. Add clearer heartbeat protocol, mail checking procedure, nudge decision criteria, escalation thresholds. Run 'bd show gt-role-template' for details.


Detect cleanup needs

**DETECT ONLY** - Check if cleanup is needed and dispatch to dog.

**Step 1: Preview cleanup needs**
```bash
gt doctor -v
# Check output for issues that need cleaning
```

**Step 2: If cleanup needed, dispatch to dog**
```bash
# Sling session-gc formula to an idle dog
gt sling mol-session-gc deacon/dogs --var mode=conservative
```

**Important:** Do NOT run `gt doctor --fix` inline. Dogs handle cleanup.
The Deacon stays lightweight - detection only.

**Step 3: If nothing to clean**
Skip dispatch - system is healthy.

**Cleanup types (for reference):**
- orphan-sessions: Dead tmux sessions
- orphan-processes: Orphaned Claude processes
- wisp-gc: Old wisps past retention

**Exit criteria:** Session GC dispatched to dog (if needed).


Move disk 3: A → B

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


ZFC #4: Replace daemon identity parsing with agent self-registration

**ZFC Violation:** internal/daemon/lifecycle.go:209-309

The daemon has embedded switch statements that parse agent identity strings to determine:
- Session names
- Working directories
- Which agents need pre-sync
- Restart commands

**Current anti-pattern:**
```go
if strings.HasSuffix(identity, "-refinery") {
    needsPreSync = true
    workDir = filepath.Join(...)
}
```

**ZFC-compliant solution:**
Agent types self-register via role beads:
- Role bead contains: working_dir, session_name_pattern, needs_sync, restart_command
- Daemon reads role bead to get lifecycle config
- No identity string parsing in Go

**Depends on:** Day 1.5 (role beads exist)

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


Digest: mol-deacon-patrol

Patrol cycle 17: All healthy


Define meta-formula YAML schema

Define the YAML schema for meta-formulas that generate multiple formulas.

## Proposed Schema

    type: meta-formula
    name: multi-lang-shiny
    generates:
      for-each:
        var: lang
        values: [go, python, typescript]
      formula:
        name: "shiny-{lang}"
        extends: base-shiny
        vars:
          language: "{lang}"

## Key Decisions

- Use "generates" key to distinguish from regular formulas
- for-each at generation level (not runtime)
- Output is N formula files or in-memory formulas

## Deliverables

1. Add MetaFormula type to types.go
2. Add ForEachGenerate struct
3. Document schema in comments


Remove all hardcoded gastown dependencies from gt codebase

The Go codebase should not have hardcoded dependencies on gastown (the rig name).

Found in prime.go outputDeaconPatrolContext() - FIXED in this session.

Other potential issues to audit:
- Check all patrol context functions (Witness, Refinery) for similar patterns
- Ensure rig-specific paths are derived from context, not hardcoded
- Test with a different rig name to verify

The principle: Gas Town should work with any rig name, not just gastown.


Digest: mol-deacon-patrol

Patrol 19: quiet


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 20: all healthy


Deacon patrol wisps should use town beads, not gastown rig beads

## Problem

The deacon is a town-level role but stores patrol wisps in gastown/mayor/rig/.beads/ (see internal/cmd/prime.go:691). This fails for users who don't have the gastown rig installed.

## Correct Architecture

Deacon -> ~/gt/.beads-wisp/ (town-level, no rig dependency)

Town-level ephemeral work (deacon patrols) should use town wisp storage, just like rig-level ephemeral work (witness/refinery patrols) uses rig wisp storage.

## Implementation Tasks

### 1. Town Setup (gt install / gt town init)

- Create ~/gt/.beads-wisp/ directory during town initialization
- Initialize as git repo (for local commits, not synced)
- Add config.yaml with wisp: true
- Ensure .beads-wisp/ is gitignored at town level

Files:
- internal/cmd/install.go (or equivalent town init)
- internal/town/manager.go (if exists)

### 2. Rig Setup (gt rig init)

Already creates <rig>/.beads-wisp/ - verify this is working:
- internal/rig/manager.go:375 (beadsDir := filepath.Join(rigPath, ".beads-wisp"))
- internal/rig/manager.go:394 (ensureGitignoreEntry)

### 3. Deacon Code Fixes

Update deacon to use town wisp storage:
- internal/cmd/prime.go:691 - change rigBeadsDir to townWispDir
- internal/cmd/sling.go - route deacon wisps to town level
- internal/daemon/daemon.go - any deacon-specific wisp handling

### 4. gt doctor Checks

Add/update doctor checks for wisp directories:
- internal/doctor/wisp_check.go - already checks rig wisps
- Add TownWispCheck to verify ~/gt/.beads-wisp/ exists
- Add TownWispGitCheck to verify it is a valid git repo
- Update existing checks to handle both town and rig levels

Files:
- internal/doctor/wisp_check.go (extend for town level)
- internal/doctor/checks.go (register new checks)

### 5. Documentation

- docs/beads-data-plane.md - already updated with three-tier architecture
- Verify wisp-architecture.md reflects town-level wisps

## Testing

1. Fresh gt install should create ~/gt/.beads-wisp/
2. gt doctor should pass with no rig installed
3. Deacon patrol should work without gastown rig
4. gt sling patrol deacon/ --wisp should route to town wisps


Digest: mol-deacon-patrol

Patrol 5: routine, all healthy


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


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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 1: All 6 agents healthy, inbox clean, no incidents


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


Merge: nux-mjxn8p5t

branch: polecat/nux-mjxn8p5t
target: main
source_issue: nux-mjxn8p5t
rig: gastown
agent_bead: gt-gastown-polecat-nux
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Move disk 3: A → B

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


Fix potential race conditions in state file operations

Non-atomic state file operations could cause data loss:

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

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

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

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

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


Code Review Convoy formula (first formula implementation)

## First Formula: Code Review Convoy

Implement the code review formula as proof of concept for formula molecules.

### Input
- PR number, branch, or file list

### Legs (parallel polecats)
| Leg | Focus | Output |
|-----|-------|--------|
| correctness | Logic errors, edge cases, off-by-ones | findings.md |
| performance | Bottlenecks, O(n²), allocations | findings.md |
| security | Injection, auth, data exposure | findings.md |
| elegance | Design clarity, abstractions | findings.md |
| resilience | Error handling, retries, timeouts | findings.md |
| style | Conventions, naming, formatting | findings.md |
| smells | Anti-patterns, god objects, coupling | findings.md |

### Synthesis
- Read all leg findings
- Deduplicate overlapping issues
- Prioritize by severity
- Produce unified review with sections

### Command
```bash
gt formula run code-review --pr=123
# Creates convoy hq-cv-xxx
# Spawns 7 polecats + 1 synthesis
# Lands with review-summary.md
```

### Implementation Steps
1. Define formula schema in beads
2. gt formula run command
3. Leg prompt templates
4. Output collection mechanism
5. Synthesis polecat spawning
6. Result attachment to convoy bead


Move disk 1: C → A

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


mol-deacon-patrol


Merge: gt-3x1.4

branch: polecat/Nux
target: main
source_issue: gt-3x1.4
rig: gastown


Persist patrol state

Update handoff bead with new states.

Persist state to the witness handoff bead:
- Updated worker statuses from all arms
- Current nudge counts per worker
- Nudge timestamps
- Actions taken this cycle
- Pending items for next cycle

```bash
bd update <handoff-bead-id> --description="<serialized state>"
```

This state survives wisp burns and session cycles.


Merge: rictus-1767081110235

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


Move disk 1: C → A

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


Move disk 3: C → A

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


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

Patrol 17


gt sling reports hook occupied but bd hook shows empty

gt sling thinks a hook is occupied when bd hook shows it empty. Example: bd hook --agent beads/crew/dave shows (empty), but gt sling bd-hobo beads/crew/dave says 'hook already occupied by bd-ul59'. They should use the same source of truth (beads database pinned field).


Move disk 1: C → A

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 7: healthy


Move disk 4: A → C

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


LocalOutpost: Refactor current polecat spawning

## Overview

Refactor current local polecat spawning to implement the Outpost interface.

## Current State

Polecat spawning is ad-hoc. This task wraps it in LocalOutpost.

## Implementation

```go
type LocalOutpost struct {
    name       string
    maxWorkers int
    tmux       *Tmux
    workers    map[string]*LocalWorker
}

func NewLocalOutpost(config OutpostConfig) *LocalOutpost

func (o *LocalOutpost) Type() OutpostType { return OutpostLocal }

func (o *LocalOutpost) Spawn(issue string, cfg WorkerConfig) (Worker, error) {
    // Create tmux session
    // Start claude in pane
    // Return LocalWorker
}
```

## LocalWorker

```go
type LocalWorker struct {
    id      string
    session string  // tmux session name
    issue   string
    status  WorkerStatus
}

func (w *LocalWorker) Attach() error {
    // tmux attach-session
}
```

## Notes

- This should be a refactor, not new functionality
- Existing polecat code becomes LocalOutpost internals
- Tests should pass before and after

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


Digest: mol-deacon-patrol

Patrol cycle 15: all healthy


Digest: mol-deacon-patrol

Patrol cycle 6: routine, healthy


Test Patrol Parent

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

Original description:
Test parent for Christmas Ornament pattern


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


Move disk 2: C → B

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


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol cycle 15: All healthy


Day 5.0: gt status shows pinned role beads and slots

Enhance gt status to display:
- All pinned role beads (mayor, witness, refinery, polecats)
- Their current hook slot contents (what molecule/bead is attached)
- Agent state if available

This gives a single-command view of who's working on what across the town.

Example output:
```
gt status

Town: gastown
Daemon: running (pid 1234)

Agents:
  mayor/           gt-liftoff (pinned)     idle
  witness/gastown  gt-wisp-abc (patrol)    running
  refinery/gastown (empty)                 idle
  polecat/nux      gt-xyz (in_progress)    working
  polecat/rictus   (empty)                 idle
```


Digest: mol-deacon-patrol

Patrol complete: routine, town stable


gt daemon: Background service management

## Summary

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

## Architecture

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

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

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

## Commands

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

## Daemon Loop

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

## Lifecycle Request Handling

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

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

## Poke Protocol

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

## Lifecycle Hierarchy

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

## Related Issues

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


Digest: mol-deacon-patrol

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


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol cycle 26: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol #1: All witnesses/refineries running (beads, gastown, wyvern). 1 dog idle. No convoys, no gates, no pending spawns. Clean cycle.


Review: Deacon town-level wisp storage (gt-ci84)

Polecat slit implemented town-level wisp storage for deacon patrol. Review the changes to ensure deacon wisps are correctly stored in ~/gt/.beads-wisp/ instead of gastown rig beads.


Digest: mol-deacon-patrol

Patrol 158 complete


Digest: mol-deacon-patrol

Patrol 79: Routine


mol-deacon-patrol


Move disk 2: B → A

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


Design Deacon molecule health-check step

**Context:** After removing Go heuristics, Deacon molecule needs the logic.

**New molecule step: health-scan**

Claude executes:
1. Check Witness heartbeat: gt witness status <rig>
2. Check Refinery heartbeat: gt refinery status <rig>
3. For each, assess: responsive? stuck? needs restart?
4. If unresponsive for N cycles, send escalation mail

**Key difference from Go approach:**
- Claude makes the judgment call, not hardcoded thresholds
- Claude can read context (what was the agent working on?)
- Claude can ask questions or check additional signals
- Thresholds come from molecule config, not Go constants

**Deliverables:**
- Update mol-deacon-patrol health-scan step
- Add configurable thresholds as molecule variables
- Test with simulated stuck agents


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.


Update all documentation to remove hook references

14 docs reference hooks:
- docs/architecture.md
- docs/beads-data-plane.md
- docs/molecular-chemistry.md
- docs/molecules.md
- docs/pinned-beads-design.md
- docs/polecat-lifecycle.md
- docs/polecat-wisp-architecture.md
- docs/propulsion-principle.md
- docs/session-lifecycle.md
- docs/sling-design.md
- docs/vision.md
- docs/wisp-architecture.md
- docs/witness-patrol-design.md
- ~/gt/CLAUDE.md

Update all to reflect pinned beads as the sole propulsion mechanism.


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol OK: 0 mail, all agents healthy, 3 polecats working


Move disk 2: C → B

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


Move disk 1: A → B

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


Move disk 1: A → B

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 7


Merge: gt-lynar

branch: polecat/furiosa-mjxeatgb
target: main
source_issue: gt-lynar
rig: gastown
agent_bead: gt-gastown-polecat-furiosa


CI integration tests for install/setup flow

Add automated tests that validate the complete setup flow catches regressions like #19 (wrong prefix).

## Scope
- Fresh gt install validation
- Rig setup validation
- Beads initialization and routing
- Basic polecat lifecycle

## Non-goals (for now)
- Full Claude Code integration tests (mock or skip)
- Performance testing
- Multi-rig scenarios

## Success criteria
- Tests run on PRs touching install/rig/beads code
- Catch prefix mismatches, redirect errors, route config issues
- < 60s runtime to not slow CI

GitHub: #20


Digest: mol-deacon-patrol

Patrol 1: All healthy, no messages, no orphans


Digest: mol-deacon-patrol

Patrol 3: All agents healthy, no messages


Move disk 2: C → B

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


Move disk 1: A → B

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


Move disk 1: A → B

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


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

Patrol 6: All healthy


gt convoy status: Show assignee and actual status for tracked issues

Currently convoy status shows all open issues as ○ with no distinction:

```
○ gt-27bzi: Add gt mail announces command [task]
○ gt-pn2fq: Add isAnnounceAddress() helpers [task]
○ gt-q73h3: Implement sendToAnnounce() [task]
```

But these issues have different statuses and assignees:
- gt-pn2fq: closed (immortan) - should show ✓
- gt-q73h3: hooked (bullet) - should show 🔨 or similar
- gt-27bzi: in_progress (toecutter) - should show ▶

## Proposed display

```
✓ gt-pn2fq: Add isAnnounceAddress() helpers [immortan]
▶ gt-q73h3: Implement sendToAnnounce() [bullet]
▶ gt-27bzi: Add gt mail announces command [toecutter]
```

Show actual status symbols and assignee in brackets.


Implement gt convoy add command

Add the 'add' subcommand to convoy for adding issues to existing convoys.

SYNTAX:
gt convoy add <convoy-id> <issue-id> [issue-id...]

BEHAVIOR:
1. Validate convoy exists
2. Add 'tracks' dependency for each issue
3. If convoy is closed, reopen it automatically
4. Print confirmation

IMPLEMENTATION:
File: internal/cmd/convoy.go
Add: convoyAddCmd as subcommand

Example:
gt convoy add hq-cv-abc gt-new-issue
# -> Added gt-new-issue to convoy hq-cv-abc

gt convoy add hq-cv-abc gt-followup  # convoy was closed
# -> Reopened convoy hq-cv-abc
# -> Added gt-followup to convoy hq-cv-abc


Burn and respawn or loop

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

Decision point at end of patrol cycle:

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

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

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

This enables infinite patrol duration via context-aware respawning.


Digest: mol-deacon-patrol

Quick patrol: no messages, all healthy


Merge: dag-mjtm8k85

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


Move disk 3: C → A

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


Digest: mol-deacon-patrol

Patrol 116: All healthy


Implement aspect merging across formula chain

Implement merging of aspects when formulas extend each other.

## Current State

extends: already works for steps and vars.
Aspects need similar merge behavior.

## Implementation

1. In Resolve(), collect aspects from entire extends chain
2. Merge lists: parent aspects first, then child
3. Support exclude-aspects field to remove inherited aspects
4. Dedupe by aspect name (child wins on conflict)

## Files

- internal/formula/parser.go: Resolve()
- internal/formula/types.go: add ExcludeAspects field

## Tests

1. Child inherits parent aspects
2. Child adds additional aspects
3. Child excludes parent aspect
4. Three-level chain merges correctly


Rollback support: gt mq revert for problematic merges

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

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

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

Track revert in MR metadata for audit trail.

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


Merge: slit-mjxem84i

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


Bubbletea TUI dashboard

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


Digest: mol-deacon-patrol

Patrol complete


Move disk 2: A → C

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol cycle 5: routine, healthy


Add migration path for existing rigs

Existing rigs have refinery as clone. Need migration path.

## Options
1. Manual: User runs 'gt rig migrate' or similar
2. Automatic: Detect clone, convert to worktree on next start
3. Deprecation: Old rigs work but warn, new rigs use worktree

## Considerations
- Don't break existing setups
- Clear upgrade path
- Handle in-flight MRs during migration


gt spawn: Enter key needs debounce delay after paste

## Problem

When spawning polecats via `gt spawn`, instructions are pasted into tmux but workers often sit idle at prompt because the Enter key arrives before the paste is fully processed.

## Observed Behavior

- Instructions pasted via tmux send-keys
- Enter key sent immediately after
- Worker session shows prompt with no input (paste not submitted)
- Requires manual intervention to nudge workers

## Expected Behavior

- Paste completes fully
- Enter key submits the pasted instructions
- Worker begins executing immediately

## Root Cause

Likely a race condition between paste buffer processing and keypress handling. Need either:
1. Debounce delay before sending Enter
2. Longer delay (Tmax) to ensure paste completes
3. Alternative submission mechanism

## Impact

- Swarm of 10 workers had multiple stalls at startup
- Required manual tmux send-keys to unstick them
- Defeats purpose of automated spawning

## References

- Observed during Mad Max swarm (Dec 18, 2025)
- Affects gt spawn command in internal/cmd/spawn.go


Merge: toast-1767074299802

attached_args: Code review this merge request

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


Digest: mol-deacon-patrol

Patrol 7: all clear


Move disk 1: C → A

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


Merge: furiosa-mjtnoooj

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


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

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

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

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

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


Merge: capable-1767140263101

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


Add mutex to swarm.Manager for thread safety

attached_args: Add swarm.Manager mutex for thread safety

Fix potential race condition in swarm manager's map access.

## Files to modify
- internal/swarm/manager.go
- internal/swarm/manager_test.go (add concurrency test)

## Problem
The swarms map[string]*Swarm is accessed without synchronization:
```go
type Manager struct {
    swarms map[string]*Swarm  // No mutex protection
}
```

Multiple goroutines could call Create(), GetSwarm(), etc. simultaneously.

## Implementation
```go
type Manager struct {
    mu     sync.RWMutex
    swarms map[string]*Swarm
}

func (m *Manager) GetSwarm(id string) *Swarm {
    m.mu.RLock()
    defer m.mu.RUnlock()
    return m.swarms[id]
}
```

## Acceptance criteria
- [ ] sync.RWMutex added to Manager struct
- [ ] All map accesses protected by mutex
- [ ] RLock for reads, Lock for writes
- [ ] Concurrency test added
- [ ] go test -race ./internal/swarm/... passes


Move disk 1: A → B

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


Merge: gt-rixa

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


Move disk 3: B → C

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


Move disk 1: C → A

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


Move disk 3: B → C

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


Digest: mol-deacon-patrol

Patrol 63: Routine, all healthy


Witness for gastown - monitors polecat health and progress.

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

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


Delete .runtime/*.json observable state

Remove JSON files that tracked observable state (now in beads/activity stream).

Files to delete or minimize:
- .runtime/refinery.json - remove stats (keep minimal process state if needed)
- .runtime/witness.json - remove stats
- .runtime/swarms.json - delete entirely (gt-kc7yj moves to beads)

Prerequisite: All events flowing through activity stream, swarms in beads.

This is the cleanup step after observability is working.


Digest: mol-deacon-patrol

Patrol 2: 3 polecats working, all healthy


Move disk 1: C → A

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 10: routine


Digest: mol-deacon-patrol

Patrol 4: healthy


Digest: mol-deacon-patrol

Patrol cycle 8: All quiet.


gt-gastown-polecat-immortan

gt-gastown-polecat-immortan

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: gt-pn2fq
role_bead: gt-polecat-role
cleanup_status: null
active_mr: gt-3rvb5
notification_level: null


Digest: mol-deacon-patrol

Patrol 16: healthy


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 64: Routine


Digest: mol-deacon-patrol

Patrol 18


Digest: mol-deacon-patrol

Patrol 15: All clear


Digest: mol-deacon-patrol

Patrol 20: all clear, handoff due


Digest: mol-deacon-patrol

Patrol 2 complete: all systems healthy, no incidents


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 8: All healthy


Move disk 5: B → C

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


Digest: mol-deacon-patrol

Patrol 17: all clear


Digest: mol-deacon-patrol

Patrol 20: 3 rigs healthy


Refinery not processing merge-requests - stale MRs accumulating

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

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

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


Digest: mol-deacon-patrol

Patrol 3: Quiet, all healthy


Move disk 5: C → A

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


Move disk 3: C → A

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


Move disk 2: C → B

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


Move disk 1: C → A

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


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 20: All healthy, 17 sessions


Digest: mol-deacon-patrol

Cycle 13


Digest: mol-deacon-patrol

Patrol 14: healthy


mol-deacon-patrol


Auto-handoff: self-cycling with guaranteed work pickup

## Summary

A mechanism for agents to self-cycle: send handoff mail, request Deacon to kill the process, and automatically restart to pick up the work.

## Use Case

User says: `auto-handoff: gt-bug3`

The agent:
1. Sends handoff mail documenting current state
2. Requests Deacon to terminate the session
3. Deacon restarts the agent in background
4. New session picks up the handoff and continues working

When the user returns to terminal, the old session is gone but work continues in background. User can reattach.

## Key Requirements

- **Guaranteed pickup**: Something in the hook and/or handoff must ensure the new session picks up the work (not just a passive "check inbox")
- **Background execution**: Work continues without user presence
- **Reattachability**: User can reconnect to see progress

## Design Questions

1. Can molecules help coordinate this? (e.g., molecule binds the handoff + auto-restart)
2. What hook handles the pickup guarantee?
3. How does Deacon know to restart vs just kill?
4. How does user reattach to a background agent?

## Related

- Molecules system
- Deacon lifecycle management
- Handoff hooks


Digest: mol-deacon-patrol

Patrol 11: All healthy


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 10: Midpoint, all healthy


Digest: mol-refinery-patrol

Patrol: No MRs in queue. Found 1 pending branch (gt-jq8i4) without MR bead. 8 stale branches detected (work already on main).


Move disk 2: B → A

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


mol-ready-work variants: safe vs aggressive

## Summary

Create two variants of mol-ready-work:

### mol-ready-work-safe (default)
- PRs: review and comment, but require human approval for merge
- Issues: triage only, don't auto-close
- Beads: implement but create PR instead of pushing to main

### mol-ready-work-aggressive
- PRs: can approve and merge directly
- Issues: can close duplicates/invalid
- Beads: can push directly to main

## Implementation
Could be a single molecule with a `{{mode}}` variable, or two separate protos.

## Parent
Part of gt-tnca (mol-ready-work epic)


Digest: mol-deacon-patrol


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

## The Insight

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

## Current State

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

Missing: **Convoy status panel**

## Proposed Enhancement

Add a convoy panel showing:

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

## Components

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

## Integration Options

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

## Why This Matters

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

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


Slim down rig root config.json to identity only

Rig root config.json should only contain identity:
- type, version, name, git_url, beads.prefix, created_at
- Remove any behavioral config (move to settings/config.json)
- Update RigConfig type to separate identity from settings
- Ensure loader reads identity from root, settings from settings/


Move disk 2: B → A

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


Move disk 1: C → A

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


Merge: gt-3x1

branch: polecat/Slit
target: main
source_issue: gt-3x1
rig: gastown


Move disk 4: A → C

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


Move disk 3: C → A

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


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

## Task

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

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

## Implementation

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

```go
var clearAll bool

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

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


Remove .gastown/ after migration complete

Final cleanup:
- Remove .gastown/ directories at town and rig levels
- Remove daemon/ and deacon/ directories (replaced by .runtime/)
- Update .gitignore to remove old patterns
- Verify all tests pass with new structure


Review PR #42: fix(done): detect default branch instead of hardcoding 'main'

Review PR #42. Verify default branch detection works correctly. Approve with gh pr review --approve if good.


Standardize bd mol vs gt mol commands

Audit all docs and templates for command usage.

Clarify:
- gt mol = Gas Town wrapper (what does it add?)
- bd mol = Beads molecule commands (authoritative)

If gt mol is thin wrapper, consider removing.


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 12: All agents healthy


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 121: All healthy, no callbacks, 3 convoys tracking


Day 3.0: Document mail protocol for patrol coordination

Document the mail protocol used for patrol coordination.

**Mail types:**
- POLECAT_DONE: Polecat → Witness (work complete, ready for merge)
- MERGE_READY: Witness → Refinery (branch ready for merge queue)
- MERGED: Refinery → Witness (merge complete, safe to nuke)
- WITNESS_PING: Witness → Deacon (health check for second-order monitoring)
- HELP: Any → escalation target (stuck, need intervention)
- HANDOFF: Any → self (session continuity)

**Format conventions:**
- Subject prefix indicates type (e.g., 'POLECAT_DONE: nux')
- Body contains structured data (branch, bead ID, etc.)

This documentation enables consistent implementation across all patrol formulas.


Patrol agent state.json not updated on activity

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 34: All healthy, no incidents


Move disk 1: A → B

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


Update templates for Propulsion Principle

Overhaul agent prompts to embody the Universal Gas Town Propulsion Principle:

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

Templates to update:
- [ ] deacon.md.tmpl - Check hook first, no decision logic
- [ ] polecat.md.tmpl - Propulsion startup, follow molecule
- [ ] witness.md.tmpl - Sling wisps when spawning agents
- [ ] refinery.md.tmpl - Accept slung epics

Key changes:
1. Remove 'should I run this?' decision points
2. Add 'check your hook' as step 1 of startup
3. Make molecule-following the default mode
4. Simplify - agents don't think, they execute


Digest: mol-deacon-patrol

Patrol 10: routine, halfway


gt doctor: add Claude settings.json validation

Add a new doctor check to validate Claude Code settings in worker directories:

**Check for:**
1. .claude/settings.json exists in polecats/*, crew/*, witness/rig, refinery/rig
2. SessionStart hook has 'gt prime' command
3. Autonomous roles (polecat, witness, refinery) have 'gt mail check --inject' in SessionStart
4. Interactive roles (crew, mayor) have mail check in UserPromptSubmit only

**Auto-fix capability:**
Use internal/claude.EnsureSettingsForRole() to create missing settings files.

Context: The spawn priming race condition fix (gt-6957) added embedded settings templates. Doctor should validate these are in place.


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.


Merge queue: per-rig queue management

Per-rig merge queue for coordinating polecat work.

## Concept

When polecats complete work, they submit to the merge queue. The Refinery processes the queue, merging work to main in order.

## Data Model

```go
type MergeRequest struct {
    ID        string    `json:"id"`
    Polecat   string    `json:"polecat"`
    Branch    string    `json:"branch"`
    Issue     string    `json:"issue,omitempty"`
    Status    MRStatus  `json:"status"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}

type MRStatus string
const (
    MRPending   MRStatus = "pending"
    MRReviewing MRStatus = "reviewing"
    MRMerged    MRStatus = "merged"
    MRRejected  MRStatus = "rejected"
)
```

## Interface

```go
type MergeQueue struct {
    rig  *Rig
    path string  // <rig>/refinery/queue.jsonl
}

func NewMergeQueue(rig *Rig) *MergeQueue

// Queue operations
func (mq *MergeQueue) Submit(polecat, branch string, issue string) (*MergeRequest, error)
func (mq *MergeQueue) List() ([]*MergeRequest, error)
func (mq *MergeQueue) Next() (*MergeRequest, error)  // oldest pending
func (mq *MergeQueue) Get(id string) (*MergeRequest, error)

// Status updates
func (mq *MergeQueue) SetStatus(id string, status MRStatus) error
func (mq *MergeQueue) MarkMerged(id string) error
func (mq *MergeQueue) MarkRejected(id, reason string) error
```

## Queue Storage

JSONL file at `<rig>/refinery/queue.jsonl`. FIFO ordering.

## Git Coordination

Refinery processes queue:
1. Fetch polecat branch
2. Attempt merge to main
3. Run tests (if configured)
4. Push to origin
5. Update queue status

## Conflict Handling

If merge fails:
- Mark MR as rejected
- Notify polecat to rebase


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

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

## Two Points to Add Instructions

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 8: All healthy


Critical packages lack test coverage

Several packages have no test files:
- internal/lock/ - Core identity locking (212 lines UNTESTED)
- internal/witness/ - Worker monitoring
- internal/mrqueue/ - MR queue management
- internal/claude/ - Claude integration
- internal/style/ - Terminal styling
- internal/constants/ - Constants

Priority for testing:
1. lock/ - prevents duplicate agents, critical for correctness
2. witness/ - agent lifecycle management
3. mrqueue/ - merge request processing

Overall: 37 test files for 160 Go files (23% by file count)


Move disk 1: B → C

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Cycle 20


Digest: mol-deacon-patrol

Patrol 251 complete: no incidents


Move disk 1: C → A

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


Witness patrol: cleanup idle orphan polecats

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


Add unit tests for internal/lock package

attached_args: Lock package tests

Add comprehensive tests for the file locking package.

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

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

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


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.


Move disk 2: A → C

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


Review PR #53: fix: Add retry logic for Enter key send in NudgeSession/NudgePane

Review PR #53. Check retry logic is sound. Test locally if needed. Approve with gh pr review --approve if good.


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, no lifecycle requests, no orphans remediated


Detect abandoned work

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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 42: All agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol 6: All healthy


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

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


Refinery: Send MERGED notification to witness after merge

During liftoff test (gt-j0gx2), observed that refinery:
1. Received MERGE_READY for nux
2. Fetched, rebased, resolved conflicts correctly
3. Ran tests (passed)
4. Merged to main and pushed
5. Deleted polecat branch

But did NOT:
- Send MERGED mail to witness
- Close the MR bead (gt-5qkah)

The mol-refinery-patrol.formula.toml documents this step but the agent didn't execute it.

Impact:
- Witness never receives MERGED signal
- Polecat worktree never gets nuked
- MR beads accumulate as open

Fix:
After successful merge+push, refinery must:
```bash
gt mail send <rig>/witness -s "MERGED <polecat>" -m "..."
bd close <mr-bead> --reason "Merged to main"
```


Digest: mol-deacon-patrol

Patrol 8: Routine


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


mol-deacon-patrol

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

Original description:
Deacon patrol molecule template. Label: template


Move disk 1: A → B

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


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 2: all healthy, no events


mol-deacon-patrol


Patrol System: Agent lifecycle loops with attachments

Enable Gas Town agents to run continuous patrols, survive crashes, and hand off work across sessions.

## Core Concepts
- **Attachments**: Molecules bound to agent's pinned bead until complete
- **Patrols**: Cyclic molecules that loop (deacon, witness, refinery)
- **Quiescent**: Agents that sleep until triggered (witness, refinery)

## Design Doc
See docs/patrol-system-design.md

## Phases
Phase 1: Foundation (attachment field, daemon detection, mol-deacon-patrol)
Phase 2: Quiescent Agents (wake triggers, witness/refinery patrols)
Phase 3: Callbacks and Plugins (mail protocol, plugin runner)
Phase 4: Polish (gt patrol status, metrics, tuning)

## Key Decisions
- Attachment as field on pinned bead (not edge type, for now)
- Mail-based orchestration for all callbacks
- Queue replacement for heartbeat delivery (not pile-up)
- Burn and respawn for patrol loops (not in-place reset)


Digest: mol-deacon-patrol

Patrol cycle 3: All healthy


Digest: mol-deacon-patrol

Patrol cycle 2: All 6 agents healthy, 3 polecats active (furiosa, nux, obsidian), beads refinery has 1 pending


Digest: mol-deacon-patrol

Patrol 259 complete: no incidents


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)


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.


gt-polecat-gastown-test-cat

gt-polecat-gastown-test-cat

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


Swarm learning: Beads database locality gap

## PGT Bug (GGT Design Already Correct)

Mayor created issues in `~/ai/mayor/rigs/beads/.beads/` but polecats use `~/ai/beads/.beads/`. Different databases = polecats can't see Mayor's beads.

**GGT Fix**: architecture.md already specifies:
- All agents use BEADS_DIR pointing to rig-level `.beads/`
- Lines 116-143: Beads Configuration for Multi-Agent
- Lines 573-586: Rig-Level Beads via BEADS_DIR

This is a PGT implementation gap, not a design issue. GGT spawn must set BEADS_DIR correctly.


Mol Mall: Formula library and sharing

## Mol Mall

Library/marketplace for formula molecules.

### Features
- Browse available formulas
- Formula metadata (author, version, inputs, outputs)
- Custom formula creation
- Formula versioning
- Cross-town formula sharing (future)

### Commands
```bash
gt formula list              # List available formulas
gt formula show <name>       # Formula details
gt formula create <name>     # Create new formula
gt formula edit <name>       # Modify formula
gt formula export <name>     # Export for sharing
gt formula import <file>     # Import shared formula
```

### Storage
- Formulas as beads in town-level .beads/
- type: formula
- Structured schema for legs, synthesis, inputs

### Future: Public Mol Mall
- Central registry of community formulas
- gt formula search 'code review'
- gt formula install community/security-audit


Digest: mol-deacon-patrol

Patrol 16: clear


Digest: mol-deacon-patrol

Patrol 4: Routine


Phase 4: Deacon Patrol Loop

$(cat /tmp/phase4.md)


Digest: mol-deacon-patrol

Patrol cycle 13: nominal


Create Refinery role template

Add Refinery template to internal/templates/roles/:
- refinery.md.tmpl with full role context
- Variables: rig name, working directory, handoff bead ID
- Update SeedRoleTemplates to include it
- gt prime uses this template for Refinery context


Move disk 1: C → A

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


Merge: slit-1767141951901

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


Add GUPP to non-polecat roles (Mayor, Deacon, Witness, Refinery)

GUPP (propulsion nudge after beacon) is only implemented for polecats in session/manager.go.

Other roles have different startup flows but could benefit from similar auto-propulsion:
- Mayor: mayor/manager.go or wherever mayor session starts
- Deacon: deacon startup flow
- Witness: witness startup flow
- Refinery: refinery startup flow

Each role may need role-specific propulsion message.

(Refiled from bd-8hea)


Serialized conflict resolution via merge-slot gate

## Problem: Monkey Knife Fight

Multiple conflict-resolution polecats racing to land creates cascading conflicts:
- Polecat A rebases on main@v1, resolving...
- Polecat B rebases on main@v1, resolving...
- Polecat A pushes → main@v2
- Polecat B pushes → CONFLICT (main moved) → needs re-resolve

This wastes cycles and creates thrashing.

## Solution: Merge-Slot Gate

A single merge slot per rig, implemented via gates:

```
┌─────────────────────────────────────────────────────┐
│              MERGE SLOT (gt-merge-slot)             │
│            Only one holder at a time                │
└─────────────────────────────────────────────────────┘
                         │
         ┌───────────────┼───────────────┐
         ▼               ▼               ▼
    [High-prio MR]  [Med-prio MR]   [Low-prio MR]
     acquires slot   waits on gate   waits on gate
```

## Design

### Merge Slot Bead
Each rig has a persistent slot bead: `gt-merge-slot` (type=slot)
- Status: open (slot available) or in_progress (slot held)
- Holder field: which polecat/MR currently holds it

### Acquiring the Slot
1. Conflict polecat checks `bd show gt-merge-slot`
2. If status=open:
   - `bd update gt-merge-slot --status=in_progress --holder=<mr-id>`
   - Proceed with conflict resolution
3. If status=in_progress:
   - Create bead-gate waiting for slot to become open
   - Block until gate closes

### Priority Ordering
Convoy graph provides priority:
- Convoy age (older = higher priority)
- Epic priority (P0 > P4)
- Retry count (high retries = penalty)

Witness dispatches conflict resolution in priority order.
Only highest-priority waiting work acquires slot when released.

### Releasing the Slot
After merge to main:
1. `bd update gt-merge-slot --status=open --holder=""`
2. All waiting gates check slot
3. Highest-priority waiter acquires

### Direct-to-Main Flow
Conflict polecat with slot:
1. Rebase on main, resolve conflicts
2. Run tests
3. Push directly to main (not back to MR queue)
4. Close original MR bead
5. Release merge slot

## Benefits
- No monkey knife fight (serialized)
- Priority respected (convoy back-pressure)
- No queue re-entry (direct to main)
- Uses existing gates infrastructure

## Implementation Tasks
1. Create merge-slot bead type
2. Slot acquire/release in gt done
3. Witness priority-ordered dispatch
4. Gate-based waiting for slot

## Related
- gt-si8rq.5: Conflict resolution workflow (update to use slot)
- gt-si8rq.6: Priority-ordered MQ (provides priority info)
- bd-quw1: Phase handoff (gate infrastructure)


Move disk 2: B → A

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


Move disk 3: B → C

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


Move disk 1: C → A

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


Feed-Based Wake Model for Patrol Agents

## The Paradigm Shift

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

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

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

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

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

## Architecture

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

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

## Wake Sources (Priority Order)

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

## Key Design Decisions

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

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

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

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

## Reference

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

## Related

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


Implement

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

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


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 18: all healthy


Digest: mol-deacon-patrol

Patrol #8


gt mail send: support reading message body from stdin

Currently gt mail send -m requires the message as a command-line argument, which causes shell escaping issues with backticks, quotes, and special characters.

Add support for reading message body from stdin:
- gt mail send addr -s 'Subject' --stdin  # Read body from stdin
- echo 'body' | gt mail send addr -s 'Subject' -m -  # Convention: -m - means stdin

This would allow:
cat <<'EOF' | gt mail send addr -s 'Subject' --stdin
Message with \`backticks\` and 'quotes' safely
EOF

Without this, agents struggle to send handoff messages containing code snippets.

## Moved from beads
Originally bd-3bsz. gt mail is in gastown, not beads.


Digest: mol-deacon-patrol

Patrol 14: all clear


Digest: mol-deacon-patrol

Patrol 9: Routine


bd list --parent: filter by parent issue

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

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

Would show all open children of gt-h5n.

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


Move disk 2: B → A

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol #18


Move disk 1: C → A

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol cycle 56: All healthy


P0: Multiple agents can claim same worker identity

Multiple Claude Code sessions running simultaneously all think they are 'dave' on beads/crew/dave. No detection or prevention of identity collision. This breaks the single-agent-per-worker assumption.

## Fix Implemented

1. **Lock Package** (`internal/lock/lock.go`):
   - PID-based lockfile at `<worker>/.gastown/agent.lock`
   - Contains PID, timestamp, session ID, hostname
   - Stale lock detection (checks if owning PID is dead)

2. **Prevention in gt prime**:
   - Workers (crew/polecat) acquire identity lock before loading context
   - If another live process holds the lock, prime fails with clear error
   - Shows lock holder details and resolution steps

3. **Detection with gt agents**:
   - `gt agents check` - scans for collisions and stale locks
   - `gt agents fix` - cleans stale locks
   - JSON output available for patrol tooling

4. **Correction in gt doctor**:
   - New `identity-collision` check
   - `gt doctor --fix` cleans stale locks


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 8: quick pass


Witness patrol wisp with polecat leases

Witness should maintain a rolling patrol wisp that tracks active polecats:

```
wisp-witness-patrol
├── lease: furiosa (boot → working → done)
├── lease: nux (working)
└── lease: slit (done, closed)
```

When POLECAT_STARTED arrives:
- bd mol bond mol-polecat-lease wisp-patrol --var polecat=X

Patrol loop iterates leases:
- gt peek $polecat
- If idle: gt nudge
- If shutdown received: close lease

When all leases closed:
- bd mol squash wisp-xxx --summary='N polecats processed'

Requires mol-polecat-lease proto definition.


mol-deacon-patrol


Cross-project dependency workflow (Gas Town side)

Gas Town integration for cross-project dependencies.

## Components
- gt-zniu: gt park command (park molecule on external dep)
- gt-in3x: gt spawn --continue (resume parked molecule)
- gt-5uf3: Patrol auto-resume (future)

## Design Doc
See: docs/cross-project-deps.md

## Depends on Beads
- bd-h807: Cross-project dependency support (epic)

## Launch Plan
Phase 1 (launch): gt park + gt spawn --continue (manual resume)
Phase 2 (later): Patrol auto-resume


Digest: mol-deacon-patrol

Patrol complete: 17 Claude procs, 3 witnesses, 2 refineries healthy. 2 convoys open. No orphans, no cleanup needed. Inbox empty.


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol cycle 14: All healthy


Digest: mol-deacon-patrol

Cycle 186: Nominal


Merge: keeper-1767106012994

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


Digest: mol-deacon-patrol

Patrol 144 complete: All agents healthy


Digest: mol-deacon-patrol

Patrol 111: All healthy


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

P19: stable


Digest: mol-deacon-patrol

Patrol 2: all healthy, beads swarm active


Move disk 1: B → C

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


Merge: coma-mjwjczb0

branch: polecat/coma-mjwjczb0
target: main
source_issue: coma-mjwjczb0
rig: gastown
agent_bead: gt-gastown-polecat-coma


Digest: mol-deacon-patrol

Patrol 1: No mail, all agents healthy (mayor/witnesses/refineries OK), 0 polecats active, 2 orphaned mols for removed furiosa polecat noted


Digest: mol-deacon-patrol

Patrol #3: Routine - 6 agents healthy


Digest: mol-deacon-patrol

Patrol 18: all quiet


Move disk 1: A → B

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


Move disk 1: B → C

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 2: All healthy, no changes


CLI cleanup: Remove duplicate mol commands from gt

## Problem
gt mol has commands that duplicate bd mol functionality:
- `gt mol catalog` (duplicate of `bd formula list`)
- `gt mol show` (duplicate of `bd mol show`)
- `gt mol squash` (duplicate of `bd mol squash`)
- `gt mol burn` (duplicate of `bd mol burn`)
- `gt mol bond` (duplicate of `bd mol bond`)

## Principle
- **bd** = beads operations (issues, molecules, formulas)
- **gt** = agent operations (sessions, communication, work dispatch)

gt should delegate to bd for beads operations, not duplicate them.

## Proposed Changes
Keep gt mol commands that are agent-specific:
- `gt mol status` - what is on MY hook
- `gt mol attach/detach` - hook management
- `gt mol current` - what should I work on
- `gt mol progress` - my progress through workflow

Remove/delegate to bd:
- `gt mol catalog` → use `bd formula list`
- `gt mol show` → use `bd mol show`
- `gt mol squash` → use `bd mol squash`
- `gt mol burn` → use `bd mol burn`
- `gt mol bond` → use `bd mol bond`

## Alternative
Keep as thin wrappers that just call bd, for convenience.


Move disk 2: A → C

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


Remove stale migration docs from gastown-py

The gastown-py repo has migration-related documentation that is now misinformation since we have made design decisions. Remove or clearly mark as obsolete: any docs about migration paths, old architecture assumptions, or superseded designs.


Immediate daemon notification on lifecycle request

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

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

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

## Proposed Solutions

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

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

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

Recommend Option A for simplicity.

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


Move disk 1: C → A

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


Move disk 1: A → B

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


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 3: quick pass, all healthy


gt mq retry: retry a failed MR

Implement 'gt mq retry <id>' to retry a failed merge request.

Actions:
1. Verify MR exists and is in failed state (open with failure labels)
2. Remove failure labels (needs-rebase, needs-fix)
3. Reset to ready state
4. Optionally re-run immediately (--now flag)

Options:
- --now: immediately process (instead of waiting for Engineer loop)

Reference: docs/merge-queue-design.md#cli-commands


Digest: mol-deacon-patrol

Patrol 19: clear


Add molecule phase lifecycle diagram to architecture.md

Create a clear lifecycle diagram showing molecule phases:

```
                    ┌─────────────┐
                    │   Proto     │
                    │  (crystal)  │
                    └──────┬──────┘
                           │
                      bd mol bond
                           │
              ┌────────────┴────────────┐
              │                         │
              ▼                         ▼
      ┌───────────────┐        ┌───────────────┐
      │     Mol       │        │    Wisp       │
      │   (liquid)    │        │    (gas)      │
      │   durable     │        │  ephemeral    │
      │  main beads   │        │ .beads-eph/   │
      └───────┬───────┘        └───────┬───────┘
              │                        │
         bd mol squash            bd mol squash
              │                        │
              ▼                        ▼
      ┌───────────────┐        ┌───────────────┐
      │    Digest     │        │   (nothing)   │
      │ (distillate)  │        │  evaporates   │
      │  in git hist  │        └───────────────┘
      └───────────────┘
```

Also document:
- When to use Mol vs Wisp
- Mol: code review waves, epic implementation, feature work
- Wisp: orchestration, polecat work sessions, patrol loops


Move disk 2: A → C

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


Nested loop support in control flow

Currently, nested loops (a loop inside a loop body) are not supported.

In expandLoopIteration(), the Loop field is intentionally not copied:
```go
// Note: Loop field intentionally not copied - nested loops need explicit support
```

To support nested loops:
1. After expanding the outer loop iteration, recursively call ApplyLoops on the body steps
2. Handle nested iteration ID prefixing (e.g., `outer.iter1.inner.iter2.step`)
3. Add tests for nested loop scenarios

This is a lower-priority enhancement since most real-world formulas use single-level loops.


Move disk 1: C → A

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


Move disk 1: A → B

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


gt crew at: auto-prime when exec'ing Claude in-session

When running 'gt crew at <name>' from inside the target session, we exec Claude directly. But this means we can't send 'gt prime' afterward since we ARE the process.

Possible solutions:
1. Claude startup hook that runs gt prime
2. Pass prompt as argument to claude CLI
3. Wrapper script approach

Related: crew resume prompt also can't be sent in this path.


save-state

Update handoff bead with new state.

Persist nudge counts and pending actions.

Needs: execute-actions


Digest: mol-deacon-patrol

Patrol 5: stable


Move disk 5: A → B

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


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol cycle 17: All agents healthy


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 6: Quick cycle, all quiet


Polecat: Clean exit after MR submission

Update polecat workflow to be truly ephemeral after MR submission.

## Current Behavior
- Polecat submits MR
- Polecat waits for merge or rebase request
- Session stays alive, sandbox persists

## New Behavior
- Polecat submits MR
- Polecat closes its work bead (status=in_review or similar)
- Polecat signals 'recyclable' to Witness
- Sandbox can be cleaned up after branch is pushed

## Implementation
1. Update mol-polecat-work.formula.toml
2. Add explicit 'submit and exit' step
3. Ensure branch is pushed before sandbox cleanup
4. Signal Witness that polecat is recyclable

## Considerations
- Sandbox cleanup can be deferred (worktrees are cheap)
- Or: Witness runs cleanup patrol for idle polecats

Implemented: Updated mol-polecat-work.formula.toml (v4) for ephemeral polecat model. Polecats now submit via gt done and become recyclable. No longer wait for Witness termination or close their own issues.


Digest: mol-deacon-patrol

Patrol cycle 14: All healthy - dag polecat started


Digest: mol-refinery-patrol

Patrol: Cleaned 2 stale MRs (dag unverifiable, furiosa already merged). Queue empty.


Move disk 1: C → A

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 3: A → B

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


ApplyBranches/ApplyGates mutate steps in place

ApplyBranches and ApplyGates claim to return a modified steps slice, but they actually mutate the original steps via the pointer map from buildStepMap().

```go
// ApplyBranches docstring says:
// Returns the modified steps slice (steps are modified in place for dependencies).
```

This is technically documented but violates the pattern established by ApplyLoops and ApplyAdvice which return new step slices.

Options:
1. Document explicitly that these functions mutate in place (current behavior)
2. Clone steps before modification for true immutability
3. Accept this as intentional since it's an optimization

The current behavior is safe because cook.go doesn't reuse the input slice, but could cause subtle bugs if callers expect immutability.

Recommend option 1 (document) or 2 (clone) for consistency.


Merge: dag-1767079859283

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


Digest: mol-deacon-patrol

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


mol-deacon-patrol


BUG: Boot spawns in wrong session (gt-deacon instead of gt-deacon-boot)

## Problem

Boot (the Deacon's watchdog) is supposed to spawn in its own session `gt-deacon-boot` per the code:
```go
const SessionName = "gt-deacon-boot"
```

But when checking tmux, Boot appears to be running in the `gt-deacon` session with cwd `dogs/boot`.

## Evidence

```
$ tmux capture-pane -t gt-deacon -p
⏺ Bash(cd /Users/stevey/gt/deacon && gt feed --since 10m --plain 2>/dev/null)
  Shell cwd was reset to /Users/stevey/gt/deacon/dogs/boot
```

## Impact

- `gt status` shows Deacon as "stopped" when Boot is running in its session
- Boot and Deacon lifecycle are confused
- Daemon's two-layer approach (Boot triage + Deacon heartbeat) doesn't work correctly

## Expected Behavior

1. Boot spawns in `gt-deacon-boot` session
2. Boot runs triage, decides if Deacon needs starting
3. If yes, Boot starts Deacon in `gt-deacon` session
4. Both sessions can coexist: Boot (ephemeral triage) and Deacon (persistent patrol)

## Investigation Needed

- Check `boot.spawnTmux()` - is it creating the right session name?
- Check if something is reusing the Deacon session for Boot
- Verify session naming throughout the daemon/boot code


Digest: mol-deacon-patrol

Patrol 7: all clear


Digest: mol-deacon-patrol

Patrol 17: routine