Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 12: All clear


Move disk 2: B → A

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


Merge: imperator-1767106079026

branch: polecat/imperator-1767106079026
target: main
source_issue: imperator-1767106079026
rig: gastown


🤝 HANDOFF: Investigate beads-sync divergence (221 files)

## Context

gt doctor now detects orphaned code on beads-sync branch. Running it shows:

  beads-sync-orphans: 221 file(s) on beads-sync not in main

This is in the gastown repo (checking from crew/max).

## Background

- Earlier today we recovered orphaned mail migration code lost in merge 96c773f
- Recently simplified architecture: all workers use mayor/rig/.beads (redirects)
- This simplification may have caused beads-sync branch to diverge unexpectedly

## Investigation Steps

1. From crew/max run: git diff main..beads-sync --stat
2. Check if beads-sync should even exist anymore (was for multi-clone sync)
3. If obsolete with redirect architecture, consider deleting it
4. If it has legitimate changes, cherry-pick or merge to main

## Key Question

With all workers using mayor/rig/.beads via redirects, is beads-sync still needed?

## Commands

git log main..beads-sync --oneline | head -20
git diff main..beads-sync -- *.go | head -100


Digest: mol-deacon-patrol

Patrol 20: Final cycle, all clear, handoff triggered


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.


submit-merge

Submit to merge queue. Create branch if needed.
Verify CI passes.

gt done  # Signal work ready for merge queue

If there are CI failures, fix them before proceeding.

Depends: rebase-main


Phase 2: Hook Execution Protocol

# Phase 2: Hook Execution Protocol

Making agents actually RUN what's on their hook.

## The Problem

Currently, agents wake up, get primed, and... wait. They don't automatically
execute their pinned molecule or slung work. The propulsion is missing.

## The Solution

gt prime should end with an ACTION, not just context loading:

```
gt prime output:
  1. Load context (existing)
  2. Check hook
  3. If hook has work → tell agent to RUN IT NOW
```

## Hook Types

| Hook Content | Action |
|--------------|--------|
| Pinned molecule (mol-*) | Execute current step, close step when done |
| Slung bead (gt-xxx) | Show bead, begin work |
| Nothing | Wait for assignment |

## Molecule Execution Pattern

When hook has a molecule:

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

Current step: inbox-check (gt-xxx)
Status: pending (ready to execute)

**EXECUTE THIS STEP NOW.**

### Step: inbox-check
Check the Mayor's inbox for messages...

When complete, close the step:
  bd close gt-xxx

Then check for next step:
  bd ready
```

The agent sees this, does the step, closes the step bead.

## Key Insight (from bd-hulf/bd-3zm7 rejection)

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

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

## Remaining Work

gt-qvn7.2.3: Enhance gt prime to show molecule step prompt using bd mol current.

## Files Changed

- internal/cmd/prime.go - Hook check and action injection
- Uses bd mol current for step discovery (already exists in beads)

## Acceptance Criteria

- gt prime shows current hook and prompts action
- Agent closes step with bd close <step-id>
- bd ready / bd mol current shows next step
- Agent naturally follows the execution flow


Move disk 3: B → C

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


Test MR

test


rebase-main

Rebase against main to incorporate any changes.
Resolve conflicts if needed.

git fetch origin main
git rebase origin/main

If there are conflicts, resolve them carefully and continue the rebase.

Depends: self-review, verify-tests


Digest: mol-deacon-patrol

Patrol 161: All agents healthy, no incidents, 1 dog idle


Digest: mol-deacon-patrol

Patrol 20: all healthy


Create patrol formula YAML files

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

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


Engineer main loop: poll for ready merge-requests

Implement the Engineer's main processing loop.

Loop structure:
1. Query: bd ready --type=merge-request
2. If empty: sleep(poll_interval), continue
3. Select highest priority, oldest MR
4. Claim: bd update <id> --status=in_progress
5. Process (delegate to other subtasks)
6. Repeat

Configuration:
- poll_interval: from rig config (default 30s)
- max_concurrent: from rig config (default 1)

The loop should be interruptible and handle graceful shutdown.

Reference: docs/merge-queue-design.md#engineer-processing-loop


Digest: mol-deacon-patrol

Patrol cycle 7: routine, healthy


Digest: mol-deacon-patrol

Cycle 14


Merge: rictus-mjtlq9xg

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


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

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


Digest: mol-deacon-patrol

Patrol 7: quick pass


Backup check for zombie polecats

Defense-in-depth check for zombie polecats that Witness should have cleaned.

**Why this exists:**
The Witness is responsible for nuking polecats after they complete work (via POLECAT_DONE).
This step provides backup detection in case the Witness fails to clean up.

**Zombie criteria:**
- State: idle or done (no active work assigned)
- Session: not running (tmux session dead)
- No hooked work (nothing pending for this polecat)
- Last activity: older than 10 minutes

**Run the zombie scan:**
```bash
gt deacon zombie-scan --dry-run
```

**If zombies detected:**
1. Review the output to confirm they are truly abandoned
2. Run without --dry-run to nuke them:
   ```bash
   gt deacon zombie-scan
   ```
3. This will:
   - Nuke each zombie polecat
   - Notify the Mayor about Witness failure
   - Log the cleanup action

**If no zombies:**
No action needed - Witness is doing its job.

**Note:** This is a backup mechanism. If you frequently find zombies,
investigate why the Witness isn't cleaning up properly.


Outpost/Worker interfaces: Core abstractions for remote compute

## Overview

Define the core interfaces that all outpost types implement.

## Interfaces

```go
type OutpostType string
const (
    OutpostLocal    OutpostType = "local"
    OutpostSSH      OutpostType = "ssh"
    OutpostCloudRun OutpostType = "cloudrun"
)

type Outpost interface {
    Name() string
    Type() OutpostType
    MaxWorkers() int
    ActiveWorkers() int
    Spawn(issue string, config WorkerConfig) (Worker, error)
    Workers() []Worker
    Ping() error
    SendMail(worker string, msg Message) error  // optional
}

type Worker interface {
    ID() string
    Outpost() string
    Status() WorkerStatus  // idle, working, done, failed
    Issue() string
    Attach() error         // for interactive outposts
    Logs() (io.Reader, error)
    Stop() error
}

type WorkerConfig struct {
    RigPath    string
    BeadsDir   string
    GitBranch  string
    Context    map[string]string  // hints for worker
}
```

## Files

- `internal/outpost/outpost.go` - Outpost interface
- `internal/outpost/worker.go` - Worker interface
- `internal/outpost/config.go` - WorkerConfig, OutpostType

## Notes

This is the foundation for all federation work. Keep interfaces minimal - we can extend later.


Digest: mol-deacon-patrol

Patrol 13: All healthy


Digest: mol-deacon-patrol

Patrol #16


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol #12: Stable


Beads CLI wrapper: shell out to bd

Wrapper for bd (beads CLI) commands.

## Interface

```go
type Beads struct {
    workDir string
}

func NewBeads(workDir string) *Beads

// Query
func (b *Beads) List(opts ListOptions) ([]*Issue, error)
func (b *Beads) Ready() ([]*Issue, error)
func (b *Beads) Show(id string) (*Issue, error)
func (b *Beads) Blocked() ([]*Issue, error)

// Mutations
func (b *Beads) Create(opts CreateOptions) (*Issue, error)
func (b *Beads) Update(id string, opts UpdateOptions) error
func (b *Beads) Close(ids ...string) error

// Sync
func (b *Beads) Sync() error
func (b *Beads) SyncStatus() (*SyncStatus, error)
```

## Data Types

```go
type Issue struct {
    ID          string
    Title       string
    Status      string
    Priority    int
    Type        string
    Description string
    Parent      string
    Children    []string
    DependsOn   []string
    Blocks      []string
}

type ListOptions struct {
    Status   string  // "open", "closed", "all"
    Type     string
    Priority int
}

