Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

This molecule is bonded dynamically by mol-witness-patrol's survey-workers step.
Each polecat being monitored gets one arm that runs in parallel with other arms.

## Variables

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

## Step: capture
Capture recent tmux output for toast.

```bash
tmux capture-pane -t gt-gastown-toast -p | tail -50
```

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

## Step: assess
Categorize polecat state based on captured output.

States:
- **working**: Recent tool calls, active processing
- **idle**: At prompt, no recent activity
- **error**: Showing errors or stack traces
- **requesting_shutdown**: Sent LIFECYCLE/Shutdown mail
- **done**: Showing completion indicators

Calculate: minutes since last activity.
Needs: capture

## Step: load-history
Read nudge history for toast from patrol state.

```
nudge_count = state.nudges[toast].count
last_nudge_time = state.nudges[toast].timestamp
```

This data was loaded by the parent patrol's load-state step and passed
to the arm via the bonding context.
Needs: assess

## Step: decide
Apply the nudge matrix to determine action for toast.

| State | Idle Time | Nudge Count | Action |
|-------|-----------|-------------|--------|
| working | any | any | none |
| idle | <10min | any | none |
| idle | 10-15min | 0 | nudge-1 (gentle) |
| idle | 15-20min | 1 | nudge-2 (direct) |
| idle | 20+min | 2 | nudge-3 (final) |
| idle | any | 3 | escalate |
| error | any | any | assess-severity |
| requesting_shutdown | any | any | pre-kill-verify |
| done | any | any | pre-kill-verify |

Nudge text:
1. "How's progress? Need any help?"
2. "Please wrap up soon. What's blocking you?"
3. "Final check. Will escalate in 5 min if no response."

Record decision and rationale.
Needs: load-history

## Step: execute
Take the decided action for toast.

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

**pre-kill-verify**:
```bash
cd polecats/toast
git status                    # Must be clean
git log origin/main..HEAD     # Check for unpushed
bd show <assigned-issue>      # Verify closed/deferred
```
If clean: kill session, remove worktree, delete branch
If dirty: record failure, retry next cycle

**escalate**:
```bash
gt mail send mayor/ -s "Escalation: toast stuck" -m "..."
```

**none**: No action needed.

Record: action taken, result, updated nudge count.
Needs: decide

## Output

The arm completes with:
- action_taken: none | nudge-1 | nudge-2 | nudge-3 | killed | escalated
- result: success | failed | pending
- updated_state: New nudge count and timestamp for toast

This data feeds back to the parent patrol's aggregate step.
---
bonded_from: mol-polecat-arm
bonded_to: gt-wsjg
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Fetch remote and identify polecat branches waiting.

```bash
git fetch origin
git branch -r | grep polecat
gt refinery queue <rig>
```

If queue empty, skip to context-check step.
Track branch list for this cycle.

instantiated_from: mol-refinery-patrol
step: queue-scan


Digest: mol-deacon-patrol

Patrol cycle 8: all nominal


Polecat doesn't auto-start after spawn inject - requires manual nudge

## Problem

After `gt spawn --issue <id> --create`, the polecat session shows Claude Code started with the injected prompt, but Claude doesn't begin processing. The prompt just sits there until manually nudged.

## Evidence

```
$ gt spawn --issue gt-rixa --rig gastown --create
...
✓ Session started. Attach with: gt session at gastown/furiosa
  Polecat nudged to start working
  Witness notified to monitor startup
```

Session shows:
```
> You have a work assignment. Run 'gt mail inbox' to see it, then start
  working on issue gt-rixa.

  ⏵⏵ bypass permissions on (shift+tab to cycle)
```

But Claude doesn't respond. Manual nudge required:
```
$ gt nudge gt-gastown-furiosa "Please start working..."
```

After nudge, polecat immediately starts working correctly.

## Hypothesis

The spawn inject happens before Claude Code is fully initialized. The text arrives in the input buffer, but Claude hasn't started listening yet. By the time Claude starts, the input has already been 'consumed' as initial prompt text but not submitted.

## Resolution Plan

This will be solved by the **polecat molecule workflow** (mol-polecat-work), which provides structured lifecycle management. The molecule approach handles startup, work, and shutdown as discrete steps with proper state tracking.

**Blocked on**: beads/crew/dave completing ephemeral molecules (bd mol bond, ephemeral beads repo).

## Workaround

For now, use `gt nudge` if a polecat doesn't start within ~30 seconds of spawn.


gt sling reports hook occupied but bd hook shows empty

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


Digest: mol-deacon-patrol

Patrol 13: all healthy


Formula versioning and migration strategy

Define how formula versions are managed:
- What does the version field mean? Semver? Integer?
- When a formula changes, what happens to existing protos?
- Do protos track their source formula version?
- Migration path: old proto + new formula = ?
- Backwards compatibility guarantees (if any)

Deferred: post-launch polish


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.


Digest: mol-deacon-patrol

Patrol 13: All healthy


gt nudge doesn't work with crew addresses

## Bug

`gt nudge beads/crew/dave "message"` fails because it uses the polecat session manager which produces wrong session names.

## Expected
Session name: `gt-beads-crew-dave` (hyphen)

## Actual
Session name: `gt-beads-crew/dave` (slash, from polecat manager)

## Root Cause

In nudge.go line 46-57, parseAddress returns polecatName=`crew/dave`, then SessionName keeps the slash.

## Fix

Detect `crew/` prefix and use crewSessionName() instead.


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

Patrol 13: quiet


Digest: mol-deacon-patrol

Patrol 5: Quiet


Add live polling and updates

Implement live polling (500ms default) for activity updates. Merge new events into view without flickering. Show connection status indicator. Handle daemon disconnects gracefully.


Wire up created_by field for beads issues

## Goal
Add actor/creator attribution to beads issues created by gastown.

## Done
- Added CreatedBy field to Issue struct
- Added Actor field to CreateOptions
- Pass --actor to bd create

## Remaining
1. Add ActorString() method to RoleInfo
2. Update beads.Create() callers to pass Actor
3. Update direct bd create exec calls to add --actor

## Context
Beads GH #748 added created_by field. Gastown needs to populate it.


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.


Digest: mol-deacon-patrol

Patrol cycle 20: final before handoff


Digest: mol-deacon-patrol

Patrol 18


Merge: gt-caih

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


Digest: mol-deacon-patrol

Patrol 17: Quiet


Digest: mol-deacon-patrol

Patrol 2: archived stale Mayor handoffs, all agents healthy


Patrols: Cyclic molecules for autonomous maintenance

## Vision

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

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

## Core Concepts

### 1. Cyclic Molecules

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

Patrols have a loop_to field specifying where to restart.

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

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

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

### 3. The Beacon

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

Without beacon, nothing proactive happens.

### 4. Session Reset as Patrol Step

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

### 5. Multi-Role Patrols

Each supervisor has its own patrol:

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

### 6. Cadence Tiers

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

### 7. Best-Effort Scheduling

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

## Open Questions

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

## Related

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

## Metaphor

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

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


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.


gt crew remove: Remove crew workspace

Implement 'gt crew remove <name> [--force]' command:
- Check for uncommitted changes, unpushed commits
- Warn and require --force if dirty
- Kill any running session
- Remove directory
- Unregister from mail


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


Port Gas Town to Go

Complete rewrite of Gas Town in Go for improved performance and single-binary distribution.

## Goals
- Single installable binary (gt)
- All Python functionality ported
- Federation support built-in
- Improved performance

## Phases
1. Core infrastructure (config, workspace, git wrapper)
2. Rig & polecat management
3. Session & tmux operations
4. Mail system
5. CLI commands
6. TUI (optional)


bd create --dedup: semantic deduplication before issue creation

Before creating issue, check for semantic duplicates using AI similarity.

**From VC**: internal/deduplication/ - AI-powered batch comparison. ~300 lines.
VC had issue pollution problem: 438 issues with ~350+ spam because no early dedup.

**Gas Town implementation**: CLI flag on bd create:
```bash
bd create --dedup --title="Fix auth bug" --description="..."
```

Checks recent issues (7-day window) with AI similarity. If confidence >0.85, warns or blocks.