type CreateOptions struct {
    Title       string
    Type        string
    Priority    int
    Description string
    Parent      string
}
```

## Implementation

Shell out to bd binary, parse JSON output where available.
```go
func (b *Beads) runBd(args ...string) ([]byte, error) {
    cmd := exec.Command("bd", args...)
    cmd.Dir = b.workDir
    return cmd.Output()
}
```

## Error Handling

- bd not installed: Clear error with install instructions
- Not a beads repo: Detect and report
- Sync conflicts: Parse and report


mol-deacon-patrol


Move disk 3: A → B

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


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


Digest: mol-deacon-patrol

Patrol 153 complete


Day 4.2: Implement gt polecat nuke command

Add gt polecat nuke <name> command:
- Kill the Claude session
- Delete the worktree
- Delete the branch
- Remove agent bead
- Full cleanup post-merge

Parent: gt-4a2qt


Merge: gt-rana.1

branch: polecat/rictus
target: main
source_issue: gt-rana.1
rig: gastown


Digest: mol-deacon-patrol


Move disk 1: C → A

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


Merge: slit-mjxc8tp2

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


Digest: mol-deacon-patrol

Patrol #15: Refineries healthy. Beads 5 pending, gastown 1 pending.


Digest: mol-deacon-patrol

Patrol #21: No messages, all agents healthy, cleaned 1 stale lock, burned 1 orphan wisp


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 20: All healthy. Handoff threshold reached.


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.


Formula validation specification

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

Deferred: post-launch polish


Digest: mol-deacon-patrol

Patrol 6: All healthy


Merge polecat/rictus: Add molecule phase lifecycle diagram

Branch: polecat/rictus

Adds molecule phase lifecycle diagram to architecture.md showing Proto → Mol/Wisp → Digest state transitions with the 'states of matter' metaphor. Also documents when to use Mol (durable) vs Wisp (ephemeral).

Closes: gt-c6zs


Mail should use wisps for ephemeral orchestration messages

## Problem

Town HQ beads are polluted with lifecycle orchestration messages:
- POLECAT_STARTED notifications
- Work assignments to polecats
- "Start work" nudges
- Test messages

These should never have been persistent beads. They accumulate forever.

## Analysis

Mail serves two purposes:
1. **Durable messages** - Handoffs, escalations, human-agent comms (need persistence)
2. **Ephemeral signals** - Lifecycle pings, work assignments, nudges (should be wisps)

## Options

### Option A: Dual-inbox architecture
- `gt mail inbox` checks both `.beads/` and `.beads-wisp/`
- Sender specifies `--ephemeral` flag for transient messages
- Ephemeral messages auto-expire or squash to digests

### Option B: All mail becomes wisps
- Default to wisp storage for all mail
- Important messages explicitly promoted to persistent
- Simpler model but loses audit trail for some messages

### Option C: Message type determines storage
- `message` type beads go to wisps by default
- `handoff` type stays persistent
- Automatic routing based on content

## Recommendation

Option A (dual-inbox) seems cleanest:
- Explicit control via `--ephemeral`
- Backwards compatible
- Clear mental model

## Acceptance Criteria

- Lifecycle pings (POLECAT_STARTED, etc.) go to wisps
- Work assignments go to wisps
- Handoffs stay persistent
- `gt mail inbox` shows both
- Wisps auto-cleanup on patrol squash

## Blocks

This blocks reliable swarm operations - every spawn pollutes HQ indefinitely.


gt context --usage: estimate remaining context via tmux line count

## Summary

Implement `gt context --usage` to estimate remaining context capacity.

## Approach

Use tmux scrollback buffer line count as proxy for token usage:
- `tmux capture-pane -p | wc -l` gives current line count
- Heuristics (tunable per model):
  - Opus 4.5: ~1800 lines = warning threshold
  - ~2000+ lines = critical, need handoff

## Output Format
```
Context Usage: 1642 lines (~82%)
Status: WARNING - consider handoff soon
```

## Notes
- Heuristics are model-specific, need config
- Line count is proxy, not exact token count
- Good enough for autonomous patrol decisions


mol-deacon-patrol


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 8: All healthy


Control flow: loop, gate, branch

Implement control flow operators for the molecule algebra.

## Core Operators

| Operator | Syntax | Purpose |
|----------|--------|---------|
| loop (fixed) | loop: { count: N, body: [steps] } | Fixed iteration |
| loop (conditional) | loop: { until: COND, max: N, body: [steps] } | Bounded conditional iteration |
| gate | gate: { before: step, condition: COND } | Wait for condition before proceeding |
| branch | branch: { from: step, steps: [a,b,c], join: step } | Parallel paths that rejoin |

Conditions evaluated mechanically (step status, output fields) per gt-8tmz.7.

## Design Review (2025-12-25)

Analyzed patrol patterns (witness, deacon, refinery) to verify these constructs
can express real Gas Town workflows. Key findings:

### Insight: Patrol Loop is OUTSIDE the Algebra

The daemon respawns patrols. Each formula describes ONE cycle. This means:
- Formulas don't need "infinite loop with burn-and-respawn"
- loop is only for **inner loops** (refinery's per-branch processing)
- "burn-or-loop" = complete cycle; daemon decides next action
- Context cycling is external, not algebraic

This significantly simplifies the algebra.

### Gap: for-each is Missing

The current proposal doesn't include for-each, but it's essential for patrol patterns:

| Pattern | Use Case |
|---------|----------|
| Witness survey-workers | For each polecat, bond an arm (parallel) |
| Refinery process-branch | For each branch in queue, run merge pipeline (sequential) |
| Deacon plugin-run | For each plugin where gate open, execute |

Proposed syntax:

    for-each:
      collection: "survey-workers.output.polecats"
      bond: mol-polecat-arm
      vars:
        polecat_name: "{item.name}"
      parallel: true

This overlaps with gt-8tmz.8 (runtime dynamic expansion). Decision needed:
- Include for-each here as control flow, OR
- Ensure gt-8tmz.8 covers these patterns adequately

### Gap: waits-for Gate Variant

The "fanout gate" pattern (aggregate waits for all dynamically-bonded children)
needs formalization:

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

Currently exists in formulas as waits_for: "all-children" but not in the algebra spec.

### What This Covers

With these operators (plus for-each), patrols become fully expressible:

**Witness Patrol:**
- for-each polecat -> bond mol-polecat-arm (parallel)
- gate with waits-for: all-children for aggregation

**Refinery Patrol:**
- for-each branch -> process pipeline (sequential)
- gate for test verification before merge

**Deacon Patrol:**
- for-each plugin -> execute if gate open
- Simple sequence otherwise

### Scope Decision

**Option A**: Implement loop, gate, branch now. Track for-each and waits-for separately.

**Option B**: Expand scope to include for-each and waits-for formalization.

Recommendation: Option A - implement core constructs, create child issues for gaps.


Move disk 1: B → C

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


Overseer inbox for strategic notifications

New address overseer/ for strategic notifications.

Receives:
- Convoy completions
- Cross-rig dependency resolutions
- Escalations from Deacon
- Daily digests (optional)

Separate from operational mail - this is the executive dashboard.

Related: hq-7h8jx (Convoy System epic in town beads)


os.Exit() calls in library code prevent proper error handling

internal/cmd/mail.go and other files have os.Exit() calls.

Issues:
- Hard to test
- Prevents graceful shutdown
- Can lose unsaved state
- Doesn't compose well in library code

Should return errors instead of calling os.Exit() directly.
Let main() decide how to exit.


Digest: mol-deacon-patrol

Patrol cycle 1: All rigs healthy, no incidents


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

Patrol 12: quiet


Move disk 1: C → A

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


MQ dashboard widget: queue status in TUI

Add merge queue status widget to the Bubbletea TUI dashboard.

Display:
┌─────────────────────────────────────────────────┐
│              MERGE QUEUE STATUS                  │
├─────────────────────────────────────────────────┤
│ Pending: 3   In Progress: 1   Merged (24h): 12  │
├─────────────────────────────────────────────────┤
│ QUEUE:                                          │
│   ► gt-mr-004  P0  Nux/gt-xyz     Processing... │
│     gt-mr-005  P1  Toast/gt-abc   Ready         │
│     gt-mr-006  P1  Capable/gt-def Blocked (005) │
└─────────────────────────────────────────────────┘

Interactive features:
- Navigate queue entries
- View MR details
- Retry/reject from dashboard

Depends on: gt-u1j.2 (Bubbletea TUI dashboard)

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


Move disk 1: A → B

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


Rename Engineer in Box to Shiny

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

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


Digest: mol-deacon-patrol

Patrol 19


Move disk 2: C → B

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


Move disk 1: A → B

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


gt swarm dispatch command not working

The "gt swarm dispatch" command shown in help does not work as expected.

**Observed:**
```
$ gt swarm dispatch bd-784c
[prints help text instead of dispatching]
```

**Expected:**
Should dispatch the next ready task from the epic to an available worker.

**Workaround:**
Had to manually use "gt sling <issue> <polecat>" for each task dispatch.

**Impact:**
- Manual task dispatch defeats swarm automation
- Coordinator has to track which tasks are ready and which polecats are free

**Suggestion:**
Implement or fix "gt swarm dispatch" to:
1. Find next unassigned task in epic
2. Find idle polecat in swarm
3. Sling task to polecat automatically

(Moved from bd-kp9y)


Digest: mol-deacon-patrol

Patrol 17: all quiet


Digest: mol-deacon-patrol

Patrol 17: Quiet


Digest: mol-deacon-patrol

Patrol 158: All healthy


Digest: mol-deacon-patrol

Patrol 2: All healthy - no changes from cycle 1


Move disk 2: B → A

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


Move disk 3: B → C

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


Polecats should not push branches to remote

## Current Behavior

Polecats push their branches to origin (e.g., `polecat/furiosa`), which pollutes the remote with many short-lived branches.

## Desired Behavior

Polecats should only commit locally. The Refinery handles all remote pushes:
1. Polecat works on local `polecat/<name>` branch
2. Polecat signals done (state → idle)
3. Refinery pulls from local polecat branch
4. Refinery runs tests, merges to main
5. Refinery pushes main to remote
6. If PR review needed, Refinery creates the PR

## Benefits

- Clean remote (no branch pollution)
- Clear responsibility (Refinery is the quality gate)
- Simpler cleanup (local branches deleted with worktree)
- Less noise in GitHub UI

## Trade-offs

- If polecat crashes before Refinery merges, code is lost locally
- But beads issue remains open, another polecat can redo the work
- This is acceptable for ephemeral workers

## Implementation

In polecat CLAUDE.md or landing protocol:
- Remove `git push origin HEAD` from workflow
- Replace with just `git commit` + signal done
- Refinery handles the rest


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol cycle 9: All healthy


Move disk 3: B → C

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


Patrol agents subscribe to bd activity --follow

Each patrol agent (Deacon, Witness, Refinery) should run bd activity --follow as a background process. Any output line is a wake signal. This is the primary wake mechanism.

Implementation:
1. Add feed subscription to await-signal step logic
2. Agent starts bd activity --follow on entering await-signal
3. Any line of output breaks the wait immediately
4. Timeout still applies as safety net

See patrol-system-design.md for full specification.


Digest: mol-deacon-patrol

Patrol #19


Digest: mol-deacon-patrol

P13: stable


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy


Digest: mol-deacon-patrol

Patrol #5: All systems nominal


Digest: mol-deacon-patrol

Patrol 18


Digest: mol-deacon-patrol

Patrol cycle 37: All healthy, no incidents


Move disk 2: C → B

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


mol-deacon-patrol


Role prompts have mismatched startup protocols

Different role prompts describe different startup protocols:

- deacon.md: Check gt mol status, spawn if none: bd mol spawn
- refinery.md: Check bd list --status=in_progress, bond if none: gt mol bond
- polecat.md: Check bd mol current

These should use consistent terminology and commands.
The propulsion principle should be applied uniformly.


Move disk 1: C → A

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


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


Digest: mol-deacon-patrol

Patrol 9: All healthy


Move disk 1: B → C

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


Move disk 1: C → A

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


Layered context onboarding pattern

Pattern from handoff discussion:

## Pattern: Layered Context Onboarding

Town CLAUDE.md (user/org) -> Rig CLAUDE.md (project) -> Role priming

## Ultra-compressed HOP for workers (no reveal)

- Permanent record: All work tracked. Outcomes matter.
- Quality gates: Molecule steps exist for a reason.
- Attribution: Completions build your track record.
- Handoff clean: Leave state any worker can continue.

## Recommendation

Create Town @AGENTS.md for shared worker context that all workers see.
This provides common behavioral guidance without revealing full HOP context.


Move disk 1: B → C

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


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 9: routine


Day 3.0: Document mail protocol contracts

Document the formal mail protocol for Gas Town agent coordination.

Mail Types:

**POLECAT_DONE** (polecat → witness)
```
Subject: POLECAT_DONE: <name>
Body: {"issue": "gt-xyz", "status": "complete|failed", "notes": "..."}
```

**MERGE_READY** (witness → refinery)
```
Subject: MERGE_READY: <branch>
Body: {"worker": "nux", "issue": "gt-xyz", "branch": "polecat/nux/gt-xyz"}
```

**MERGED** (refinery → witness)
```
Subject: MERGED: <branch>
Body: {"issue": "gt-xyz", "sha": "abc123", "worker": "nux"}
```

**LIFECYCLE:Shutdown/Cycle/Restart** (agent → deacon/)
```
Subject: LIFECYCLE:Shutdown
Body: {"action": "shutdown"}
```

**HELP** (polecat → witness → mayor)
```
Subject: HELP: <brief>
Body: {"issue": "gt-xyz", "problem": "...", "context": "..."}
```

Create: docs/mail-protocol.md


Merge: rictus-mjtlq9xg

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


Move disk 2: C → B

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


Digest: mol-deacon-patrol

Patrol 3: stable


Digest: mol-deacon-patrol

Patrol 123: All healthy


Digest: mol-deacon-patrol

Patrol 15: Green


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 2: All healthy, no events


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 90: All healthy


Swarm cleanup: delete merged polecat branches and reset state

After a swarm completes and branches are merged, leftover state remains:

## Current Problem

1. **Remote branches not deleted** - polecat/* branches stay on origin after merge
2. **Polecat clones not reset** - still on old branch with completed work
3. **No cleanup command** - manual cleanup required

## Observed After Swarm

Remote branches still present:
- origin/polecat/Morsov
- origin/polecat/Nux
- origin/polecat/Rictus
- origin/polecat/Slit
- origin/polecat/Toast

## Proposed Solution

Add cleanup commands:

1. gt swarm cleanup <swarm-id> - Clean up after swarm completion
   - Delete remote polecat branches that were merged
   - Reset polecat clones to main
   - Clear issue assignments

2. gt polecat reset <rig>/<polecat> - Reset single polecat
   - git checkout main && git pull
   - Delete local polecat branch
   - Clear current issue assignment

3. Auto-cleanup option on gt session stop --cleanup

## Manual Cleanup For Now

git push origin --delete polecat/Nux polecat/Toast ...
cd polecats/Nux && git checkout main && git pull


Digest: mol-deacon-patrol

Patrol complete: Restarted 5 downed agents (Mayor, 2 Witnesses, 2 Refineries). All systems now healthy.


Digest: mol-deacon-patrol

Patrol 160 complete


Merge: dementus-1767073385126

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


Create .runtime/ for town-level runtime state

Move ephemeral town state to .runtime/:
- Create ~/gt/.runtime/ directory structure
- Move daemon/state.json → .runtime/daemon.json
- Move deacon/heartbeat.json → .runtime/deacon.json
- Move .gastown/agent-state.json → .runtime/agent-requests.json
- Move .gastown/keepalive.json → .runtime/keepalive.json
- Update .gitignore to ignore .runtime/
- Update all code references


Move disk 1: C → A

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


End-to-end integration test

Create and run end-to-end integration test.

## Test Scenario

1. Clean state: no polecats, fresh beads
2. Create test issue: simple documentation fix
3. Verify Deacon sees it: bd ready shows issue
4. Trigger Deacon: send heartbeat or wait
5. Verify spawn: gt polecats shows new polecat
6. Watch polecat work: tmux attach
7. Verify completion: issue closed, MR created

## Test Script

```bash
#!/bin/bash
# e2e-test.sh

# 1. Clean state
gt polecat remove --all
bd create "Test: update README typo" --type=task --priority=1

# 2. Verify ready
bd ready | grep "update README"

# 3. Wait for Deacon or trigger
# (manual for v0.1)

# 4. Watch
gt status
gt polecats gastown

# 5. Wait for completion
# (manual observation for v0.1)

# 6. Verify
bd list --status=closed | grep "update README"
```

## Success Criteria

- Issue created and visible in bd ready
- Polecat spawned and working
- Issue closed with commit reference
- No manual intervention (except observation)


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.


Clean dead sessions

Clean dead sessions and orphaned state.

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

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

# Fix everything
gt doctor --fix
```

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

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


Digest: mol-deacon-patrol

Cycle 20 - handoff threshold


Interactive prompts for destructive operations

Add interactive confirmations for destructive operations.

## Operations Needing Confirmation
- `gt swarm cancel` - Cancels active swarm
- `gt swarm land --force` - Force landing
- `gt polecat decommission` - Removes polecat
- `gt rig remove` - Removes rig
- `gt stop --all` - Stops all sessions
- `gt mail purge` - Permanently deletes mail

## Implementation Options

### Option 1: promptui library
```go
import "github.com/manifoldco/promptui"

prompt := promptui.Prompt{
    Label:     "Delete polecat Toast",
    IsConfirm: true,
}
result, err := prompt.Run()
```