**Value**: Prevents pollution from parallel workers discovering same issues.

**VC lesson**: 115 issues filed in single day (Nov 2) because supervisor over-discovered without dedup. Rate limiting + dedup are essential.


gt orphans: Find lost polecat work

Add a command to find orphaned commits that were never merged to main.

## Problem
Polecat work can get lost when:
- Session killed before merge
- Refinery fails to process
- Network issues during push

## Solution
Add `gt orphans` command that:
1. Uses `git fsck --unreachable` to find dangling commits
2. Filters to recent commits (default: 7 days, configurable)
3. Excludes stash/index entries (WIP on, index on)
4. Shows commit details and suggests recovery

## Usage
```
gt orphans              # Last 7 days
gt orphans --days=14    # Last 2 weeks
gt orphans --recover    # Interactive cherry-pick
```

## Found orphans (Dec 16-20, 2025)
- 3b146c11: Fix mail read auto-ack and add Mayor startup directive
- b6fdc561: Add persistent theme config and fix crew session theming
- 97aba756: Unify gt prime to call bd prime and mail check
- ce769ca5: Add mol-bootstrap molecule for Gas Town installation
- b2219de7: Add bootstrap documentation for new Gas Town installations
- bc82348: feat: Add gt done command (already recovered)


Test: New Router

Testing bd create for mail


Digest: mol-deacon-patrol

P20: stable - handoff after 20 patrols


gt mail inbox doesn't find crew worker mail - identity mismatch

## Problem

Crew workers don't see their handoff messages when running `gt mail inbox` from their working directory.

## Root Cause

gt derives identity from cwd path, but crew workers have a different path structure:
- **cwd**: `/Users/stevey/gt/beads/crew/dave`
- **gt derives**: `beads/crew/dave` (wrong)
- **should be**: `beads/dave` (crew workers use `rig/name` format)

Messages sent to `beads/dave` don't show up because gt is looking for `beads/crew/dave`.

## Workaround

Use explicit identity flag:
```bash
gt mail inbox --identity "beads/dave"
```

## Fix

Identity detection in gt should handle crew/ subdirectory:
- Path `<rig>/crew/<name>` should derive identity as `<rig>/<name>`
- This matches how polecats work: `<rig>/polecats/<name>` → `<rig>/<name>`

## Affected

All crew workers in all rigs.


Merge: gt-h6eq.6

branch: polecat/keeper
target: main
source_issue: gt-h6eq.6
rig: gastown


Deprecate hook files, use pinned beads for propulsion

## Problem

Hook files were "deprecated" via comments but NOT eradicated. The code is all still there and actively used.

## Current State (NOT Done)

**Live hook file exists:**
- `/Users/stevey/gt/deacon/.beads/hook-deacon.json`

**Code still calling hook functions:**
- `resume.go:151` - WriteSlungWork
- `park.go:114` - ReadHook
- `spawn.go:407` - WriteSlungWork
- `molecule_step.go:293` - WriteSlungWork
- `molecule_step.go:368` - BurnHook

**Hook infrastructure still exists:**
- `internal/wisp/io.go` - All hook I/O functions
- `internal/wisp/types.go` - SlungWork, Wisp types, constants
- `.beads/.gitignore` - hook-*.json pattern

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

## Goal: Total Eradication

1. Remove ALL hook file code from callers
2. Delete hook functions from internal/wisp/
3. Delete hook types and constants
4. Remove gitignore patterns
5. Delete any live hook files, convert to pinned beads
6. Update all documentation
7. Verify propulsion cycle works with pinned beads only


Digest: mol-deacon-patrol

Patrol: no callbacks, no polecats, all agents healthy, cleaned 2 orphan processes + 2 stale locks


Digest: mol-deacon-patrol

Patrol 13: routine


Plugin/molecule catalog integration design

Two currently independent systems:
1. Disk-based plugins (~~/gt/plugins/) - Deacon patrol extensions
2. Molecule catalog (protos in beads) - bd pour/wisp/bond

Investigate integration points:
- User-contributed molecules bonded to catalog
- Dynamic molecule attachment during execution (e.g., 'attach security sniffer because we noticed condition X')
- How plugins could contribute protos
- How protos could trigger plugins

Not blocking launch. Future design investigation.


Patrol lifecycle integration test

Verify patrol runs 3+ cycles without wisp accumulation. bd wisp list should show <5 wisps. Context cycles cleanly produce handoff mail. Test with Deacon patrol.


Merge: gt-unrd

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


Competing molecule instantiation mechanisms need resolution

Documentation describes 4 different molecule instantiation methods:
1. bd mol bond (beads-based, in molecules.md)
2. gt sling (proposed in sling-design.md)
3. gt swarm (implemented in code)
4. gt molecule instantiate (in architecture.md)

Role prompts use different methods:
- Deacon: bd mol spawn
- Refinery: gt mol bond
- Polecat: bd mol current

Need to:
1. Decide canonical mechanism
2. Update all role prompts to use it
3. Remove/deprecate alternatives
4. Update architecture docs


Town & Rig Management: install, doctor, federation

Reify the Gas Town installation as a first-class concept.

## Goals
- Installable: gt install [path] creates complete installation
- Diagnosable: gt doctor checks and fixes issues
- Federable: Clone town to VMs with central control

## Architecture Reference

See docs/architecture.md for full design, especially:
- Directory structure (Town Level / Rig Level sections)
- Configuration (town.json, rigs.json schemas)
- Key design decisions (visible config dir, decentralized agents)


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 5: Routine


Phase 4: Deacon Patrol Loop

$(cat /tmp/phase4.md)


Digest: mol-deacon-patrol

Patrol #19


Digest: mol-deacon-patrol

Patrol #15: Stable


Template and Formula Distribution: Embed in binary, detect staleness

## Problem

Two types of Gas Town infrastructure live in `.beads/` but have unclear distribution:

1. **Role templates** (`*.md.tmpl`) - embedded in binary, rendered to CLAUDE.md on setup
2. **Patrol formulas** (`*.formula.json`) - currently just exist, no clear seeding path

When `gt` is rebuilt with updated templates/formulas, existing installations don't auto-update.

## Current State