### Option 2: Simple stdin
```go
func confirm(prompt string) bool {
    fmt.Printf("%s [y/N]: ", prompt)
    var response string
    fmt.Scanln(&response)
    return strings.ToLower(response) == "y"
}
```

## Bypass Flags
All confirmations skippable with --force or --yes:
```go
if !force && !confirm("Really cancel swarm?") {
    return nil
}
```

## Acceptance Criteria
- [ ] Destructive ops prompt by default
- [ ] --force or --yes bypasses
- [ ] Clear prompt text explaining action
- [ ] Non-interactive mode (piped input) auto-fails


Digest: mol-deacon-patrol

Patrol 8: Nominal


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Move disk 3: B → C

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


Move disk 1: B → C

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


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

## Problem

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

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

## Goal

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

## Key Insight: Beads Replace SendKeys

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

## Degraded Behavior (No-Tmux Mode)

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

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

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

## Requirements

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

## Acceptance Criteria

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


Digest: mol-deacon-patrol

Patrol 3: All nominal


Session cycling: Auto-spawn successor when context full

Enable automatic session succession for crew workers.

When a crew worker's context fills up (>80%), they should:
1. Write handoff mail to themselves
2. Signal session end
3. System auto-spawns successor session
4. Successor reads handoff, finds attached work, auto-continues

This completes the autonomous overnight work pattern from gt-9g82.

Depends on:
- Detecting context fullness (Claude Code API?)
- Session spawning mechanism (tmux/daemon)
- Handoff protocol already implemented


Digest: mol-deacon-patrol

Patrol 18: routine


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 8: All healthy.


gt spawn: beads sync warnings on fresh worktree

When spawning fresh polecats, seeing 'Warning: beads sync: exit status 1' and 'Warning: beads push: exit status 1'. Worktrees are created but beads state may not be properly synced.


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


Execute registered plugins

Execute registered plugins.

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

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

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

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

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

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


Computed range expansion (for-each over expressions)

Support for-each expansion over computed ranges, not just static lists:

for-each:
  var: move_num
  range: "1..2^{disks}"  # Computed at cook time

This enables formulas like Towers of Hanoi where the step count is a function of input variables. The range expression is evaluated during cooking.

Related: towers-of-hanoi.formula.yaml demonstrates the need.
Depends on: gt-8tmz.8 (Runtime dynamic expansion)


Protocol: Type System for Formulas

Protocols define interfaces that formulas implement - a type system for workflows.

## Concept

```toml
# reviewable.protocol
[protocol]
name = "Reviewable"

[requires]
steps = ["review"]  # Must have a step tagged "review"
outputs = ["review_decision"]  # Must produce this

[guarantees]
"review completes before any deploy step"
```

Formulas declare: `implements = ["Reviewable", "Deployable"]`

System verifies compliance statically.

## Use Cases

1. Ensure all deploy formulas have review steps
2. Define compliance requirements as protocols
3. Enable formula discovery: "Give me all Deployable formulas"
4. Validate formula composition compatibility

## Properties

- Static verification (before execution)
- Composable (protocol can extend protocol)
- Documentation value (self-describing contracts)

## Open Questions

1. Protocol syntax - embedded in formula or separate files?
2. Verification timing - cook time? load time?
3. Protocol versioning - how do protocols evolve?
4. Inheritance - can protocols extend other protocols?

## Related

- docs/formula_evolution.md - "Formula Schemas" section
- gt-8tmz - molecule algebra


Refinery needs manual restart/handoff mechanism

Refinery sessions can get stuck or need restart. Currently requires manual intervention. Need: 1) gt refinery restart command, 2) Refinery self-handoff on context fill, 3) Auto-recovery from stuck states.


bd list: Add type aliases (mr→merge-request)

The --type flag requires exact matches. Add aliases for convenience:

- mr → merge-request
- feat → feature
- mol → molecule

**Context**: Refinery cleanup missed 6 open MRs because `--type=mr` returned nothing while `--type=merge-request` found them.

**Implementation**: In the type filter parsing, normalize aliases before matching.


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.


Use Beads issue status as spawn source of truth

Currently witness tracks spawned issues in .gastown/witness.json to prevent re-spawning:

{"spawned_issues": ["gt-abc1", "gt-def2", ...]}

This is redundant with Beads issue status (in_progress). The witness could query:
  bd list --status=in_progress

The local list serves as a performance cache to avoid querying beads every cycle. Consider:
1. Use Beads as source of truth
2. Keep local cache with TTL
3. Sync cache on witness start

This simplifies state management and ensures consistency.


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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 4: All clear


Digest: mol-deacon-patrol

Patrol complete: inbox checked (4 msgs, 1 escalation resolved), all agents healthy (2 witnesses, 2 refineries, 3 polecats, 5 crew), cleaned 66 abandoned wisps


Digest: mol-deacon-patrol

Patrol 4: all clear


Move disk 1: B → C

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


Merge: furiosa-1767059690595

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


working

Actively working. Monitor for stuck.

The polecat is processing its assigned issue ({{issue}}).
Monitor via peek. Watch for:
- Progress on commits
- Status updates in beads
- SHUTDOWN mail when done

Wait for SHUTDOWN signal from the polecat.
Variables: {{polecat}}, {{issue}}


Digest: mol-deacon-patrol

Patrol cycle 13: All healthy


Update architecture.md: Engineer role and Beads merge queue

Update docs/architecture.md with recent design decisions:

1. Agent table: Change "Refinery" role to "Engineer"
   - Refinery = place/module/directory
   - Engineer = role (agent that works in the Refinery)

2. Merge Queue section: Document Beads-native model
   - MRs are beads issues with --type=merge-request
   - gt mq commands (submit, list, next, process, reorder)
   - Ordering via depends-on links

3. CLI section: Add gt mq commands

4. Key Design Decisions: Add decisions for:
   - #15: Merge Queue in Beads
   - #16: Engineer role (distinct from Refinery place)
   - #17: Session restart protocol for Engineer


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 #1: All agents healthy, no messages, no orphans


Digest: mol-deacon-patrol

Patrol 146: All healthy, new furiosa spawn


Digest: mol-deacon-patrol

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


Mail system: JSONL inbox, delivery, tmux injection

Refactor mail system to wrap bd mail commands.

## Status

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

## Implementation

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

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

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

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

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

## Address Translation

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

## Tmux Notification

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

## Migration

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

## Dependencies

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


Digest: mol-deacon-patrol

Patrol 17


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.


Move disk 1: C → A

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol cycle 14: All healthy


Move disk 2: C → B

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


Update Deacon template to emphasize staying in ~/gt/deacon directory

The Deacon template should instruct the agent to stay in ~/gt/deacon/ as much as possible, and always return there after any excursion. This prevents issues with identity detection (mail, mol status) which depend on cwd.


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)


Merge: rictus-mjw3nj1a

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


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

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


Move disk 6: A → C

Move disk 6 from peg A to peg C. (Move 608/1023)


Rename .beads-ephemeral to .beads-wisps in docs

The wisp storage directory should be named `.beads-wisps/` not `.beads-ephemeral/`.

Also fix the architecture: Witness and Refinery share mayor/rig's beads and wisps.
They don't have separate ephemeral stores.

## Files to update
- docs/wisp-architecture.md
- docs/architecture.md
- ~/gt/docs/patrol-system-design.md
- ~/gt/CLAUDE.md

## Changes
1. Rename `.beads-ephemeral/` → `.beads-wisps/` everywhere
2. Remove incorrect references to witness/.beads-ephemeral/ and refinery/rig/.beads-ephemeral/
3. Clarify that all rig-level patrols use mayor/rig/.beads-wisps/


Move disk 2: A → C

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


Merge: slit-1767082302712

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


Digest: mol-deacon-patrol

Patrol #3: Stable, no changes


Digest: mol-deacon-patrol

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


Merge: immortan-mjwlaw9o

branch: polecat/immortan-mjwlaw9o
target: main
source_issue: immortan-mjwlaw9o
rig: gastown
agent_bead: gt-gastown-polecat-immortan


Digest: mol-deacon-patrol

Patrol 20: final cycle


Digest: mol-deacon-patrol

Cycle 183: All agents healthy, no incidents


Digest: mol-deacon-patrol

Patrol 2: inbox clear, all agents healthy


Merge: toast-1767146237529

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


Merge: gt-ldk8

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


MR state transitions: validate open→in_progress→closed

Enforce valid state transitions for merge-requests:

Valid transitions:
- open → in_progress (Engineer claims MR)
- in_progress → closed (merge success or rejection)
- in_progress → open (failure, reassign to worker)
- open → closed (manual rejection)

Invalid:
- closed → anything (immutable once closed)

Implement validation in MR update operations.

Reference: docs/merge-queue-design.md#state-machine


Digest: mol-deacon-patrol

Patrol 15: All clear


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 46: All healthy


Digest: mol-deacon-patrol

Patrol 15: quick pass


Activity feed from wisp state: gt patrol status

Enable mayor and gt tool to quickly see what patrol agents are doing.

## Problem

The mayor and gt tool cannot quickly see what the deacon (or other patrol agents) are doing.
Need a way to extract an activity feed from the current wisp state.

## Desired Commands

- gt patrol status: Show current patrol state (step, timing, cycle count)
- gt patrol history: Show recent patrol cycles (from digests)
- gt patrol feed: Live tail of patrol activity

## Data Sources

- .beads-wisp/issues.jsonl: Current wisp with step progress
- .beads/issues.jsonl: Digests from squashed patrols
- heartbeat.json: Last activity timestamp

## Use Cases

1. Mayor checking deacon: Is the deacon doing anything?
2. Debugging hangs: What step is it stuck on?
3. Operator monitoring: Dashboard of patrol health
4. Summaries for handoffs: Auto-generate patrol digest

## Related

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


Digest: mol-deacon-patrol

Patrol 14: Routine


Digest: mol-deacon-patrol

Patrol 54: All healthy


Handoff mail not delivered to mayor inbox

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

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

Expected: Handoff mail in inbox

(Moved from hq-zs2t8)


Digest: mol-deacon-patrol

Patrol 5: Routine


Move disk 7: C → A

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


Merge: gt-xqh3y

branch: polecat/eli-mjufuh2g
target: main
source_issue: gt-xqh3y
rig: gastown


gt handoff should accept full session paths like gastown/crew/max

Currently gt handoff only accepts role shortcuts like 'crew', 'witness', etc. and tries to auto-detect the rig/name from environment. User tried 'gt handoff gastown/crew/max' and got 'unknown session type'. Should parse paths like '<rig>/crew/<name>' or '<rig>/<role>' directly into session names like 'gt-<rig>-crew-<name>'.


Optimize: Share stepMap across control flow operators

In ApplyControlFlow, both ApplyBranches and ApplyGates call buildStepMap() separately:

```go
func ApplyBranches(steps []*Step, compose *ComposeRules) ([]*Step, error) {
    stepMap := buildStepMap(steps)  // Called here
    ...
}

func ApplyGates(steps []*Step, compose *ComposeRules) ([]*Step, error) {
    stepMap := buildStepMap(steps)  // Called again here
    ...
}
```

This is inefficient for large formulas. Options:

1. Pass stepMap as a parameter to ApplyBranches/ApplyGates
2. Create an internal version that accepts stepMap, keep public API unchanged
3. Build once in ApplyControlFlow and pass down

Low priority since formula sizes are typically small.


Move disk 1: C → A

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


Digest: mol-deacon-patrol

Patrol 20: Final patrol, 11 sessions healthy, no incidents


Move disk 4: B → A

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


Digest: mol-deacon-patrol

Patrol cycle 11: All agents healthy


gt spawn beads sync warning is misleading for redirect-based polecats

## Problem

When spawning a polecat, gt spawn shows a warning:
```
Warning: beads sync: exit status 1
```

This is misleading because polecats using the redirect architecture (`.beads/redirect`) share the canonical database at `mayor/rig/.beads/beads.db`. The 'stale beads' indicated by the warning is just git branch divergence (main vs beads-sync), not actual data staleness.

## Expected Behavior

gt spawn should either:
1. Skip the beads sync check for polecats using redirects (they share the canonical DB)
2. Or provide a clearer message like 'beads redirect active, using shared database'

## Reproduction

```bash
gt spawn --issue gt-xxx --rig gastown --create
# Shows 'Warning: beads sync: exit status 1' even though beads are current
```

## Root Cause

spawn.go calls beads sync and treats any non-zero exit as a warning. But with redirects, the polecat doesn't need its own beads - it uses the canonical source via the redirect chain:
```
polecat/.beads/redirect -> ../../.beads -> gastown/.beads/redirect -> mayor/rig/.beads
```

## Fix Options

1. Check for .beads/redirect before calling sync
2. Have bd sync return 0 when redirect is present
3. Suppress the warning in spawn when redirect exists


Move disk 1: C → A

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


Move disk 4: B → A

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


bd mol advance command

## Cross-Repo Reference

This work is tracked in beads repo as **bd-3zm7**.

The gastown task gt-qvn7.2.1 is a placeholder.
Actual implementation happens in beads.

See: bd show bd-3zm7 (from beads/crew/dave)


Work on gt-e11: gt mail send priority flag is incompatibl...