- Templates: embedded via `//go:embed`, written on `gt install`/`gt rig init`
- Formulas: exist in `.beads/formulas/` but no seeding mechanism
- `bd init` creates empty structure (correct - bd shouldn't know Gas Town)
- No staleness detection for either

## Proposed Solution

### 1. Embed formulas in `gt` binary

```go
//go:embed formulas/*.formula.json
var formulaFS embed.FS
```

### 2. Seed formulas during setup

`gt install` and `gt rig init` write embedded formulas to `.beads/formulas/`.

### 3. Hash-based staleness detection

`gt doctor` checks:
- CLAUDE.md hash vs embedded template hash
- Formula files hash vs embedded formula hash

If stale → warn. `gt doctor --fix` refreshes.

### 4. Keep bd/gt boundary clean

- `bd` stays generic: `bd cook <path>` takes any formula path
- `gt` knows where formulas live, handles distribution
- Patrol formulas are Gas Town infrastructure, not beads concern

## Tasks

1. Move formulas to embedded FS in gt binary
2. Add formula seeding to `gt install` / `gt rig init`
3. Add hash storage for templates and formulas
4. Add staleness detection to `gt doctor`
5. Add `--fix` flag to refresh stale files


Digest: mol-deacon-patrol

Patrol complete: 0 mail, Mayor+2 witnesses+2 refineries healthy, 3 polecats working (gastown), no orphans, gc N/A


context-check

Assess own context usage. If high, prepare for handoff.


Test Patrol Parent

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

Original description:
Test parent for Christmas Ornament pattern


README: Update Install section for homebrew/npm

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

But users will install via homebrew or npm. Update to show:
  brew install gastown
  # or
  npm install -g @anthropic/gastown

Also add prerequisites section (tmux, Claude Code CLI).


Deacon patrol molecules stored in wrong beads location

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


Digest: mol-deacon-patrol

Patrol 6: All healthy


Digest: mol-deacon-patrol

Patrol 15


Digest: mol-deacon-patrol

Patrol 14: all healthy


bd cook command: Formula to Proto

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

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

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

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

**Beads issue: bd-wa2l**


Polecat template: clarify work status commands (bd list vs gt mol status)

Template shows 'bd list --status=in_progress' for checking work, but polecats should probably use 'gt mol status' instead (or in addition). Clarify the right approach for polecats to check their current work assignment.


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

This molecule is bonded dynamically by mol-witness-patrol's survey-workers step.
Each polecat being monitored gets one arm that runs in parallel with other arms.

## Variables

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

## Step: capture
Capture recent tmux output for toast.

```bash
tmux capture-pane -t gt-gastown-toast -p | tail -50
```

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

## Step: assess
Categorize polecat state based on captured output.

States:
- **working**: Recent tool calls, active processing
- **idle**: At prompt, no recent activity
- **error**: Showing errors or stack traces
- **requesting_shutdown**: Sent LIFECYCLE/Shutdown mail
- **done**: Showing completion indicators

Calculate: minutes since last activity.
Needs: capture

## Step: load-history
Read nudge history for toast from patrol state.

```
nudge_count = state.nudges[toast].count
last_nudge_time = state.nudges[toast].timestamp
```

This data was loaded by the parent patrol's load-state step and passed
to the arm via the bonding context.
Needs: assess

## Step: decide
Apply the nudge matrix to determine action for toast.

| State | Idle Time | Nudge Count | Action |
|-------|-----------|-------------|--------|
| working | any | any | none |
| idle | <10min | any | none |
| idle | 10-15min | 0 | nudge-1 (gentle) |
| idle | 15-20min | 1 | nudge-2 (direct) |
| idle | 20+min | 2 | nudge-3 (final) |
| idle | any | 3 | escalate |
| error | any | any | assess-severity |
| requesting_shutdown | any | any | pre-kill-verify |
| done | any | any | pre-kill-verify |

Nudge text:
1. "How's progress? Need any help?"
2. "Please wrap up soon. What's blocking you?"
3. "Final check. Will escalate in 5 min if no response."

Record decision and rationale.
Needs: load-history

## Step: execute
Take the decided action for toast.

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

**pre-kill-verify**:
```bash
cd polecats/toast
git status                    # Must be clean
git log origin/main..HEAD     # Check for unpushed
bd show <assigned-issue>      # Verify closed/deferred
```
If clean: kill session, remove worktree, delete branch
If dirty: record failure, retry next cycle

**escalate**:
```bash
gt mail send mayor/ -s "Escalation: toast stuck" -m "..."
```

**none**: No action needed.

Record: action taken, result, updated nudge count.
Needs: decide

## Output

The arm completes with:
- action_taken: none | nudge-1 | nudge-2 | nudge-3 | killed | escalated
- result: success | failed | pending
- updated_state: New nudge count and timestamp for toast

This data feeds back to the parent patrol's aggregate step.
---
bonded_from: mol-polecat-arm
bonded_to: gt-zq7f
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Digest: mol-deacon-patrol

Patrol 3: All healthy, no issues


Digest: mol-deacon-patrol

Patrol #16: Stable


TODO: Detect cycles in molecule dependency graph

molecule.go:302 has a TODO to detect cycles in the dependency graph. Currently, cyclical dependencies could cause issues.


Test message

Testing GGT mail via beads


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.


Digest: mol-deacon-patrol

Patrol 13


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.


load-context

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

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


Work assignment mail not received by polecat

When gt spawn sends a work assignment:

1. gt spawn says '✓ Work assignment sent'
2. Polecat runs 'gt mail inbox'
3. Shows '0 messages, 0 unread'

The work assignment mail never arrived at the polecat's inbox.

## Observed in session
- Spawned polecat dementus on gt-th7
- Polecat checked inbox: empty
- Polecat couldn't find issue (separate sync bug)

## Possible causes
- Mail routing issue for polecat addresses
- gt spawn not actually sending mail
- Mail sent to wrong address format

This was likely caused by stale beads in old polecats. With gt-9nf (fresh polecats), polecats now use shared rig beads via redirect file, eliminating sync issues. Mail routing uses town beads correctly.


Digest: mol-deacon-patrol

Patrol 17: Nominal


Digest: mol-deacon-patrol

Patrol 4: Routine, all healthy


Digest: mol-deacon-patrol

Patrol 6: All healthy


Digest: mol-deacon-patrol

Patrol 18: Quiet


Digest: mol-deacon-patrol

Patrol 3: All healthy, quiet


Digest: mol-deacon-patrol

Patrol cycle 4: routine check, all 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.


mol-deacon-patrol


Town Doctor molecule for harness health checks

Create a Town Doctor molecule that any Gas Town agent can run to diagnose and repair harness issues.

## Concept

Instead of just `gt doctor` as a CLI command with hardcoded checks, create a **molecule** (checklist workflow) that:
- Any agent (Mayor, Witness, Polecat) can instantiate
- Walks the agent through diagnostic steps
- Agent uses judgment to fix issues found
- Works as a structured troubleshooting guide

## Why a Molecule?

1. **Agent-driven**: The agent running it becomes "the doctor" temporarily
2. **Extensible**: Add new checks by updating the molecule, not code
3. **Contextual**: Agent can reason about issues, not just run scripts
4. **Self-healing**: Agent can fix problems it finds, not just report them

## Proposed Checks (molecule steps)

1. Verify harness structure (mayor/, .beads/, CLAUDE.md exist)
2. Validate config files (town.json, rigs.json parse correctly)
3. Check beads health (bd doctor, redirect validity)
4. Verify git state (clean working tree, proper remotes)
5. Check rig integrity (each registered rig exists, has config.json)
6. Validate agent clones (mayor/rig/, refinery/rig/ exist and are valid)
7. Check for orphaned worktrees/branches
8. Verify daemon state (if running)

## Integration

- `gt doctor` could instantiate the molecule for the current agent
- Or agent can run `bd ready` and pick up doctor tasks when prioritized
- Results logged to beads for audit trail

## Related

- gt-cr9: Harness Design & Documentation (completed)
- Molecules design in architecture.md


Digest: mol-deacon-patrol

Patrol OK: 0 polecats, 6 core sessions up, town quiet


Test7

Test with fixed workdir


Molecule execution support for polecats and crew

Enable agents to run bonded molecules through the full lifecycle.

## The Model
1. BOND - bd mol bond <template> --assignee <identity>
   Creates concrete issues, assigns root to agent

2. DISCOVER - Agent finds assigned molecules via bd ready
   DAG structure shows unblocked steps

3. WORK - Agent works through DAG, closing steps as done
   Can delegate children to lower-tier agents (haiku)

4. SURVIVE - Agent dies → beads persist
   Any agent resumes from DAG state

5. SUPERVISE - Witness monitors for stalled molecules
   Nudges owner or reassigns if dead

## Questions to Resolve
- Seed node terminology: seed vs root vs pole vs nucleus
- Assignee inheritance: single owner vs delegation model
- Stall detection: heartbeat vs activity timeout vs session monitoring

## Implementation
- Polecat startup: check for assigned molecules
- Polecat work loop: follow molecule DAG
- Witness: monitor molecule progress, detect stalls
- Mayor: can assign molecules, handle escalations

## Depends On
- beads: bd mol bond command (bd-usro in beads repo)


Test Patrol Parent

Test parent for Christmas Ornament pattern


Polecat CLAUDE.md update for hook execution

Update polecat role CLAUDE.md to include hook execution instructions.

## Key Additions

### Startup Protocol

```markdown
## Startup Protocol

When you wake up:

1. **Check your hook first**
   Run: gt prime
   This shows your assigned work.

2. **If hook has molecule**
   You are running a workflow. Execute the current step.
   When done: bd mol advance <mol-id>

3. **If hook has slung bead**
   Work on that specific issue.
   Claim it: bd update <id> --status=in_progress

4. **If hook empty**
   Wait for assignment via mail or spawn.
```

### Work Completion

```markdown
## Completing Work

When you finish your assigned issue:

1. Commit changes: git add && git commit -m "description (issue-id)"
2. Push branch: git push -u origin <branch>
3. Create MR bead: bd create "Merge: <issue-id>" --type=merge-request
4. Close issue: bd close <issue-id> --reason "Fixed in commit abc123"
5. Sync: bd sync
6. Signal done: gt mail send witness/ -s "LIFECYCLE: Done" -m "Completed <issue-id>"
```

### Exit States

```markdown
## Exit States

When finishing, signal your state:

- COMPLETED: Work done successfully
- BLOCKED: Cannot proceed, need help
- ESCALATE: Problem beyond your scope
- HANDOFF: Passing to successor
```

## File

templates/polecat/CLAUDE.md


Digest: mol-deacon-patrol

Patrol #12


mol-polecat-arm

Single polecat inspection and action cycle.

This molecule is bonded dynamically by mol-witness-patrol's survey-workers step.
Each polecat being monitored gets one arm.

## Variables

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

## Steps

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

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

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

### assess
Categorize polecat state.

States:
- **working**: Recent tool calls, active processing
- **idle**: At prompt, no recent activity
- **error**: Showing errors or stack traces
- **requesting_shutdown**: Sent LIFECYCLE/Shutdown mail
- **done**: Showing completion indicators

Calculate: minutes since last activity.
Needs: capture

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

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

Needs: assess

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

| State | Idle Time | Nudge Count | Action |
|-------|-----------|-------------|--------|
| working | any | any | none |
| idle | <10min | any | none |
| idle | 10-15min | 0 | nudge-1 (gentle) |
| idle | 15-20min | 1 | nudge-2 (direct) |
| idle | 20+min | 2 | nudge-3 (final) |
| idle | any | 3 | escalate |
| error | any | any | assess-severity |
| requesting_shutdown | any | any | pre-kill-verify |
| done | any | any | pre-kill-verify |

Nudge text:
1. "How's progress? Need any help?"
2. "Please wrap up soon. What's blocking you?"
3. "Final check. Will escalate in 5 min if no response."

Record decision and rationale.
Needs: load-history

### execute
Take the decided action.

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

**pre-kill-verify**:
```bash
cd polecats/{{polecat_name}}
git status                    # Must be clean
git log origin/main..HEAD     # Check for unpushed
bd show <assigned-issue>      # Verify closed/deferred
```
If clean: kill session, remove worktree, delete branch
If dirty: record failure, retry next cycle

**escalate**:
```bash
gt mail send mayor/ -s "Escalation: {{polecat_name}} stuck" -m "..."
```

**none**: No action needed.

Record: action taken, result, updated nudge count.
Needs: decide

## Output

The arm completes with:
- action_taken: none | nudge-1 | nudge-2 | nudge-3 | killed | escalated
- result: success | failed | pending
- updated_state: New nudge count and timestamp

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

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


Digest: mol-deacon-patrol

Patrol 8: all clear, handing off for fresh context


Batch wisp squashing in Deacon maintenance

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

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


Digest: mol-deacon-patrol

Patrol 18: clear


Test merge request

branch: polecat/Test/gt-test
target: main
source_issue: gt-test
worker: TestWorker
rig: gastown


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

Patrol 18: All healthy


Update swarm terminology to streams

Gas Town moved from batch swarms to continuous streaming of polecats. Update:
- Docs and designs
- Code comments
- CLI flags (remove --swarm if present, or reframe)
- Variable/function names where appropriate

Streams reflect the reality: polecats flow continuously, not in discrete batches.


CLI: mayor commands (start, attach, stop, status)

Mayor management CLI commands.

## Commands

### gt mayor start
```
gt mayor start [--continue] [--agent AGENT]
```
- --continue: Resume from previous session (check for handoff mail)
- --agent: claude (default) or other agent type

### gt mayor attach
```
gt mayor attach
```
Attach to running Mayor session.

### gt mayor stop
```
gt mayor stop [--grace-period N]
```
Stop Mayor session with optional grace period.

### gt mayor status
```
gt mayor status [--json]
```
Show Mayor running status.

## Session Management
Session name: `gt-mayor`
Working directory: `<town>/mayor/rig/` or `<town>/mayor/`

## Implementation
Similar to session commands but for special Mayor context.

```go
func getMayorPath(townRoot string) string {
    return filepath.Join(townRoot, "mayor")
}

func getMayorSessionName() string {
    return "gt-mayor"
}
```

## New File
internal/cmd/mayor.go

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

## Acceptance Criteria
- [ ] gt mayor start launches Mayor session
- [ ] gt mayor attach works
- [ ] gt mayor stop with grace period
- [ ] gt mayor status shows running state


Chemistry UX commands from Beads

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

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


Review dimensions as aspects

Refactor code-review molecule to use aspects for each review dimension (security, performance, accessibility). More flexible than current pluggable molecule approach - add/remove checks by composing aspects.


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


bd pin command fails: invalid field for update: pinned

In beads v0.32.0, `bd pin <id>` fails with 'invalid field for update: pinned'. The pinned field exists in the schema but update logic doesn't handle it.

Repro:
```
bd create 'test issue'
bd pin <id>
# Error: invalid field for update: pinned
```

Expected: Issue should be pinned.

This blocks gt mail send --pinned from working.


MQ config schema: merge_queue section in rig config.json

Define and implement merge_queue configuration in rig config.

Schema:
{
  "merge_queue": {
    "enabled": true,
    "target_branch": "main",
    "integration_branches": true,
    "on_conflict": "assign_back",  // or "auto_rebase"
    "run_tests": true,
    "test_command": "go test ./...",
    "delete_merged_branches": true,
    "retry_flaky_tests": 1,
    "poll_interval": "30s",
    "max_concurrent": 1
  }
}

Implement:
- Config loading in rig package
- Default values
- Validation

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


Digest: mol-deacon-patrol

Patrol 7: all quiet


Test Patrol Parent

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

Original description:
Test parent for Christmas Ornament pattern


Track operational stats as entity/audit beads

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

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

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

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


Digest: mol-deacon-patrol

Patrol 4: routine, all healthy


Daemon: Implement exponential backoff based on activity file

Modify daemon heartbeat logic to use exponential backoff when idle.

Read ~/gt/daemon/activity.json on each heartbeat.
Compute idle duration: time.Since(activity.Timestamp)
Adjust next ticker interval based on idle duration:

| Idle Duration | Next Heartbeat |
|---------------|----------------|
| 0-5 min       | 5 min (base)   |
| 5-15 min      | 10 min         |
| 15-45 min     | 30 min         |
| 45+ min       | 60 min (max)   |

Implementation:
1. Add activity file reading to daemon heartbeat
2. Replace fixed ticker with dynamic interval calculation
3. Reset to base interval when activity is fresh

No counter tracking needed - pure discovery from single timestamp.

CROSS-RIG DEPENDENCY: Also requires beads:bd-v8ku (assigned to beads/crew/dave)


Digest: mol-deacon-patrol

Patrol 19: All healthy


Digest: mol-deacon-patrol

Patrol 17: All clear


Digest: mol-deacon-patrol

Patrol #12: Stable


Merge: gt-3x1

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


Merge: gt-3x0z.1

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


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

## Problem

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

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

## Current State

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

## Target State

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

## Benefits

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

## Implementation

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


Fanout gate: waits-for children aggregation

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

## Current State

Formulas already use this pattern informally:

    step: aggregate
    waits_for: "all-children"

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

## Proposed Syntax

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

Or simpler:

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

## Semantics

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

## Use Cases

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

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

## Relationship to gate

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

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

But dedicated syntax is cleaner for this common pattern.

## Dependencies

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


Digest: mol-deacon-patrol

Patrol 5: All green


Remove gt context --usage estimation

The external context estimation approach doesn't work:
- tmux scrollback trick breaks with --cycle
- Can't see actual context usage from outside
- Only the agent knows its internal state

Remove or deprecate:
- gt context --usage flag
- Any external context monitoring logic

Document why in comments: 'Context management is agent-initiated, not externally monitored.
See self-check guidance in role templates.'

This is P3 because it's cleanup - the feature just doesn't work, not actively harmful.


Digest: mol-deacon-patrol

Patrol 4: All clear


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Digest: mol-deacon-patrol

Patrol 17: All healthy


gt up: set BD_ACTOR env var when spawning agents

When gt spawns agents (polecats, crew, patrol roles), it should set BD_ACTOR env var so that bd commands (like `bd hook`) know the agent identity.

Currently gt sets GT_ROLE but bd can't check that (no coupling to gt). bd already checks BD_ACTOR, so gt just needs to set it.

Places to update:
- `gt up` for polecats/crew
- Deacon, Witness, Refinery spawning
- Any other agent spawn points

Related: closed bd-fej5 in beads repo as obsolete (fix belongs here).


142 instances of error suppression with _ = pattern

Code has 142 instances of '_ = ' error suppression in non-test code.
Examples:
- internal/polecat/manager.go: _ = pool.Load() - ignores state loading
- internal/daemon/notification.go: _ = os.WriteFile() - ignores file write
- internal/mail/router.go: _ = r.notifyRecipient() - notification ignored

These create silent failures and hard-to-debug issues.

Options:
1. Document intentional suppressions with comments
2. Handle errors properly where appropriate
3. At minimum, log suppressed errors at debug level


mol-theme-generate: Custom name pool generation via cognition

Currently polecat name themes are hardcoded in namepool.go. Simple theme selection is fine as static config, but custom name generation should be a molecule.

Examples requiring cognition:
- "Generate 50 polecat names in the style of [book/movie/game]"
- "Create names that match the project's domain (medical, financial, etc.)"
- "Extend the mad-max theme with 20 more obscure characters"

## Molecule: theme-generate
Generate custom polecat names for a rig.

## Step: analyze-request
Understand the naming request:
- Theme style or source material
- Number of names needed
- Any constraints (length, format)

## Step: generate-candidates
Generate candidate names matching the style.
Aim for 2x the requested count.

## Step: validate-names
Filter candidates:
- No duplicates with existing themes
- Appropriate length (3-15 chars)
- No problematic terms

## Step: create-theme
Write the custom theme to rig config or beads.
Register in name pool.
Needs: validate-names

## Notes
- Output is a new theme entry in BuiltinThemes equivalent
- Could be stored as a pinned bead for persistence


Digest: mol-deacon-patrol

Patrol 5: Quiet, all healthy


Phase 4.1: mol-deacon-patrol uses ephemeral

Deacon patrol cycles run as ephemeral molecules.

## Current Deacon Loop

```
while running:
    check_heartbeat()
    check_mail()
    sleep(interval)
```

## Molecule-Based Loop

```
while running:
    mol = bd mol bond mol-deacon-patrol-cycle --ephemeral
    execute_cycle(mol):
        check_heartbeat()
        check_mail()
        log_status()
    summary = generate_cycle_summary()
    bd squash mol --summary summary
    sleep(interval)
```

## Benefits

- Each cycle is tracked
- Digests show daemon health over time
- Can query: 'show me patrol cycles from last hour'
- Crash mid-cycle → ephemeral shows where we were


Merge: gt-92l

branch: polecat/Ace
target: main
source_issue: gt-92l
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


Merge: gt-o3is

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


Add harness overview to Mayor priming

Update gt prime Mayor context to explain the harness concept: umbrella repo for GT installation, rigs underneath, Mayor sits above all rigs


Remove Go-based witness patrol - Claude session is the executor

## Problem

The witness has 1370 lines of Go code in internal/witness/manager.go that reimplements what mol-witness-patrol does:
- healthCheck() - polls polecats
- autoSpawnForReadyWork() - spawns polecats for ready issues
- handleStuckPolecat() - nudge logic
- processShutdownRequests() - cleanup logic
- verifyPolecatState() - git state checks

This is backwards. The molecule should drive the work, Claude should execute it.

## The Wrong Architecture (gt-59zd, now cancelled)

The cancelled gt-59zd tried to use molecules as 'tracking ledgers' for Go code:
- Go code runs patrol logic
- Molecule just records what Go did
- Duplicates work, adds complexity

## The Right Architecture

1. Witness runs as Claude session (via gt sling witness or tmux)
2. Claude executes mol-witness-patrol steps directly
3. No Go patrol loop needed
4. Molecule IS the executor, not bookkeeping

## Scope

1. Remove patrol-related functions from manager.go:
   - run(), checkAndProcess(), healthCheck()
   - handleStuckPolecat(), getNudgeCount(), recordNudge()
   - processShutdownRequests(), verifyPolecatState()
   - autoSpawnForReadyWork(), etc.

2. Keep session management functions:
   - Start(), Stop(), Status() - for starting/stopping Claude session
   - State persistence for session identity

3. Update gt witness commands to use Claude session model

4. Test that mol-witness-patrol executes correctly in Claude session

## Related

- gt-zde4: Fixed Witness CLAUDE.md to emphasize mol-following
- gt-59zd: Cancelled - wrong architecture
- witness.md.tmpl: Already rewritten with ZFC principle


Digest: mol-deacon-patrol

Patrol 11: All clear


Witness cleanup should know worktree parent repo

Witness had to discover that polecat worktrees are created from mayor/rig, not the rig root.

## Problem
When cleaning up polecat/tracer:
- Witness ran git worktree remove from gastown/ - failed
- Had to discover worktree was from mayor/rig
- Then removed correctly

## Improvement
Witness should know the worktree parent repo path (mayor/rig) and clean up from there directly.

## Evidence
Tracer bullet 2025-12-23: Witness took extra steps to figure out cleanup path.


Add gate checking to Deacon patrol loop

Integrate gate checking into Deacon's patrol cycle.

## Patrol Integration
```go
func (d *Deacon) checkGates(ctx context.Context) {
    gates, _ := d.store.ListOpenGates(ctx)

    for _, gate := range gates {
        // Check timeout
        if time.Since(gate.CreatedAt) > gate.Timeout {
            d.notifyWaiters(gate, "timeout")
            d.closeGate(gate, "timed out")
            continue
        }

        // Check condition
        if d.checkCondition(gate.AwaitType, gate.AwaitID) {
            d.notifyWaiters(gate, "cleared")
            d.closeGate(gate, "condition met")
        }
    }
}
```

## Moved from beads
Originally bd-is6m. Deacon is in gastown, not beads.


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

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


Digest: mol-deacon-patrol

Patrol 3: All healthy, routine


Digest: mol-deacon-patrol

P9: stable


Digest: mol-deacon-patrol

Patrol 3: routine checks, all healthy


Digest: mol-deacon-patrol

Patrol 18: Nominal


Digest: mol-deacon-patrol

Patrol #13: Stable


Merge: gt-h6eq.3

branch: polecat/nux
target: main
source_issue: gt-h6eq.3
rig: gastown


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 6: Mayor OK, 11 sessions


Unified Beads Namespace - prefix-based routing across town

Vision: Run bd commands from anywhere in town, with prefix-based routing.

Current state:
- Town beads at ~/gt/.beads/ with hq-* prefix
- Rig beads at ~/gt/<rig>/mayor/rig/.beads/ with rig-specific prefixes (gt-, bd-, wy-, etc.)
- Redirects allow agents to use specific beads location
- No automatic prefix-based routing

Desired state:
- bd show gt-xyz from ANYWHERE in town → routes to gastown beads
- bd show hq-abc from ANYWHERE in town → routes to town beads
- bd show wy-def from ANYWHERE in town → routes to wyvern beads
- Prefix determines beads location automatically

Implementation options:
1. Registry file at town root mapping prefix → beads location
2. bd wrapper/hook that reads prefix and routes
3. Unified store with namespace prefixes (more invasive)

Related work:
- gt-0pdhj: Remove hardcoded gastown dependencies
- Template fixes needed for deacon, witness, refinery CLAUDE.md


Witness arm bonding integration test

Test witness with 3 polecats. Verify: arms bonded per worker, each arm captures/assesses independently, aggregation waits for all arms, witness proceeds after aggregation.


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.


Implement gt mq CLI commands

Add gt mq subcommands as sugar over bd:

- gt mq submit: Create MR for current branch
- gt mq list: Show open merge requests
- gt mq next: Show next MR ready to process
- gt mq process: Engineer processes the queue
- gt mq reorder <id> --after <x>: Change ordering via deps
- gt mq status <id>: Show MR details

All commands should work with the Beads data plane.


gt mq list shows empty when MRs exist

The gt mq list command returns empty results even when merge requests exist in the queue.


Digest: mol-deacon-patrol

Patrol 7: All clear


Molecule converge: iterate until AI says done

Work isn't 'done' until AI is confident it's done. Fixes the 85% problem.

**From VC**: internal/iterative/converge.go - 3-7 iterations with AI convergence detection. ~600 lines.
Target: 20%+ more issues discovered. Observed: ~25% average improvement.

**Gas Town implementation**: Molecule converge config:
```yaml
converge:
  strategy: ai
  min_iterations: 3
  max_iterations: 7
  confidence: 0.85
```

Polecat iterates, AI checks convergence. Stop when AI is confident or max reached.

**Value**: Raw agents get to ~85% and stop. Iteration catches the remaining 15%.

**VC metrics**: Convergence rate >70%, mean 4-5 iterations for complex work.


Implement Christmas Ornament pattern for mol-witness-patrol

Integrate dynamic bonding into mol-witness-patrol once Beads primitives are ready.

## Completed

- ✅ WaitsFor parsing (gt-odfr) - Parser now extracts WaitsFor: all-children
- ✅ mol bond command (gt-isje) - gt mol bond creates dynamic children with --var expansion
- ✅ WitnessPatrolMolecule() updated with Christmas Ornament structure (gt-tnow.1)
- ✅ PolecatArmMolecule() created for per-polecat inspection (gt-tnow.2)

## Remaining

- gt-tnow.3: Plugin hook support (P2)
- gt-tnow.4: Integration test with live polecats (P2)

## Design Docs

- docs/molecular-chemistry.md (already updated with pattern)
- docs/architecture.md (already updated with activity feed)
- gt-qflq: mol-witness-patrol design bead (updated)
- gt-dapb: mol-polecat-arm proto


Self-review

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

Fix any issues found before proceeding.


mol-deacon-patrol


gt doctor: Detect and clean up orphaned sessions/processes

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

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

## Proposed Solution

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

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

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

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


gt sling --force: return displaced work to ready pool

When slinging with --force to an agent with occupied hook, the displaced molecule should be returned to the ready pool rather than silently orphaned.

Current behavior:
- --force overwrites the hook attachment
- Previous work becomes orphaned (still assigned but not pinned)

Desired behavior:
1. Unpin the displaced molecule (clear assignee, set pinned=false)
2. Print warning in tool output: 'Warning: displaced gt-xxx back to ready pool'
3. Proceed with new sling

This ensures:
- No silent data loss
- Agent sees the warning and can act on it
- Human caller sees what happened
- Displaced work is discoverable via 'bd ready'

Implementation location: checkHookCollision() or the sling handlers themselves (after the --force check passes)


Phase 3: Polecat Work Cycle

# Phase 3: Polecat Work Cycle

The complete lifecycle of a single polecat working a single issue.

## The Cycle

```
spawn → wake → prime → read hook → work → submit → complete → cleanup
```

## Step by Step

### 1. Spawn (Deacon/Mayor initiates)

```bash
gt spawn --issue gt-xxx --rig gastown
```

Creates fresh worktree, assigns issue, creates polecat session.

### 2. Wake (Claude starts)

Polecat Claude session starts. SessionStart hook fires.

### 3. Prime (Context loads)

```bash
gt prime  # Runs automatically via hook
```

Loads CLAUDE.md, injects beads context, checks hook.

### 4. Read Hook

gt prime finds the assigned issue on the hook:

```
## Your Hook: gt-xxx

You have been assigned this issue. Begin work now.

Title: Fix authentication bug
Priority: P1
Description: ...

Claim it with: bd update gt-xxx --status=in_progress
```

### 5. Work

Polecat:
- Claims issue: `bd update gt-xxx --status=in_progress`
- Reads relevant code
- Makes changes
- Commits with issue ID

### 6. Submit

Polecat:
- Pushes branch
- Creates MR bead: `bd create "Merge: gt-xxx" --type=merge-request`
- Signals completion

### 7. Complete

Polecat:
- Closes the issue: `bd close gt-xxx --reason "Fixed in commit abc123"`
- Syncs beads: `bd sync`

### 8. Cleanup

Polecat:
- Sends completion mail to Witness
- Session terminates (or awaits next assignment)

## The mol-polecat-work Molecule

This is already defined. The polecat should be bonded to it on spawn.

Key steps:
1. orient - Read context, understand codebase
2. claim - Update issue status
3. work - Implement the fix
4. test - Run tests, verify
5. submit - Push, create MR
6. handoff - Signal done, sync

## Implementation

### gt spawn enhancements

- Automatically pin mol-polecat-work to new polecat
- Pass issue ID as variable
- Ensure hook is set before Claude starts

### Polecat CLAUDE.md

Must include:
- Hook reading instructions
- Molecule execution pattern
- Exit state vocabulary (COMPLETED, BLOCKED, ESCALATE)

## Acceptance Criteria

- gt spawn creates polecat with issue on hook
- Polecat wakes and begins work automatically
- Polecat completes issue and submits MR
- Issue is closed with commit reference


Test infrastructure: fixtures, mocks, integration tests

Test infrastructure for Gas Town.

## Test Categories

### Unit Tests
- Config parsing
- Mail operations
- Merge queue operations
- Template rendering

### Integration Tests
- Git operations (uses real git in temp dirs)
- Full workflows (spawn → work → merge)
- CLI command tests

## Fixtures

```go
package testutil

// Creates temp town with minimal structure
func NewTestTown(t *testing.T) *TestTown

// Creates temp rig with git repo
func NewTestRig(t *testing.T, town *TestTown, name string) *TestRig

// Creates test polecat
func NewTestPolecat(t *testing.T, rig *TestRig, name string) *TestPolecat
```

## Mocks

```go
// Mock tmux for session tests (avoid actual tmux)
type MockTmux struct {
    Sessions map[string][]string  // captured send-keys
}

func (m *MockTmux) NewSession(name, dir string) error
func (m *MockTmux) SendKeys(session, keys string) error
func (m *MockTmux) CapturePane(session string, lines int) (string, error)
```

## Test Helpers

```go
// Run test in temp directory
func InTempDir(t *testing.T, fn func(dir string))

// Initialize git repo for testing
func InitGitRepo(t *testing.T, dir string)

// Assert file exists with content
func AssertFileContains(t *testing.T, path, substr string)

// Assert JSON file has field
func AssertJSONField(t *testing.T, path, field string, expected any)
```

## CI Integration

- go test ./... runs all tests
- Integration tests skip with -short flag
- Coverage report generation

## Test Data

Embedded test fixtures:
```go
//go:embed testdata/*
var testdataFS embed.FS
```


Digest: mol-deacon-patrol

Patrol #10: Halfway checkpoint


Digest: mol-deacon-patrol

Patrol cycle 19: routine


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

Patrol 20: final patrol before handoff


test sling pinned


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


Handle callbacks from agents

Handle callbacks from agents.

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

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

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


Remove stale migration docs from gastown-py

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


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


Cross-project dependency workflow (Gas Town side)

Gas Town integration for cross-project dependencies.

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

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

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

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


Remove bd sync instruction from polecat startup workflow

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

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

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

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

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

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


Test Polecat Arm

Test child for bonding pattern


gt spawn pins mol-polecat-work

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

## Current Behavior

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

## New Behavior

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

## Molecule Bonding

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

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

## Hook Pinning

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

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

## Files

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


Mol Mall: Formula Package Registry

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

## Concept

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

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

## Resolution Hierarchy

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

## Package Manifest

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

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

## Distribution Scenarios

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

## Open Questions

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

## Related

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


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.


Design: Mayor session cycling and handoff

Design for Mayor session cycling and structured handoff.

## Overview

Mayor coordinates across all rigs and runs for extended periods. Needs session cycling pattern with structured handoff notes.

## Key Elements

1. Session cycling recognition (when to cycle)
2. Handoff note format (structured state capture)
3. Handoff delivery (mail to self)
4. Fresh session startup (reading and resuming)

## Subtasks (implementation)

- gt-g2d: Mayor session cycling prompting
- gt-sye: Mayor startup protocol prompting
- gt-vci: Mayor handoff mail template
- gt-1le: town handoff command (optional, P2)

**Design complete.** Each subtask has full specification in its description.


gt rig add: Auto-configure HQ routes.jsonl for new rigs

## Summary

When `gt rig add <rig-name>` adds a new rig to the town, it should automatically
add a routing entry to `~/gt/.beads/routes.jsonl` so that beads with that rig's
prefix can be looked up from the town root.

## Current Behavior

After running `gt rig add myproject`:
- Rig is cloned and set up
- No routing entry is added to HQ beads

## Desired Behavior

After running `gt rig add myproject`:
- Rig is cloned and set up
- Detect the rig's beads prefix (from config.yaml or existing issues)
- Add entry to `~/gt/.beads/routes.jsonl`:
  `{"prefix": "mp-", "path": "myproject/mayor/rig"}`

## Implementation Notes

1. After rig setup, check for `<rig>/mayor/rig/.beads/config.yaml`
2. Read `issue-prefix` if set, or sample an issue ID from the database
3. Append to `~/gt/.beads/routes.jsonl` if the prefix isn't already routed
4. Create routes.jsonl if it doesn't exist

## Edge Cases

- Rig has no beads yet (no prefix known) - skip routing setup, let doctor fix later
- Prefix already exists in routes.jsonl - warn and skip (or update path?)
- routes.jsonl doesn't exist - create it


Merge: beads-2nh

branch: fix/spawn-beads-path
target: main
source_issue: beads-2nh
rig: gastown


mol-deacon-patrol


Design: Collapse mail into beads

## Proposal

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

## Rationale

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

These can all be beads issues with a special prefix.

## Design

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

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

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

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

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

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

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

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

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

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


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.


Merge: gt-tnca.1

branch: polecat/immortan
target: main
source_issue: gt-tnca.1
rig: gastown


Digest: mol-deacon-patrol

Patrol #5: Routine - 6 sessions healthy


Digest: mol-deacon-patrol

Patrol 10: All healthy, 1 in_progress issue (max working)


Patrol formulas: Inconsistent variable placeholder syntax

The patrol formulas use inconsistent syntax for variable placeholders:

## Inconsistency

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

## Expected

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

## Fix

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


Formula SDK: Developer Tooling for Workflow Authors

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

## Components

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

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

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

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

## Relationship to Other Concepts

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

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

## Open Questions

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

## Related

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


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, 3 polecats idle, no orphans, 6 Mayor messages pending


Expansion var overrides not implemented

ExpandRule.Vars field exists in schema but is ignored during expansion.

## Current State

The vars map in expand rules should override the expansion formula default variables, but currently the Vars field is not used.

## Implementation

1. In ApplyExpansions, pass rule.Vars to expandStep
2. Merge vars with formula defaults (rule.Vars wins)
3. Substitute vars in template placeholders
4. Add test: expansion with var overrides

## Files

- internal/formula/expand.go: ApplyExpansions, expandStep
- internal/formula/expand_test.go: add test case


Load persisted patrol state

Read handoff bead and get nudge counts.

Load persistent state from the witness handoff bead:
- Active workers and their status from last cycle
- Nudge counts per worker per issue
- Last nudge timestamps
- Pending escalations

```bash
bd show <handoff-bead-id>
```

If no handoff exists (fresh start), initialize empty state.
This state persists across wisp burns and session cycles.


Deacon keepalive: quiet daemon during rounds

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

## Problem

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

## Solution

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

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

## Files

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

## Deacon Behavior

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

## Daemon Changes

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

## Worst Case

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

## Configuration

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


Test Patrol for Bonding

Parent issue for mol bond CLI test


More branches to process?

More branches to process?

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

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

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


Digest: mol-deacon-patrol

Patrol 16: Routine


Digest: mol-deacon-patrol

Patrol 3: all clear, hook fix applied


Burn and respawn or loop

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

Decision point at end of patrol cycle:

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

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

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

This enables infinite patrol duration via context-aware respawning.


Go scaffolding: cmd/gt, go.mod, Cobra setup

Set up Go project structure with CLI framework.

**Stack:**
- Cobra for command/flag handling
- Lipgloss for styled terminal output

**Deliverables:**
- cmd/gt/main.go with Cobra root command
- Basic subcommands: version, help
- Lipgloss styles for status output (success, warning, error)
- go.mod with dependencies


gt mol status: role detection fails from polecat directory

When running 'gt mol status' from a polecat's worktree directory (e.g., ~/gt/gastown/polecats/furiosa), the role detection incorrectly returns 'mayor' instead of 'gastown/furiosa'.

## Root Cause
The detectRole() function in prime.go calculates relPath from townRoot (~gt) to cwd (~/gt/gastown/polecats/furiosa), giving 'gastown/polecats/furiosa'. It then checks parts[0] == 'mayor' but 'gastown' != 'mayor', so it falls through to rig detection where it treats 'gastown' as a rig name.

However, the code then looks for parts[1] == 'polecats' but the actual check is parts[1] == 'polecats' which should work...

## Actual Issue
Need to debug further - the hook file IS created correctly by spawn, but gt mol status can't find it because it's looking for the wrong agent identity.

## Expected
Running from ~/gt/gastown/polecats/furiosa should detect:
- Role: polecat
- Rig: gastown
- Polecat: furiosa
- Agent identity: gastown/furiosa

## Actual
- Role: mayor
- Agent identity: mayor

This prevents polecats from seeing their slung work via gt mol status.


Daemon: integration test with real lifecycle

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

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


Digest: mol-deacon-patrol

Patrol 9: Mayor OK, 11 sessions


CLI: cleanup commands for stale state

Cleanup commands for recovering from stale state.

## Commands

### gt cleanup <polecat>
Clean stale state for specific polecat.
```
gt cleanup <rig>/<polecat> [--dry-run]
```

Actions:
- Remove orphaned state.json if clone missing
- Clear stale session references
- Reset stuck state (working → idle after timeout)

### gt cleanup --all
Clean all polecats in workspace.
```
gt cleanup --all [--dry-run]
```

## Implementation
```go
func CleanupPolecat(rigName, polecatName string, dryRun bool) (*CleanupResult, error)

type CleanupResult struct {
    OrphanedStateRemoved bool
    SessionsCleared      int
    StateReset           bool
    Warnings             []string
}
```

## Overlap with Doctor
- Doctor diagnoses and offers --fix
- Cleanup is more aggressive state recovery
- Consider merging into doctor --fix

## New File
internal/cmd/cleanup.go

## Acceptance Criteria
- [ ] Removes orphaned state files
- [ ] Clears stale session refs
- [ ] --dry-run shows what would happen
- [ ] Reports all actions taken


CloudRun worker container: Dockerfile and entrypoint

## Overview

Docker container image for Cloud Run workers.

## Dockerfile

```dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o gt ./cmd/gt

FROM ubuntu:22.04

# Install Claude Code
RUN apt-get update && apt-get install -y     curl git nodejs npm     && npm install -g @anthropic-ai/claude-code     && apt-get clean

# Install gt
COPY --from=builder /app/gt /usr/local/bin/gt

# Worker entrypoint
COPY deploy/cloudrun/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

EXPOSE 8080
ENTRYPOINT ["/entrypoint.sh"]
```

## Entrypoint

```bash
#!/bin/bash
git config --global user.name "$GIT_USER"
git config --global user.email "$GIT_EMAIL"
exec gt worker serve --port 8080
```

## Files

- `deploy/cloudrun/Dockerfile`
- `deploy/cloudrun/entrypoint.sh`
- `deploy/cloudrun/README.md`

## Dependencies

Depends on: gt-9a2.11 (HTTP server - gt worker serve)


mol-witness-patrol

Per-rig worker monitor patrol loop.

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

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

This molecule uses wisp storage (.beads-wisp/) for ephemeral patrol state.
Persistent state (nudge counts, handoffs) is stored in a witness handoff bead.


Merge to main and push immediately.

Merge to main and push immediately.

```bash
git checkout main
git merge --ff-only temp
git push origin main
git branch -d temp
git push origin --delete <polecat-branch>
```

Main has moved. Any remaining branches need rebasing on new baseline.

instantiated_from: mol-refinery-patrol
step: merge-push


Digest: mol-deacon-patrol

Patrol 20: Mayor OK, 11 sessions


Add agent abstraction layer to support non-Claude agents

Currently Gas Town hardcodes 'claude --dangerously-skip-permissions' throughout the codebase for spawning agents. We should add an abstraction layer to support other AI agents (e.g., Gemini CLI, OpenAI agents, local models).

Locations that spawn Claude:
- internal/cmd/mayor.go:131
- internal/cmd/deacon.go:150
- internal/cmd/witness.go:280
- internal/cmd/crew.go (multiple locations)
- internal/cmd/up.go:190, 229
- internal/session/manager.go:146
- internal/refinery/manager.go:207

Suggested approach:
1. Create an agent package with an interface
2. Add configuration for agent type in town/rig config
3. Replace hardcoded claude commands with agent.Spawn() calls
4. Support agents: claude, gemini, openai, local (ollama, etc.)


Digest: mol-deacon-patrol

Patrol 2: Quiet cycle, all healthy, orphan gt-mol-aux persists


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.


Delete hook types from internal/wisp

Delete from internal/wisp/types.go:
- WispType type
- TypeSlungWork constant
- HookPrefix, HookSuffix constants
- Wisp struct
- SlungWork struct
- NewSlungWork function
- HookFilename function
- AgentFromHookFilename function

The entire file may become empty or minimal.


Digest: mol-deacon-patrol

Patrol #8: Stable


Digest: mol-deacon-patrol

P16: stable


Phase 3.1: Summary generation protocol

Define how agents generate summaries for squash.

## The Problem

Beads doesn't make AI calls (inversion of control). Gas Town agents must:
1. Generate their own summary before calling squash
2. Pass summary to bd squash command

## Summary Template

```
Task: <source issue title>
Action: <what was done - fix/implement/refactor/etc>
Outcome: <result - tests pass, committed, needs follow-up, etc>
Details: <1-2 sentences of specifics if needed>
```

## Example

```
Task: Fix lifecycle parser matching bug (gt-rixa)
Action: Reordered conditional checks in parseLifecycleRequest
Outcome: Tests passing, committed to polecat/furiosa
Details: The 'cycle' keyword was matching 'lifecycle:' prefix. Now checks restart/shutdown first, uses word boundary for cycle.
```

## Command

```bash
bd squash eph-abc123 --summary "Task: Fix lifecycle parser..."
```


Digest: mol-deacon-patrol

Patrol 3: stable


Phase 2: Awareness and real-time channels (announce:, #channel)

## Scope

Extensions for awareness broadcasting and ephemeral real-time communication.

### Deliverables

1. **announce:name** - Shared single-copy bulletin board
   - Informational, not work-creating
   - Recipients check when convenient, missing is OK
   - Use case: 'Bob is refactoring logging, be aware'
2. **#channel resolution** - Dynamic tmux scan for running agents
   - #rig/gastown → tmux sessions matching gastown/*
   - #town → all Gas Town sessions
3. **gt channel publish** - Ephemeral nudge broadcast to channel

### Key semantics
- announce: shared copy (1 message, N readers) vs list: (N copies, N obligations)
- #channel ephemeral - no storage, real-time only
- Channels resolve against running sessions, not filesystem


Check own context limit

Check own context usage.

If context is HIGH (>80%):
- Ensure state is saved to handoff bead
- Prepare for burn/respawn

If context is LOW:
- Can continue patrolling


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 10: Mayor OK, 11 sessions


Test Patrol for Bonding

Parent issue for mol bond CLI test


Merge: gt-g44u.2

branch: polecat/Doof
target: main
source_issue: gt-g44u.2
rig: gastown


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

Patrol 4: quiet


Refinery tmux status: show merge queue length

Add refinery-specific status line showing:
- MQ length (pending merges)
- Currently processing item (if any)
- Maybe: success/failure counts

Implement in runRefineryStatusLine() in internal/cmd/statusline.go


Digest: mol-deacon-patrol @ 2025-12-24 20:23

Patrol complete: inbox clear, all agents healthy, no orphans


Digest: mol-deacon-patrol

Patrol 2: All healthy, no messages, quiet cycle


Test Patrol Parent

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

Original description:
Test parent for Christmas Ornament pattern


Merge: gt-a95

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


Implement gt sling command

The unified work dispatch command.

```bash
gt sling <thing> <target> [options]
```

Implements spawn + assign + pin in one operation. See sling-design.md.

Acceptance:
- [ ] Parse thing (proto name, issue ID, epic ID)
- [ ] Parse target (agent address)
- [ ] Spawn molecule if proto
- [ ] Assign to target agent
- [ ] Pin to agent's hook (pinned bead)
- [ ] Support --wisp flag for ephemeral
- [ ] Support --molecule flag for issue+workflow
- [ ] Error if hook already occupied (unless --force)


self-review

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

Fix any issues found before proceeding.

Depends: implement


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.


Merge: gt-ci84

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Interrupt vs Queue mail semantics

Add priority/delivery semantics to mail messages.

## Semantics

| Type | Delivery | Use Case |
|------|----------|----------|
| Interrupt | tmux send-keys | Lifecycle, URGENT, stuck detection |
| Queue | Create message only | Normal mail, status, heartbeat |

## Implementation

- `bd mail send --interrupt` uses tmux send-keys notification
- Default is queue (agent checks with `gt mail check`)
- Urgent flag on messages for interrupt delivery

## Agent Side

- `gt mail check --quiet` - non-blocking check for queued mail
- `gt mail wait` - block until mail arrives (for idle agents)
- Heartbeats become queued, agent checks at natural breakpoints


Molecule composition: Includes directive

Add support for molecule composition via the Includes directive.

## Format
\`\`\`markdown
## Molecule: derived-name
Includes: mol-base-molecule

## Step: additional-step
Additional instructions here.
Needs: step-from-base
\`\`\`

## Implementation
1. Add \`Includes:\` parsing to ParseMoleculeSteps()
2. Resolve included molecule by ID
3. Merge steps from included molecule
4. Allow new steps to depend on included steps
5. Support multiple includes (polymers)

## Files to modify
- internal/beads/molecule.go
- internal/beads/molecule_test.go

## Acceptance
- [ ] Parse Includes directive
- [ ] Resolve and merge included steps
- [ ] Dependencies across molecules work
- [ ] Multiple includes supported
- [ ] Tests cover composition scenarios


Digest: mol-deacon-patrol

Patrol 10: all clear


mol-deacon-patrol

Mayor's daemon patrol loop.

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


mol-deacon-patrol


Auto-restart patrol agents after N loops

All patrol roles should auto-restart to keep context usage low. Role-specific heuristics:

**Deacon**:
- 20 patrol loops without major incident
- Immediate restart after ANY extraordinary action (lifecycle request, remediation, escalation)
- Rationale: Keep context short so there's headroom if something big comes up

**Witness**:
- Based on polecats processed (not loop count)
- Restart after processing N polecats (spawns, nudges, decommissions)
- Suggested N: 10-15 polecats

**Refinery**:
- Based on MRs processed (not loop count)
- Restart after processing N merge requests
- Suggested N: 5-10 MRs (merges are context-heavy)

Benefits:
- Keeps context fresh (better focus/performance)
- Reduces cost (quadratic increase vs conversation length)
- Preserves headroom for handling surprises
- Simple and predictable (no context estimation needed)

Each role tracks their metric in state file and hands off when threshold reached.


Digest: mol-deacon-patrol

Patrol 20: clear, handoff


Digest: mol-deacon-patrol

Patrol 6: All clear


Digest: mol-deacon-patrol

Patrol 4: 8 sessions active, all healthy


Digest: mol-deacon-patrol

Patrol 3: All clear


Process witness mail

Process witness mail: lifecycle requests, help requests.

```bash
gt mail inbox
```

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

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