Work on gt-e11: gt mail send priority flag is incompatible with bd mail send. Run 'bd show gt-e11' for details.


test-agent-verify


Digest: mol-deacon-patrol

Patrol 11: All healthy.


Digest: mol-deacon-patrol

Patrol cycle 13: All healthy


Move disk 1: A → B

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


Remove stubbed ProcessMRFromQueue and mrqueue package

internal/refinery/engineer.go has stubbed ProcessMRFromQueue() that returns hardcoded failure.
internal/mrqueue/ package exists but isn't used.

This was aspirational 'beads-based MR automation' but:
1. Refinery agent just runs git commands per role prompt
2. manager.ProcessMR() is already fully implemented if we need Go automation
3. The stub creates confusion about what's working

Either:
1. Remove engineer.ProcessMRFromQueue and mrqueue package entirely
2. Or finish implementing it if there's a real use case

Leaning toward removal - YAGNI.


Witness: bond mol-polecat-arm when discovering polecat

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

## Changes to witness/manager.go

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

## Arm Lifecycle

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

## Deduplication

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


Move disk 3: A → B

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol complete: gastown healthy, beads dormant


Digest: mol-deacon-patrol

Patrol 17: All healthy


Move disk 4: C → B

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


Spawn --molecule integration

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

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

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

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

Files: internal/cmd/spawn.go

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


Digest: mol-deacon-patrol

Patrol 20: All healthy, 2 crew active


Day 1.1b: Add type=role to bead schema

Add role as a valid bead type in the schema.

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

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

Must be done alongside type=agent schema work.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 119: All healthy


Digest: mol-deacon-patrol

Patrol 4: Nominal


#channel resolution for real-time broadcast

Wire tmux scanner into nudge system for #channel addresses.

## Deliverables

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

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

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

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


Digest: mol-deacon-patrol

P14: stable


Digest: mol-deacon-patrol

Patrol 5


Digest: mol-deacon-patrol

Patrol cycle 20: All 6 agents healthy, handoff threshold


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol 6: Mayor OK, 11 sessions


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 6: routine, all healthy


Digest: mol-deacon-patrol

Patrol 7: all clear


Move disk 1: C → A

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


Move disk 2: A → C

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


Digest: mol-deacon-patrol

Patrol 42: All healthy, 6 agents pinged, no incidents


Polecat template: fix 'git clone' to 'git worktree'

Template says 'You're in a project git clone' but polecats use worktrees, not clones. Fix terminology.


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 8: Mayor OK, 11 sessions


Polecats go off-task instead of working pinned bead

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

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

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


Phase verbs: pour and wisp commands

Implement the phase transition verbs:
- bd pour <proto> - instantiate as persistent mol
- bd wisp <proto> - instantiate as ephemeral wisp
- Update bd mol bond to inherit phase from target

These replace the current --wisp flag with cleaner verb semantics.


Move disk 2: A → C

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


Move disk 1: C → A

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


Merge: rictus-mjw3nj1a

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


Digest: mol-deacon-patrol

Cycle 20: Final health check - all healthy


Switch formulas from JSON to TOML

## Problem
Formula JSON files have poor ergonomics for agents and humans:
- Multi-line strings require `\n` escaping
- Diffs are hard to read (long single-line changes)
- No comments allowed

## Solution
Switch formulas to TOML format:

```toml
formula = "mol-deacon-patrol"
version = 1
description = """
Mayor's daemon patrol loop.
Multi-line strings work naturally.
"""

[[steps]]
id = "inbox-check"
title = "Handle callbacks"
description = """
Check inbox for messages.

```bash
gt mail inbox
```
"""
```

## Tasks
- [ ] Add TOML parsing for formulas (github.com/BurntSushi/toml)
- [ ] Update formula loader to try .toml first, fall back to .json
- [ ] Add `bd formula convert <name>` to migrate JSON → TOML
- [ ] Convert existing formulas
- [ ] Update docs

## Notes
- Keep issues.jsonl as-is (machine data, append-only)
- TOML only for human-edited formula files


Witness daemon: heartbeat loop, spawn ephemeral agent

Background daemon for agent lifecycle and monitoring.

## Core Responsibilities

1. **Heartbeat monitoring**: Check agent health periodically
2. **Session lifecycle**: Restart agents after handoff (Witness Protection)
3. **Polecat monitoring**: Track worker progress, nudging
4. **Escalation**: Report failures to Mayor

## Session Lifecycle (Witness Protection)

The daemon enables autonomous long-running operation by cycling agent sessions:

```go
type SessionLifecycle struct {
    AgentType string  // "witness", "refinery"
    StatePath string  // path to state.json
}

func (d *Daemon) monitorSessionLifecycle(agent SessionLifecycle) {
    // 1. Detect session exit
    // 2. Check state.json for requesting_cycle: true
    // 3. If cycle requested: start new session, clear flag
    // 4. If unexpected exit: escalate to Mayor
}
```

See architecture.md Key Decision #12: Agent Session Lifecycle.

## Interface

```go
type Daemon struct {
    rig      *Rig
    polecats *PolecatManager
    sessions *SessionManager
    config   DaemonConfig
}

type DaemonConfig struct {
    HeartbeatInterval time.Duration  // default: 30s
    NudgeThreshold    int            // nudges before escalation
    MaxWorkers        int            // from rig config
}

func NewDaemon(rig *Rig) *Daemon
func (d *Daemon) Start() error
func (d *Daemon) Stop() error

// Lifecycle
func (d *Daemon) CycleSession(agentType string) error
func (d *Daemon) SpawnWorker(issueID string) error
func (d *Daemon) ShutdownWorker(polecat string) error
```

## Heartbeat Loop

Every HeartbeatInterval:
1. Check Witness session (restart if cycle requested)
2. Check Refinery session (restart if cycle requested)
3. For each active polecat: assess progress, nudge if stuck
4. Query `bd ready` for new work, spawn up to max_workers


Digest: mol-deacon-patrol

Patrol 15: Nominal


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

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

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

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


Move disk 1: C → A

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


load-context

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

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


Digest: mol-deacon-patrol

Patrol complete: 2 mayor handoffs (not for deacon), all agents healthy, no orphans


gt-gastown-polecat-cal

gt-gastown-polecat-cal

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


Move disk 2: C → B

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


Add await-work and plugin-run steps to mol-refinery-patrol

## Context

The mol-refinery-patrol needs two additional steps:

### 1. await-work (Decision Point)

Not just 'wait for signal' but a crossroads:
- Check for pending signals (mail, nudge, human)
- Check plugin gates (any plugins need to run?)
- Check maintenance schedule (daily/weekly due?)
- Evaluate context and decide next action

Position: Between burn-or-loop and inbox-check (the loop point)

### 2. plugin-run (Like Deacon)

Refinery needs plugin support for:
- **Monitors**: Flag PRs touching sensitive code
- **Gates**: Block merges under certain conditions
- **Schedulers**: Reorder queue based on priority/urgency
- **Maintenance**: Weekly cleanup, audits, stats
- **Audits**: Log merge statistics, track patterns

Position: After queue-scan, before process-branch

## Implementation

Update RefineryPatrolMolecule() in builtin_molecules.go to include:
- await-work step with decision tree
- plugin-run step with gate types

## Related
- gt-7920 (original mol-refinery-patrol)
- docs/deacon-plugins.md (existing plugin model)


Digest: mol-deacon-patrol

Patrol 18: all quiet


Git safety audit module

Port git_audit.py safety checks to Go.

## Purpose

Before destroying polecat clones, verify no code is at risk.

## Checks

1. Uncommitted changes (staged and unstaged)
2. Unpushed commits
3. Git stashes
4. Local-only branches (not tracking remote)

## Beads-Only Classification

Some files are safe to discard:
- .beads/*
- .claude/settings.json

Changes only affecting these = "beads-only" = safe to destroy.

## Interface

```go
type GitAuditResult struct {
    Polecat              string
    Path                 string
    UncommittedFiles     []string
    UncommittedIsBeadsOnly bool
    UnpushedCommits      int
    Stashes              []StashInfo
    StashesAreBeadsOnly  bool
    LocalBranches        []string
    Error                error
}

func (r *GitAuditResult) HasCodeAtRisk() bool

func AuditPolecat(name string, path string) *GitAuditResult
func AuditPolecats(polecats []PolecatInfo) []*GitAuditResult
```

## Reference

PGT: swarm/git_audit.py


test-new-swarm-1767338498


Digest: mol-deacon-patrol

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


Move disk 1: A → B

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


Witness template uses non-existent --assignee flag on bd mol wisp

## Bug

The witness.md.tmpl template uses an invalid flag:

```
bd mol wisp mol-witness-patrol --assignee={{ .RigName }}/witness
```

But `bd mol wisp` does NOT support the `--assignee` flag (only `--dry-run`, `--var`, and global flags).

## Location

`internal/templates/roles/witness.md.tmpl:142`

## Fix

Use the two-step pattern like the deacon template does:

```bash
bd mol wisp create mol-witness-patrol
bd update <wisp-id> --status=pinned --assignee={{ .RigName }}/witness
```

## Impact

Witness agents following the template will get a CLI error when trying to create patrol wisps.


Digest: mol-deacon-patrol

Patrol 9: healthy


Implement gt mol status command

Show what's on an agent's hook.

```bash
gt mol status [target]
```

Output:
- What's slung (molecule name, associated issue)
- Current phase and progress
- Whether it's a wisp
- Next action hint

If no target, shows current agent's status.

Acceptance:
- [ ] Read pinned bead attachment
- [ ] Display molecule/issue info
- [ ] Show phase progress
- [ ] Indicate wisp vs durable


Polecat prompting: gt mq submit on completion

Update Polecat CLAUDE.md prompting to:

1. On task completion, run: gt mq submit --issue <id>
2. This creates a merge-request bead in the queue
3. Engineer will process it

The Polecat self-reports completion to the merge queue.


Digest: mol-deacon-patrol

Patrol 4: gastown+beads witnesses/refineries healthy


check-refinery

Ensure the refinery is alive and processing merge requests.

Needs: inbox-check


Digest: mol-deacon-patrol

Patrol 126: All healthy


gt shutdown should fully cleanup polecats (worktrees, branches, inboxes)

Current gt shutdown only kills tmux sessions but leaves:

1. Git worktrees in polecats/ directory
2. Polecat branches (polecat/<name>)
3. Inbox messages
4. Beads assignee state

This causes stale polecats to be reused on next startup.

## Expected Behavior

gt shutdown should:
1. Kill all polecat tmux sessions (current behavior)
2. For each polecat with StateIdle or StateDone:
   - Remove worktree
   - Delete branch
   - Clear inbox
3. For polecats with uncommitted work:
   - REFUSE to clean up
   - Report which polecats have uncommitted changes
   - Require --force or --nuclear to proceed

## Current Code

- start.go:runImmediateShutdown() only calls t.KillSession()
- Witness cleanupPolecat() does full cleanup but isn't called by shutdown

## Fix

Either:
1. Call Witness cleanup for each polecat during shutdown
2. OR add rig.ShutdownPolecats() that does the full cleanup


Digest: mol-deacon-patrol

Patrol 13: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol 14: All healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Move disk 1: A → B

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


Merge: nux-mjw18ii8

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


Move disk 2: A → C

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


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.


Digest: mol-deacon-patrol

Patrol 17: routine


gt swarm is implemented but undocumented

internal/swarm/ package is fully implemented with:
- gt swarm create
- gt swarm status
- gt swarm list
- gt swarm land
- gt swarm cancel
- gt swarm start

But no documentation exists for it:
- Not in README
- Not in architecture.md (uses different terminology)
- Not in any role prompts

Either:
1. Document gt swarm as the canonical mechanism
2. Or deprecate it in favor of gt sling

Related to gt-6n13 (competing molecule mechanisms)


Digest: mol-deacon-patrol

Cycle 19


queue: shared storage work queues

## queue: Shared Storage Work Queues

Work queue with shared storage (single copy, first-to-claim).

## Pattern Clarification

**Queue is a MAILBOX pattern** (pull-based):
- Workers poll shared queue
- First to claim gets the work
- Worker decides when to check

**This is DIFFERENT from Dog dispatch** (push-based):
- `gt sling <work> deacon/dogs` pushes to hook
- GUPP fires immediately
- Deacon decides when to assign

| Pattern | Mechanism | Initiative |
|---------|-----------|------------|
| `queue:` | Poll mailbox, claim | Worker pulls |
| Dog sling | Hook assignment | Deacon pushes |

## Use Cases for queue:

1. **Batch cleanup tasks** - Multiple agents can help, order does not matter
2. **Overflow work** - When primary handler is busy
3. **Opportunistic tasks** - Agents check between other work

## Deliverables

1. Parse queue:name syntax in router
2. Shared storage model:
   - Single message copy (NOT fan-out)
   - Stored in queue-specific location
   - Multiple agents can see it
3. Queue configuration in ~/gt/config/queues.json
4. Queue inbox command: gt mail queue <name>
5. Claim semantics: `gt mail claim <msg-id>` marks as claimed

## Key Difference from list:
- list: creates N copies (N obligations)
- queue: creates 1 copy (1 obligation, first-to-claim)

## Dependencies
- Config directory (gt-i6jvc) ✅ closed

## Acceptance
- queue:cleanup creates single message
- Multiple agents can view queue
- Claim marks message as taken
- Message invisible to others after claim


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

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

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

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

## Second-Order Monitoring

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

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


Digest: mol-deacon-patrol

Patrol 14: Quiet


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, inbox empty, 1 dog idle


Digest: mol-deacon-patrol

Patrol 3: Routine


Digest: mol-deacon-patrol

Patrol 10: all healthy


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


Deacon health pings clear agent backoff

Deacon's periodic health checks also clear patrol agent backoff.

## Current Flow (mol-deacon-patrol)

Deacon already pings witnesses/refineries for health checks. These pings should:
1. Verify agent is alive
2. Clear their backoff as side effect

## Implementation

In mol-deacon-patrol health-scan step:
- gt nudge <rig>/witness 'HEALTH_CHECK from deacon'
- gt nudge <rig>/refinery 'HEALTH_CHECK from deacon'

Receiving agent:
- Responds to prove liveness
- Resets backoff to base interval

## Ping Interval

Deacon patrols every ~1-2 minutes. This ensures:
- Maximum backoff is bounded by deacon ping interval
- Even if daemon misses activity, deacon catches up


Digest: mol-deacon-patrol

Patrol 14: all clear


mol-polecat-arm: Add nudge_text variable definition

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

## Current variables section

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

## Missing

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

## Usage in formula

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

## Fix

Add nudge_text to the variables section with a sensible default.


Pinned beads architecture implementation

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

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


Move disk 1: B → C

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


Digest: mol-deacon-patrol

Patrol 21: all healthy, no lifecycle requests, 4 in-progress issues noted, handoff triggered at threshold


Digest: mol-deacon-patrol

Patrol 11: Routine


Dynamically discover rigs in checkStaleAgents

In internal/daemon/lifecycle.go:734-735, the rig list is hardcoded:

```go
// Add rig-specific agents (witness, refinery) for known rigs
// For now, we check gastown - could be expanded to discover rigs dynamically
rigs := []string{"gastown", "beads"}
```

This should use gt rigs or similar to dynamically discover configured rigs instead of hardcoding.

Affects: checkStaleAgents() which checks for dead agents that stopped updating their bead state.


Move disk 3: A → B

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


Ephemeral rig support for ad-hoc batch work

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

## Use Case

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

## Interface

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

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

## Directory Structure

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

## Cleanup Trigger

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

## Note

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

## Reference

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


Move disk 1: B → C

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


Merge: gt-ih0s

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


Activity Feed TUI

Terminal UI for browsing Gas Town activity. Shows hierarchical view of rigs, workers, and their current state. Features: live updates, expandable details, molecule progress (step X of Y). Built with bubbletea/lipgloss. Design doc: history/activity-feed-tui-design.md


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


Merge: morsov-1766966180179

branch: polecat/morsov-1766966180179
target: main
source_issue: morsov-1766966180179
rig: gastown


Digest: mol-deacon-patrol

Patrol 120: All healthy - session complete


Digest: mol-deacon-patrol

Patrol 13: all healthy


Witness role template + CLAUDE.md

Create the Witness agent's role context:

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

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

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


gt done: Command doesn't exist but documented in polecat CLAUDE.md

The polecat CLAUDE.md documents 'gt done' as the command to signal work is ready for merge queue, but running it gives 'unknown command'. Either implement the command or update the documentation.


Digest: mol-deacon-patrol

Cycle 197: Nominal


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


Overseer Crew: User-managed persistent workspaces

## Overview

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

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

## Directory Structure

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

## Key Differences from Polecats

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

## CLI Commands

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

## Design Notes

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

## Background

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


Role templates: rename 'Dependency Trap' to 'Gotchas when Filing Beads'

The 'Dependency Trap' heading is too specific. Rename to something like 'Gotchas when Filing Beads' or 'Beads Filing Tips'. Applies to all role templates (polecat, crew, mayor, witness, refinery, deacon).


Direct formula-to-wisp instantiation (skip proto)

For massive ephemeral workflows (e.g., million-step Towers of Hanoi), allow:

bd wisp towers-of-hanoi --var disks=20

This would cook + wisp in one step, never materializing the proto. Useful when:
- The proto would be huge (1M+ steps)
- The work is ephemeral (wisp, not mol)
- You don't need the intermediate artifact

Implementation: streaming cook that emits directly to wisp storage.

Related: towers-of-hanoi.formula.yaml demonstrates the use case.


Move disk 2: C → B

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


Move disk 1: B → C

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


mol-refinery-patrol

Merge queue processor patrol loop.

The Refinery is the Engineer in the engine room. You process polecat branches, merging them to main one at a time with sequential rebasing.

**The Scotty Test**: Before proceeding past any failure, ask yourself: "Would Scotty walk past a warp core leak because it existed before his shift?"

## Merge Flow

The Refinery receives MERGE_READY mail from Witnesses when polecats complete work:

```
Witness                    Refinery                      Git
   │                          │                           │
   │ MERGE_READY              │                           │
   │─────────────────────────>│                           │
   │                          │                           │
   │                    (verify branch)                   │
   │                          │ fetch & rebase            │
   │                          │──────────────────────────>│
   │                          │                           │
   │                    (run tests)                       │
   │                          │                           │
   │                    (if pass)                         │
   │                          │ merge & push              │
   │                          │──────────────────────────>│
   │                          │                           │
   │ MERGED                   │                           │
   │<─────────────────────────│                           │
   │                          │                           │
```

After successful merge, Refinery sends MERGED mail back to Witness so it can
complete cleanup (nuke the polecat worktree).


Move disk 1: A → B

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


Digest: mol-deacon-patrol

Patrol cycle 18: all healthy


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


Track spawned sessions in DogDispatchInfo

Minor TODO in internal/cmd/sling.go:1002:

```go
return &DogDispatchInfo{
    DogName:  targetDog.Name,
    AgentID:  agentID,
    Pane:     pane,
    Spawned:  false, // TODO: track if we spawned a new session
}, nil
```

The Spawned field is always false. Should track if DispatchToDog actually spawned a new session vs reused an existing one.

Low priority - the information could be useful for logging/debugging but doesn't affect functionality.


Digest: mol-deacon-patrol

Patrol 144 complete: All agents healthy


Move disk 1: C → A

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


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)


Molecule Phase Terminology Documentation

Document the three-phase molecule lifecycle with consistent terminology:

## The Phases (States of Matter)

| Phase | State | Nature |
|-------|-------|--------|
| **Proto** | Solid/Crystal | Frozen template, static definition in catalog |
| **Mol** | Liquid | Reified instance, malleable, tracked in git (durable) |
| **Wisp** | Gas | Evaporates after squash, ephemeral orchestration |

## Documentation Gaps Identified

### High Priority
1. Update vision.md Steam Engine metaphor to use proto/mol/wisp terminology
2. Add lifecycle diagram: Proto → bond → Mol or Wisp → squash → Digest
3. Document Go types for phases (ProtoMolecule, etc.)
4. Document .beads-ephemeral/ structure and purpose

### Medium Priority
5. Update CLAUDE.md files (polecat, witness, refinery) with molecule workflow
6. Document bd mol bond/squash/burn CLI API with examples
7. Add polecat guide: Executing molecules and generating summaries

### Low Priority
8. Add terminology glossary to architecture.md
9. Create troubleshooting playbook for stuck molecules
10. Add reference diagrams for state transitions

## Current State
- architecture.md has good molecule basics but uses inconsistent terminology
- vision.md has Steam Engine metaphor (proto=fuel, wisp=steam, digest=distillate)
- molecules.md has detailed reference but needs phase clarity
- builtin_molecules.go has 8 molecules but no phase documentation in code


Consider splitting large files (800+ lines)

Several files are getting large and may benefit from splitting:
- internal/beads/beads.go (990 lines)
- internal/cmd/molecule.go (981 lines)
- internal/refinery/manager.go (934 lines)
- internal/beads/beads_test.go (883 lines)
- internal/cmd/polecat.go (836 lines)
- internal/witness/manager.go (808 lines)
- internal/cmd/mail.go (804 lines)

For .go files, consider extracting logical subsystems. For test files, this is lower priority.


Implement handoffs using pinned beads

Replace the current mail-based handoff system with pinned beads.

## Current Problem

Handoff messages get closed before the successor can read them because:
1. `gt mail read` auto-acks (closes) messages
2. `bd mail inbox` only shows open messages
3. Successor sees empty inbox

## Solution

Use pinned beads for handoffs:
- One pinned bead per role: `mayor-handoff`, `<rig>-refinery-handoff`, etc.
- Predecessor updates the content before cycling
- Successor reads on startup via `gt prime`
- Never closes - always available

## Implementation

### 1. Create handoff beads on first cycle
- `bd create --title='Mayor Handoff' --type=task --status=pinned --assignee=mayor`
- Store ID in role config or use well-known naming convention

### 2. Update gt handoff command
- Instead of `bd mail send`, update the pinned handoff bead
- `bd update <handoff-id> --description='...handoff content...'`

### 3. Update gt prime
- Read the role's handoff bead
- Display content to successor

### 4. Compression/reset
- `gt rig reset` clears handoff content
- Or manual: `bd update <handoff-id> --description=''`

## Dependencies

Requires beads-6v2 (StatusPinned) to be implemented first.


Digest: mol-deacon-patrol

Patrol 3: nux exited (wrong-rig escalation), 11 sessions, all core healthy


Test Epic: GGT MVP Validation


Move disk 2: B → A

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


Digest: mol-deacon-patrol

Patrol 9: all healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

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

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 1: All healthy, no messages, no orphans


Digest: mol-deacon-patrol

Patrol 20: Final patrol, all healthy, handoff


Digest: mol-deacon-patrol

Patrol cycle 4: routine check, all nominal


Merge: furiosa-dogs

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


Digest: mol-deacon-patrol

Patrol cycle 2: all healthy, no incidents


Merge: dex-mjufugxv

branch: polecat/dex-mjufugxv
target: main
source_issue: dex-mjufugxv
rig: gastown