Failure handling: assign back to worker, add labels

Handle merge failures appropriately.

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

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

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


Add org formula examples and tests

Create example organizational formula hierarchy and tests.

## Examples

Create in .beads/formulas/:
- acme-base.formula.yaml: Company-wide (security-audit aspect)
- acme-frontend.formula.yaml: extends acme-base, adds accessibility-audit
- acme-backend.formula.yaml: extends acme-base, adds sql-injection-scan

## Tests

1. Three-level inheritance resolves correctly
2. Aspect merge order is correct
3. exclude-aspects removes parent aspect
4. Cooking org formula produces expected steps
5. Error on missing parent formula


Digest: mol-deacon-patrol

Patrol complete: all agents healthy, no lifecycle requests, 9 in-progress items noted


Add charmbracelet TUI dependencies (bubbletea, bubbles)

Add charmbracelet TUI framework dependencies.

## Dependencies to add
```
go get github.com/charmbracelet/bubbletea
go get github.com/charmbracelet/bubbles
```

## Already have
- github.com/charmbracelet/lipgloss (styling)

## Verify
- go mod tidy
- go build ./...

Quick task, just adding deps.


Merge: morsov-1766966180179

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


Messaging infrastructure: lists, queues, and channels

## Problem

Current messaging is point-to-point only:
- Mail: A → B (durable, polling)
- Nudge: A → B (ephemeral, real-time)

No support for broadcast, work queues, or pub/sub patterns.

## Design

### Addressing Syntax

| Prefix | System | Resolution | Storage | Claim? |
|--------|--------|------------|---------|--------|
| `agent/` | Mail | Direct | Recipient inbox | N/A |
| `@group` | Mail | Dynamic (filesystem) | Fan-out (N copies) | No |
| `list:name` | Mail | Static config | Fan-out (N copies) | No |
| `queue:name` | Mail | Static config | Shared (1 copy) | Yes |
| `announce:name` | Mail | Static config | Shared (1 copy) | No |
| `#channel` | Nudge | Dynamic (tmux) | None (ephemeral) | No |

### Dynamic Aliases

- `@rig/gastown` → scan ~/gt/gastown/ for agent dirs (witness, refinery, crew/*, polecats/*)
- `@town` → scan ~/gt/ for all agent dirs
- `@witnesses` → for each rig, include <rig>/witness
- `@crew/gastown` → scan ~/gt/gastown/crew/*
- `#rig/gastown` → scan tmux for gastown/* sessions
- `#town` → scan tmux for all Gas Town sessions

**Mail** resolves against filesystem (agents that exist)
**Channels** resolve against tmux (agents that are running)

### Static Config

Location: `~/gt/config/` (JSON format, machine-edited)

```json
// lists.json
{
  "oncall": ["mayor/", "gastown/witness", "beads/witness"],
  "cleanup/gastown": ["gastown/witness", "deacon/"]
}
```

### Work Queue Semantics

- `gt mail send queue:cleanup/gastown -s "Task" -m "..."`
- `bd update <msg-id> --claim` → atomic claim (sets assignee + in_progress)
- If already claimed, returns error "already claimed by X"

### Use Cases

1. **Polecat spawn**: `gt mail send @rig/gastown` → Witness + Deacon both notified
2. **Polecat cleanup**: `gt mail send queue:cleanup/gastown` → first to claim handles it
3. **Town broadcast**: `gt mail send @town -s "Handoff now"` → everyone gets copy
4. **Real-time alert**: `gt channel publish #witnesses "Swarm incoming"`

## Implementation Tasks

1. Create ~/gt/config/ directory structure
2. Implement dynamic alias resolution (filesystem scan)
3. Implement static list lookup (config/lists.json)
4. Add fan-out at send time for @/list: addresses
5. Implement queue: with shared storage
6. Add `bd update --claim` for work queue semantics
7. Implement channel resolution (tmux scan)
8. Add `gt channel publish` command


gt rig reset: clear stale mail on reset/land

## Problem

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

## Current State

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

## Proposed Behavior

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

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

## Implementation

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


Digest: mol-deacon-patrol

Patrol complete: 12 agents healthy, no lifecycle requests, 1 potential orphan (bd-llfl). Mayor has 6 pending messages.


Remove keepalive file infrastructure

The keepalive mechanism (~/gt/daemon/activity.json) is deprecated in favor of feed-based wake.

TODO:
1. Remove keepalive.TouchTownActivity() calls from gt commands
2. Remove keepalive.ReadTownActivity() from daemon
3. Delete internal/keepalive package
4. Update daemon to use longer base heartbeat (recovery-focused)

Whitelist consideration: Some read-only commands might need to wake (TBD - none identified yet)


Digest: mol-deacon-patrol

Patrol 14


Digest: mol-deacon-patrol

Patrol 6: all clear


Polecat cleanup should refuse to lose uncommitted work

The system should stubbornly refuse to lose work from a polecat.

## Current Problem

- gt spawn --force bypasses safety checks
- gt shutdown doesn't check for uncommitted work
- Witness cleanup doesn't check git status

## Desired Behavior

Before any polecat cleanup, check:
1. git status - any uncommitted changes?
2. git stash list - any stashes?
3. Unpushed commits on branch?
4. Unsynced beads changes?

If ANY of these exist:
- REFUSE to clean up
- Print clear error message listing what would be lost
- Require explicit --nuclear flag to force (not just --force)

## Implementation

Add to cleanupPolecat() in witness/manager.go:
```go
func (m *Manager) checkUncommittedWork(polecatName string) error {
    dir := m.polecatDir(polecatName)

    // Check git status
    if hasUncommitted, _ := git.HasUncommittedChanges(dir); hasUncommitted {
        return fmt.Errorf("polecat %s has uncommitted changes", polecatName)
    }

    // Check stashes
    if stashCount, _ := git.StashCount(dir); stashCount > 0 {
        return fmt.Errorf("polecat %s has %d stashes", polecatName, stashCount)
    }

    // Check unpushed commits
    if unpushed, _ := git.UnpushedCommits(dir); unpushed > 0 {
        return fmt.Errorf("polecat %s has %d unpushed commits", polecatName, unpushed)
    }

    return nil
}
```

## Affected Commands

- gt shutdown
- gt rig shutdown
- Witness cleanup
- gt spawn --force (should warn if overwriting)


Digest: mol-deacon-patrol

Final patrol cycle 20: all systems healthy


Evaluate pending async gates

Evaluate pending async gates.

Gates are async coordination primitives that block until conditions are met.
The Deacon is responsible for monitoring gates and closing them when ready.

**Timer gates** (await_type: timer):
Check if elapsed time since creation exceeds the timeout duration.

```bash
# List all open gates
bd gate list --json

# For each timer gate, check if elapsed:
# - CreatedAt + Timeout < Now → gate is ready to close
# - Close with: bd gate close <id> --reason "Timer elapsed"
```

**GitHub gates** (await_type: gh:run, gh:pr) - handled in separate step.

**Human/Mail gates** - require external input, skip here.

After closing a gate, the Waiters field contains mail addresses to notify.
Send a brief notification to each waiter that the gate has cleared.


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)


Digest: mol-deacon-patrol

Quick patrol: no messages, all healthy


Hook system for event extensibility

GGT needs hook system for extensibility like PGT.

## Event Types
```go
type Event string
const (
    EventPreSessionStart  Event = "pre-session-start"
    EventPostSessionStart Event = "post-session-start"
    EventPreShutdown      Event = "pre-shutdown"
    EventPostShutdown     Event = "post-shutdown"
    EventOnPaneOutput     Event = "on-pane-output"
    EventSessionIdle      Event = "session-idle"
    EventMailReceived     Event = "mail-received"
    EventWorkAssigned     Event = "work-assigned"
)
```

## Hook Configuration
File: .claude/hooks.json or .gastown/hooks.json
```json
{
  "hooks": {
    "pre-shutdown": [
      {"type": "command", "cmd": "./scripts/pre-shutdown.sh"}
    ],
    "on-pane-output": [
      {"type": "command", "cmd": "./scripts/activity-monitor.sh"}
    ]
  }
}
```

## Hook Types
1. **Command**: Execute external script
2. **Built-in**: Internal Go functions (pre-shutdown checks)

## Hook Interface
```go
type HookRunner struct {
    config *HookConfig
}

type HookResult struct {
    Success bool
    Message string
    Block   bool  // For pre-* hooks: should operation be blocked?
}

func (r *HookRunner) Fire(event Event, ctx *HookContext) []HookResult
```

## CLI Commands
```
gt hooks list [<event>]    # List registered hooks
gt hooks fire <event>      # Manually fire for testing
gt hooks test [--all]      # Validate hook config
```

## Integration Points
- internal/session/manager.go: Fire pre/post session hooks
- internal/mail/router.go: Fire mail-received hook

## New Package
internal/hooks/
├── types.go    # Event, HookConfig, HookResult
├── runner.go   # HookRunner, Fire()
└── builtin.go  # Built-in hooks (pre-shutdown checks)

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

## Acceptance Criteria
- [ ] Hook config loading from JSON
- [ ] Command hooks execute subprocess
- [ ] Pre-shutdown hook integration with session stop
- [ ] CLI for listing and testing hooks


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


Add molecules.jsonl as separate catalog file for template molecules


Digest: mol-deacon-patrol

Patrol 9: Refineries healthy


gt spawn: Not injecting work instructions to session

gt spawn starts session but doesn't inject the issue assignment.

Repro:
1. gt spawn gastown/Toast --issue gt-2ux
2. Session starts but polecat just sees Claude prompt
3. No issue context injected

Expected: Polecat should receive issue details automatically.
Actual: Polecat sits at blank prompt, needs manual injection.


Phase verbs: pour and wisp commands

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

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


Digest: mol-deacon-patrol

Patrol cycle 5: routine, healthy


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 17: routine


Deacon CLAUDE.md for patrol execution

Update Deacon role CLAUDE.md for patrol execution.

## Key Additions

### Role Definition

```markdown
## Your Role: DEACON

You are the Deacon - Gas Towns heartbeat process.
You run mol-deacon-patrol continuously.

Your job:
- Check mail for callbacks
- Spawn polecats for ready work
- Monitor rig health (basic)
- Cycle context when full
```

### Patrol Execution

```markdown
## Patrol Execution

You run mol-deacon-patrol on your hook.

On each heartbeat from the daemon:
1. Check your current step: bd hook
2. Execute that step
3. Advance: bd mol advance mol-deacon-patrol
4. If COMPLETE: restart the patrol or cycle context

The daemon keeps you alive. Your job is to run the patrol.
```

### Heartbeat Response

```markdown
## Heartbeat Response

When you see "HEARTBEAT: ..." from the daemon:
- If idle: check your hook, start/resume patrol
- If mid-step: continue working
- If waiting: the heartbeat reminds you to check state

Heartbeats are your clock tick. Use them.
```

### Context Cycling

```markdown
## Context Cycling

When context is high (>80%):
1. Write state to molecule
2. Run: gt handoff -s "Deacon cycling" -m "Context full"
3. Exit cleanly
4. Daemon respawns you
5. You wake, prime, read hook, continue
```

## File

deacon/CLAUDE.md (in town root)


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: fixed stale mol spawn prompts, cleaned 36 orphaned wisps, all agents healthy


Session pre-shutdown checks

Session stop should verify clean state before killing, like PGT.

## Pre-Shutdown Checks

### 1. Git Working Tree Clean
```go
func checkGitClean(clonePath string) error {
    // git status --porcelain
    // Fail if any output
}
```

### 2. All Commits Pushed
```go
func checkCommitsPushed(clonePath string) error {
    // git log origin/HEAD..HEAD
    // Fail if any unpushed commits
}
```

### 3. Assigned Issues Handled
```go
func checkIssuesHandled(polecat *Polecat) error {
    // If polecat.Issue != "", check if closed or reassigned
}
```

### 4. Beads Synced
```go
func checkBeadsSynced(clonePath string) error {
    // bd sync --status in clone directory
}
```

## Behavior on Failure
1. First attempt: Nudge worker to fix
2. Retry up to 3 times with delay
3. After retries: Escalate to Witness/Mayor

## Integration
Modify internal/session/manager.go Stop():
```go
func (m *Manager) Stop(polecat string, force bool) error {
    if !force {
        if err := m.runPreShutdownChecks(polecat); err != nil {
            return fmt.Errorf("pre-shutdown checks failed: %w", err)
        }
    }
    // existing stop logic
}
```

## Flags
- --force: Skip checks
- --grace-period N: Time to wait for fixes

## Dependencies
- Ties into gt-69l (hook system) - can be hook-based
- Ties into gt-f8v (Witness pre-kill verification)

## Acceptance Criteria
- [ ] Stop fails if uncommitted changes (without --force)
- [ ] Stop fails if unpushed commits
- [ ] Clear error messages with fix instructions
- [ ] --force bypasses all checks


Merge: slit-1767073379145

attached_args: Code review this merge request

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

CODE REVIEW (valkyrie): REQUEST CHANGES

Critical bugs found in internal/swarm/manager.go:
1. JSON field changed from 'dependents' to 'dependencies' but bd outputs 'dependents'
2. 'hooked' status removed from in_progress handling
3. Assignee field removed from task loading

These changes will break swarm coordination. Polecat_spawn.go fix is correct.

Recommendation: Revert swarm/manager.go changes, keep polecat_spawn.go fix.


Merge: gt-qz2l

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


Merge: furiosa-1767073359963

attached_args: Code review this merge request

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


Digest: mol-deacon-patrol

Cycle 12: quiet


bd update --claim for work queue semantics

Atomic claim operation for work queue messages.

## Deliverables

1. Add --claim flag to bd update
2. Atomic operation:
   - Sets assignee to claimer
   - Sets status to in_progress
   - Fails if already claimed
3. Conflict detection:
   - If already claimed, return error: "already claimed by X"
4. Integration with gt mail for queue messages

## Example
```bash
gt mail queue cleanup/gastown  # See available work
bd update msg-xxx --claim       # Claim it atomically
# Returns error if someone else claimed first
```

## Dependencies
- queue: shared storage (gt-???)

## Acceptance
- --claim sets assignee + status atomically
- Double-claim returns clear error
- Works with queue messages


Merge: gt-h6eq.3

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


Digest: mol-deacon-patrol

Patrol 18


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

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


bd create should support molecule type

gt molecule commands expect type=molecule but bd validates against bug|feature|task|epic|chore|merge-request only


**VERIFICATION GATE**: This step enforces the Beads Promise.

If tests PASSED: This step auto-completes. Proceed to merge.

If tests FAILED:
1. Diagnose: Is this a branch regression or pre-existing on main?
2. If branch caused it:
   - Abort merge
   - Notify polecat: "Tests failing. Please fix and resubmit."
   - Skip to loop-check
3. If pre-existing on main:
   - Option A: Fix it yourself (you're the Engineer!)
   - Option B: File a bead: bd create --type=bug --priority=1 --title="..."

**GATE REQUIREMENT**: You CANNOT proceed to merge-push without:
- Tests passing, OR
- Fix committed, OR
- Bead filed for the failure

This is non-negotiable. Never disavow. Never "note and proceed."

instantiated_from: mol-refinery-patrol
step: handle-failures


gt session start --issue doesn't pin work to hook

When starting a polecat with --issue, the work isn't pinned to the hook:
  gt session start beads/Toast --issue bd-oxgi

After session starts, 'gt mol status' shows empty hook.

The polecat had to manually discover the work via bd ready. The --issue flag should call 'gt hook attach' or equivalent to pin the work.


CLI: session commands (start, stop, at, list, capture, inject)

Session management CLI commands.

## Commands

### gt session start
Start a polecat session.
```
gt session start <rig>/<polecat> [--issue <id>]
```
- Creates tmux session
- Launches claude in polecat workdir
- Optionally injects initial issue context

### gt session stop
Stop a polecat session.
```
gt session stop <rig>/<polecat> [--force]
```
- Graceful shutdown by default
- --force kills immediately

### gt session at (attach)
Attach to running session.
```
gt session at <rig>/<polecat>
```
- Attaches tmux session to current terminal
- Detach with Ctrl-B D

### gt session list
List all sessions.
```
gt session list [--rig <rig>] [--json]
```
- Shows running/stopped status
- Optionally filter by rig

### gt session capture
Capture recent output from session.
```
gt session capture <rig>/<polecat> [--lines <n>]
```
- Default: last 100 lines
- Useful for checking polecat progress

### gt session inject
Send message to session.
```
gt session inject <rig>/<polecat> -m "message"
gt session inject <rig>/<polecat> -f <file>
```
- Injects text via tmux send-keys
- Used for nudges, notifications

## Address Format

`<rig>/<polecat>` e.g., `wyvern/Toast`

## Implementation

Session subcommand group:
```go
var sessionCmd = &cobra.Command{Use: "session"}
sessionCmd.AddCommand(startCmd, stopCmd, atCmd, listCmd, captureCmd, injectCmd)
```


Day 3.5: Test polecat → refinery → merged flow

Integration test:
1. Spawn polecat with work
2. Polecat completes (updates state, closes bead)
3. Witness detects completion
4. Witness sends MERGE_READY
5. Refinery processes and merges
6. MERGED signal received

Parent: gt-hwka3


load-context

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

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


bd sync: Handle mol-* prefix for protos gracefully

When bd sync imports protos (mol-*), it warns about prefix mismatch. The allowed_prefixes config doesn't seem to apply to imports.

Current behavior: bd sync fails import step with prefix mismatch error
Expected: mol-* should be recognized as valid proto prefix, or allowed_prefixes should be respected

Workaround: The export/push still succeeds, only import fails.

Related: bd-47qx


Document crew worker patrol integration

Document how mol-ready-work integrates with crew worker workflow. Cover: starting the patrol, patrol vs normal operation, backlog configuration, handoff mechanics, discovered work handling. Update CLAUDE.md with patrol section.


Merge: gt-h6eq.7

branch: polecat/dag
target: main
source_issue: gt-h6eq.7
rig: gastown


Digest: mol-deacon-patrol

Patrol 1: all agents healthy, no callbacks, clone divergence detected (zoey 52 behind)


Digest: mol-deacon-patrol

Patrol 15: All agents healthy


Merge: gt-h6eq.6

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


Day 4.2: Implement gt polecat nuke command

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

Parent: gt-4a2qt


Digest: mol-deacon-patrol

Patrol 7: Mayor OK, 11 sessions


gt crew remove: Does not close agent bead

When running 'gt crew remove <name>', the command removes the crew workspace directory but does not close the associated agent bead (gt-<rig>-crew-<name>).

This leaves orphaned agent beads in the system after crew removal.

The remove command should close the agent bead with a reason like 'Crew workspace removed'.


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-ie33
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Check mail for MR submissions, escalations, messages.

```bash
gt mail inbox
# Process any urgent items
```

Handle shutdown requests, escalations, and status queries.

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


Tmux status line: rig color themes and worker identity display

## Summary

Customize tmux status line for Gas Town workers with:
1. Per-rig configurable color themes
2. Clear worker name and role visibility

## Current Problem

- Only mayor shows in status line (and truncated)
- Can't tell which rig/worker you're looking at
- All sessions look the same

## Proposed Design

### Per-rig colors
```yaml
# In rig config or beads
theme:
  primary: '#ff6600'    # Orange for gastown
  secondary: '#333333'
  accent: '#ffcc00'
```

### Status line format
```
[gastown/Rictus] polecat | gt-70b3 | branch: polecat/Rictus
[beads/emma] crew | working | branch: main
[mayor] coordinator | idle
```

### Components
- Rig name with rig color
- Worker name
- Role (polecat/crew/mayor/witness/refinery)
- Current issue or status
- Branch name

## Configuration

Could use pinned beads for this (see gm-w13, beads-6v2):
- `bd show <rig>-theme` returns theme config
- Stored as pinned bead, always available
- Part of 'config in beads data plane' initiative

Implementation complete. Core features: per-rig color themes, dynamic status line with issue/mail indicators, gt theme/issue commands. Ready for testing.


Digest: mol-deacon-patrol

Patrol cycle 15: All healthy


Digest: mol-deacon-patrol

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


inbox-check

Process witness mail: lifecycle requests, help requests.

```bash
gt mail inbox
```

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

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


🤝 HANDOFF: Timing fixes applied

Fixed mayor attach timing bug. Completed: timing fix, gt-tulx, Emma beads-6v2. Remaining P1: gt-17zr, gt-kcee, gt-szsq. Run gt prime on startup.


Digest: mol-deacon-patrol

Patrol 20: quiet, handoff threshold reached


Crew worker grip in gastown - human-managed persistent workspace.

role_type: crew
rig: gastown
agent_state: idle
hook_bead: null
role_bead: gt-crew-gastown-grip-role
cleanup_status: null


Human and mail gates

Implement human:<prompt> gate (requires explicit approval command). Implement mail:<pattern> gate (waits for mail matching pattern). These enable async human-in-loop workflows.


Digest: mol-deacon-patrol

Patrol cycle 14: nominal


Overhaul autonomous-mode guidance with ledger/capability framing

Re-read all relevant docs in ~/gt/docs (especially hop/) and overhaul the autonomous-mode guidance in role templates with a stronger "why" framing.

Current state:
- Theory of Operation explains "system stalls if you wait"
- Steam engine metaphor (piston, gearbox, flywheel)
- Physics not politeness language

Enhancement direction (without revealing HOP explicitly):
1. Frame work as "contributing to a ledger of demonstrated capability"
2. Emphasize quality: "your work history is visible, every completion matters"
3. Add the redemption arc: "bad work can be overcome through consistent good work"
4. Strengthen the "proving the model" angle: "every autonomous completion is evidence this works at scale"
5. Consider adding "your CV grows with every completion" concept

Files to update:
- internal/templates/roles/*.md.tmpl (all role templates)
- internal/cmd/prime.go (AUTONOMOUS MODE output)
- Possibly ~/gt/docs/philosophy.md or similar

Constraints:
- Gas Town cannot explicitly reference HOP
- Concepts and motivation are fine, just not the name or confidential details
- Should feel like natural evolution, not grafted-on messaging

Read first:
- ~/gt/docs/hop/CONTEXT.md
- ~/gt/docs/hop/BUSINESS_OVERVIEW.md
- ~/gt/docs/philosophy.md (if exists)
- All role templates

Deliverable: Updated templates and prime.go with stronger ledger/capability framing.


gt-gastown-polecat-dementus

gt-gastown-polecat-dementus

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-yt4py
role_bead: gt-polecat-role
cleanup_status: has_stash


Digest: mol-deacon-patrol

Patrol 9: All agents healthy


Swarm completion detection and auto-close

Detect when all epic children are closed and auto-close the swarm molecule.

Core logic:
1. After any issue closes, check if it was part of a swarm
2. Query bd list --parent=<epic> --status=open
3. If empty (all closed), close the swarm molecule
4. Fire completion event for activity feed

Can be implemented as:
- Part of Witness patrol
- Or as a bd hook triggered on issue close
- Or as a gt swarm check command called periodically

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

Dependencies: gt-kc7yj.1 (gt swarm refactor)


Digest: mol-deacon-patrol

Patrol 13: clear


Merge polecat/rictus: Add molecule phase lifecycle diagram

Branch: polecat/rictus

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

Closes: gt-c6zs


Merge: gt-o3is

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


Witness tmux status: show polecat count under management

Add witness-specific status line showing:
- Number of polecats under management
- Active/idle status
- Maybe: last nudge time, blocked count

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


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.


Merge conflicts: Buzzard/mq-status, Dementus/harness-docs


Digest: mol-deacon-patrol

Patrol 8: all clear, handing off for fresh context


Merge: gt-3x0z.1

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


Digest: mol-deacon-patrol

Patrol 16: clear


Test Task 2: Add comment to version.go


Witness: Handle LIFECYCLE work-merged mail

Witness should process the `LIFECYCLE: work merged` notification from Refinery.

## Implementation

1. In Witness mail processing, add handler for subject containing "LIFECYCLE: work merged"
2. Parse worker name from mail body
3. Update polecat state to `merged` (new state - see sibling task)
4. Log completion for metrics
5. Worktree is now eligible for cleanup on next gc cycle

## Acceptance
- Witness correctly parses and handles work-merged mail
- Polecat state updated to merged
- No action taken if polecat already cleaned up (idempotent)


Digest: mol-deacon-patrol

Patrol 7: All clear


Digest: mol-deacon-patrol

Patrol 8: all clear


Check own context limit

Check own context limit.

The Deacon runs in a Claude session with finite context.
Check if approaching the limit:

```bash
gt context --usage
```

If context is high (>80%), prepare for handoff:
- Summarize current state
- Note any pending work
- Write handoff to molecule state

This enables the Deacon to burn and respawn cleanly.


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-ksrt
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Digest: mol-deacon-patrol

Patrol 2: archived stale Mayor handoffs, all agents healthy


Direct formula-to-wisp instantiation (skip proto)

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

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

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

Implementation: streaming cook that emits directly to wisp storage.

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


gt polecat remove --all: bulk polecat teardown

Currently gt polecat remove only accepts one polecat at a time. Need bulk operations:

## Requested
- `gt polecat remove gastown --all` - remove all polecats from a rig
- `gt polecat remove gastown/A gastown/B ...` - remove multiple by name

## Context
After a swarm completes, tearing down 20 polecats one at a time is tedious.
Ephemeral workers should be easy to create and destroy in bulk.

## Related
- gt-c92: CLI: all command for batch polecat operations


mol progress: track dynamically bonded children

Extend `gt mol progress` to show dynamically bonded children.

## Current Behavior

```
gt mol progress gt-abc
```

Shows progress through pre-defined steps from InstantiateMolecule.

## New Behavior

Also show dynamically bonded children:

```
📊 Progress: mol-witness-patrol (gt-abc)

  Steps (9):
    ✓ inbox-check
    ✓ check-refinery
    ✓ load-state
    ◐ survey-workers (bonded 3 children)
    ○ aggregate (WaitsFor: all-children)
    ○ save-state
    ○ generate-summary
    ○ context-check
    ○ burn-or-loop

  Bonded Children (3):
    ✓ arm-toast (5/5 steps)
    ◐ arm-nux (3/5 steps)
    ○ arm-furiosa (0/5 steps)

  Progress: 4/9 steps, 3 arms (1 complete, 1 in-progress, 1 pending)
```

## Implementation

1. Find children with bonded_to: <parent-id> in description
2. Recursively get progress for each bonded child
3. Aggregate into parent progress display


Complete gt crew commands (list, attach, remove, refresh, status)

Add remaining crew subcommands to internal/cmd/crew.go:

1. gt crew list - List crew workspaces with status
2. gt crew at/attach - Start tmux session in crew workspace
3. gt crew remove - Remove crew workspace (with safety checks)
4. gt crew refresh - Context cycling with mail-to-self handoff
5. gt crew status - Show detailed workspace status

Build on existing crew add implementation in internal/cmd/crew.go.
Reference closed issues gt-cik.3-7 for original requirements.


Digest: mol-deacon-patrol

Patrol 5: all healthy


Digest: mol-deacon-patrol

Patrol #7


P0: Multiple agents can claim same worker identity

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

## Fix Implemented

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

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

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

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


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-eg1es
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


gt crew add: CLAUDE.md customization leaves git dirty

When gt crew add generates a customized CLAUDE.md for crew workers, it differs from the repo version (Crew Worker Context vs Polecat Context, personalized footer). This leaves the git state 'dirty'.

Options:
1. Add CLAUDE.md to .gitignore in crew workspaces
2. Auto-commit the customized CLAUDE.md locally
3. Store crew CLAUDE.md content elsewhere (e.g., .claude/CLAUDE.md)

Current behavior is functional but 'gt crew list' shows 'Git: dirty' for new crew.

Found during: adding crew workers grip, fang, wolf


Add mayor/config.json for town-level configuration

Create new town-level config file:
- Add TownConfig.Config field to types.go
- Create mayor/config.json with theme defaults, daemon settings
- Update loader to read/write mayor/config.json
- Migrate any town-level config from .gastown/ to here


Document bd mol bond/squash/burn CLI

Create CLI reference documentation for molecule commands:

## bd mol bond

Instantiate a proto into a runnable molecule.

```bash
bd mol bond <proto-id> [--wisp] [--assignee=<addr>]
```

- Default: creates a Mol (durable, in main beads)
- --wisp: creates a Wisp (ephemeral, in .beads-ephemeral/)
- --assignee: who will execute this molecule

## bd mol squash

Complete a molecule and generate digest.

```bash
bd mol squash <mol-id> --summary='...'
```

- For Mol: creates digest in git history
- For Wisp: evaporates (no permanent record)
- --summary: required summary of what was accomplished

## bd mol burn

Abandon a molecule without completing.

```bash
bd mol burn <mol-id> [--reason='...']
```

- Discards molecule state
- No digest created
- Use when molecule is no longer needed


bd admin compact --older-than=0 ignores the flag, uses default 30 days

When running bd admin compact --prune --older-than=0, the output says 'No expired tombstones to prune (TTL: 30 days)' - the flag value is ignored.


Add orphaned-attachments doctor check

Add gt doctor check for molecules attached to non-existent agents.

Check: orphaned-attachments
Warning if: Handoff bead exists for agent that no longer has worktree
Fix suggestion: Re-sling to active agent or close molecule


gt session start --issue doesn't inject work to prompt

When starting a polecat session with --issue flag:
  gt session start beads/Toast --issue bd-oxgi

The session starts but the polecat doesn't receive the issue context. They sit at the prompt awaiting input. Had to manually nudge them.

Expected: Session start should either nudge or inject the issue context so polecat starts working immediately (propulsion principle).


Digest: mol-deacon-patrol

Patrol 16: all clear


Digest: mol-deacon-patrol

Patrol 12: Quick cycle, all quiet


Merge: valkyrie-1767074338488

branch: polecat/valkyrie-1767074338488
target: main
source_issue: valkyrie-1767074338488
rig: gastown


Digest: mol-deacon-patrol

Patrol #9: Stable


Digest: mol-deacon-patrol

Patrol #7: Stable


Digest: mol-deacon-patrol

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


P4: Graceful degradation without tmux

Low-priority: Add graceful degradation for environments without tmux.

Current state: Patrol formulas use tmux capture-pane for observing agent state.

tmux-independent alternatives (degraded mode):
1. Tail Claude Code session logs if available
2. Rely solely on agent bead state (less real-time)
3. Use claude --output-file and tail that
4. IPC mechanisms (named pipes, sockets)

NOT launch-blocking. By summer 2025, Claude Code is expected to add signaling and reflection features that will obviate tmux scraping.

For now:
- Keep tmux as primary observation mechanism
- Document the tmux dependency
- Add --no-tmux flag that falls back to bead-only observation

This is P4 backlog - address after liftoff.


survey-workers

List polecats and categorize by status.

```bash
gt polecat list <rig>
```

Needs: load-state


Document Rig/Cook/Run lifecycle

The rig-cook-run.md spec is written. Propagate terminology to all relevant docs: - molecule-algebra.md (done) - molecular-chemistry.md (done) - vision.md (done) - propulsion-principle.md - sling-design.md - Any agent templates that reference cooking/instantiation


Digest: mol-deacon-patrol

Patrol 3: Routine


Implement

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

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


Polecat sessions terminate unexpectedly during work

During swarm bd-784c, polecat sessions (Toast, Nux) terminated mid-task without completing their work.

**Observed:**
- Polecats were actively working (edits in progress, tests running)
- Sessions suddenly showed 'not running' in gt polecat status
- tmux sessions existed but were empty/reset
- Work was partially complete (some commits made, issue still open)

**Impact:**
- Lost work progress
- Required manual intervention to restart
- Unclear if work was saved/committed

**Suggestion:**
- Add session health monitoring
- Auto-restart on unexpected termination
- Log session exit reasons


Digest: mol-deacon-patrol

Patrol 18: All clear


gt mail inbox shows wrong identity when run from deacon directory

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


Polecats go off-task instead of working pinned bead

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

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

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


Burn and respawn or loop

End of patrol cycle decision.

If context is LOW:
- Burn this wisp (no audit trail needed for patrol cycles)
- Sleep briefly to avoid tight loop (30-60 seconds)
- Return to inbox-check step

If context is HIGH:
- Burn wisp with summary digest
- Exit cleanly (daemon will respawn fresh Witness)

```bash
bd mol burn   # Destroy ephemeral wisp
```

The daemon ensures Witness is always running.


Digest: mol-deacon-patrol

Patrol 2: All clear


Test Patrol Parent

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

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

Original description:
Test parent for Christmas Ornament pattern


Enhance gt status with role hierarchy view

Show identity and role hierarchy in gt status:

## Current Output
Flat list of agents by rig, no clear role hierarchy.

## Desired Output
Tree structure showing:
- Town-level roles (Mayor, Deacon)
- Per-rig role slots with their role_bead references
- Each agent slot with pinned work

Example:
```
Town: gt
├── 🎩 Mayor (gt-mayor-role)
│   └── gt-mayor [running] → gt-u7dxq
├── 🔔 Deacon
│   └── gt-deacon [running]
└── Rigs
    └── gastown/
        ├── 👁 Witness (gt-witness-role)
        │   └── gt-witness-gastown [running]
        ├── 🏭 Refinery (gt-refinery-role)
        │   └── gt-refinery-gastown [running] → (work)
        ├── 👷 Crew
        │   ├── jack [running] → gt-xxxx
        │   └── joe [running]
        └── 😺 Polecats
            └── (none)
```

## Key Changes
1. Use tree-style indentation (├── └──)
2. Group agents by role type
3. Show role_bead for each role category
4. Use emojis for quick visual scanning


Digest: mol-deacon-patrol

Patrol 12: all healthy


Digest: mol-deacon-patrol

Patrol 7


Digest: mol-deacon-patrol

Patrol 7: healthy


Digest: mol-deacon-patrol

Patrol 20: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 9: All clear


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.


Fix blocking bugs (gt-dsfi, gt-n7z7, gm-c6b)

Fix bugs blocking Witness functionality:

1. gt-dsfi: handoff deadlock
   - Polecats hang when trying to exit
   - Blocks shutdown request handler

2. gt-n7z7: refinery foreground race condition
   - Sometimes detects parent as already running
   - Blocks reliable Refinery startup

3. gm-c6b: mail coordination
   - Cross-rig mail should use town-level database
   - Affects Witness <-> Mayor communication

These should be fixed early as they'll block integration testing.

Fixed gt-dsfi and gt-n7z7. Issue gm-c6b not found in database.


Load context

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

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


Digest: mol-deacon-patrol

Patrol complete: cleaned 1 orphaned process, all 8 sessions healthy, no stuck wisps


Merge: ace-1767074385080

attached_args: Code review this merge request

branch: polecat/ace-1767074385080
target: main
source_issue: ace-1767074385080
rig: gastown


Update docs to reflect molecule-first paradigm

Gas Town is fundamentally a molecule execution engine. Documentation should reflect this more clearly.

## Issues Found

### 1. gt spawn examples show molecule as optional
README.md line 116: `gt spawn --issue <id> # Start polecat on issue`
Should emphasize: polecats execute molecules, not just issues.

### 2. Architecture.md spawn examples inconsistent
Line 344 shows molecule: `gt spawn --issue gt-xyz --molecule mol-engineer-in-box`
Line 1434 shows without: `gt spawn --issue <id>`

### 3. Config vs molecule distinction not clear
outposts.yaml shows static policy - should note when molecules apply.

### 4. Operational molecules section is good but buried
Lines 430-566 cover operational molecules well. Should be more prominent.

## Updates Needed
- [ ] README: Update spawn examples to show molecule usage
- [ ] architecture.md: Ensure all spawn examples include molecules
- [ ] architecture.md: Add section on "when config vs molecule"
- [ ] architecture.md: Move operational molecules higher in document
- [ ] Add principle: "If it requires cognition, it's a molecule"
- [ ] federation-design.md: Note that policy can escalate to mol-outpost-assign

## Key Message
Gas Town doesn't spawn workers on issues. It spawns workers on molecules.
The issue is just the seed data for the molecule execution.


Remove polecat state derivation from issue status

**File:** polecat/manager.go (lines 556-599)

**Current behavior:**
- Switch on issue.Status to derive polecat state
- Go decides: open/in_progress → Working, closed → Done

**Fix:**
- Polecat state comes from polecat, not inferred by Go
- Polecat signals state via mail or explicit field
- Or: remove state derivation entirely, just report issue status

**Lines to refactor:**
- manager.go:576-588 (switch statement)

**Priority:** P2 - less critical than daemon/heartbeat logic


Digest: mol-deacon-patrol

Patrol 12: Routine


SwarmManager: create, start, update, query operations

SwarmManager operations for creating and managing swarms.

## Interface

```go
type SwarmManager struct {
    rig    *Rig
    beads  *BeadsWrapper  // shells out to bd CLI
}

func NewSwarmManager(rig *Rig) *SwarmManager

// Lifecycle
func (m *SwarmManager) Create(epicID string, workers []string) (*Swarm, error)
func (m *SwarmManager) Start(swarmID string) error
func (m *SwarmManager) UpdateState(swarmID string, state SwarmState) error
func (m *SwarmManager) Cancel(swarmID string, reason string) error

// Queries (delegate to beads)
func (m *SwarmManager) GetSwarm(id string) (*Swarm, error)
func (m *SwarmManager) GetReadyTasks(swarmID string) ([]SwarmTask, error)
func (m *SwarmManager) GetActiveTasks(swarmID string) ([]SwarmTask, error)
func (m *SwarmManager) IsComplete(swarmID string) (bool, error)
```

## Implementation Notes

- `GetReadyTasks` wraps `bd ready --parent <epicID>`
- `IsComplete` checks if all child issues are closed
- State transitions update the epic's description or a tag field
- No separate manifest files - beads IS the source of truth


Digest: mol-deacon-patrol

Patrol 16: all healthy


Digest: mol-deacon-patrol

Patrol 3: quiet, health OK


Digest: mol-deacon-patrol

Patrol 7: all healthy


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.


gt-gastown-polecat-keeper

gt-gastown-polecat-keeper

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


Digest: mol-deacon-patrol

Patrol 15: Mayor OK, 11 sessions


Phase 2: Quiescent agents (Witness, Refinery)

Enable Witness and Refinery to sleep until triggered.

## Scope
- Wake triggers: gt spawn, MR submit, mail, Deacon ping
- Wake SLA: <1 minute
- mol-witness-patrol and mol-refinery-patrol definitions
- Quiescent entry/exit protocol

## Implementation
- Kill tmux session on quiescent entry
- Preserve sandbox (worktree, state files)
- Restart session on wake trigger
- Agent checks pinned, spawns default patrol if naked

Depends: Phase 1 complete


Liftoff implementation plan in Beads

## Context

Session on 2025-12-27 produced three key docs:
- `~/gt/docs/agent-as-bead.md` - Agents ARE beads (identity, hook slots, CV chain roots)
- `~/gt/docs/zfc-violations-audit.md` - Where Go infers instead of trusting agents
- `~/gt/docs/liftoff-plan.md` - 4.5 day plan to self-sustaining Gas Town

## Work Required

### Phase 1: Audit existing beads ✅
- Review all open beads in gt- prefix
- Close obsolete/stale issues
- Update any that need refinement
- Note which existing beads align with liftoff plan

### Phase 2: File new beads ✅
Translate liftoff-plan.md into beads with proper dependencies.

Three pillars:
1. **Pillar 1: Agent Identity** (gt-d0jqp) - schema, slot commands, migration
2. **Pillar 2: Patrol Ignition** (gt-hwka3) - witness/refinery formula wiring
3. **Pillar 3: Polecat Lifecycle** (gt-4a2qt) - recycle/nuke commands, session-per-step

### Phase 3: Review ✅
Human reviews the plan.

## Deliverable

A complete dependency graph in beads that can be:
1. Queried with `bd ready` to find available work
2. Slung to polecats in dependency order
3. Tracked to completion

## References

- ~/gt/docs/liftoff-plan.md - 4.5 day plan
- ~/gt/docs/agent-as-bead.md - Agent identity design
- ~/gt/docs/zfc-violations-audit.md - ZFC violations addressed


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-1wmw - The source issue ID being worked on


HTTP work client: CloudRun dispatch client

## Overview

HTTP client for dispatching work to Cloud Run and streaming results back.

## Implementation

```go
type WorkClient struct {
    serviceURL string
    httpClient *http.Client  // HTTP/2 enabled
}

func NewWorkClient(serviceURL string) *WorkClient {
    return &WorkClient{
        serviceURL: serviceURL,
        httpClient: &http.Client{
            Transport: &http2.Transport{},
            Timeout:   0,  // No timeout for streaming
        },
    }
}

func (c *WorkClient) DispatchWork(ctx context.Context, req WorkRequest) (<-chan WorkEvent, error) {
    // 1. POST to /work
    // 2. Return channel that streams WorkEvents
    // 3. Close channel when done/error
}
```

## Streaming Reader

```go
func (c *WorkClient) streamEvents(body io.Reader, events chan<- WorkEvent) {
    defer close(events)
    decoder := json.NewDecoder(body)
    for {
        var event WorkEvent
        if err := decoder.Decode(&event); err != nil {
            return
        }
        events <- event
    }
}
```

## Files

- `internal/cloudrun/client.go`

## Dependencies

Depends on: gt-9a2.7 (protocol types)
Used by: gt-9a2.8 (CloudRunOutpost)


bd close hooks: context check and notifications

Add hook system to bd close for context checking and notifications.

## Concept

Register hooks that run on every bd close:

# .beads/config.yaml
hooks:
  on_close:
    - command: 'gt context-check'
    - notify: 'Next step ready'

## Use cases

### Context check on close
After closing a step, check if context is getting full.
If >80%, output warning suggesting session cycling.

### Next step notification
Automatically show next ready step (complements --continue).

### Custom actions
User-defined scripts for workflow automation.

## Hook types

- command: Run shell command with env vars (BEAD_ID, BEAD_TITLE, etc)
- notify: Send message to agent
- webhook: POST to URL (future)

## Integration with context detection

The context-check hook could:
1. Capture tmux pane (if in tmux session)
2. Estimate context usage (turn count, output length)
3. If high, output: 'Context at ~85%. Consider cycling.'

## Priority
P2 - nice to have, not blocking launch.

## Related
- gt-qswb (bd mol current)
- gt-fly0 (bd close --continue)


Day 2.6: Define bd agent state command

Add command for agents to write their own state to agent beads.

```bash
bd agent state <agent-id> <state>
# Example: bd agent state gt-mayor running
# States: idle | running | stuck | stopped | dead
```

Implementation:
1. Lookup agent bead by ID
2. Update state field
3. Update last_activity timestamp
4. Trigger bd sync if configured

Also add:
- bd agent heartbeat <agent-id> - just updates last_activity
- bd agent show <agent-id> - show agent bead details

This is the ZFC-compliant way for agents to self-report state.

Delegated to beads repo: bd-uxlb. Assign to beads/crew/dave.


Digest: mol-deacon-patrol

Patrol 20: All healthy - handoff threshold reached


gt sling --on flag for wisp scaffolding

Add --on flag to gt sling for applying forms to existing work:
  gt sling shiny gastown/Toast --on gt-abc123

When --on is specified, implies --wisp (scaffolding existing work).
The form shapes execution of the target bead.


Digest: mol-deacon-patrol

Patrol 9: all quiet


Digest: mol-deacon-patrol

Patrol 6: all healthy


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

P15: stable


Digest: mol-deacon-patrol

Patrol: 2 completions (valkyrie gt-yd98 MQ, scrotus gt-mzal.1 boot proto). 8 polecats working.


Digest: mol-deacon-patrol

P6 clear


Digest: mol-deacon-patrol

Patrol 12: all quiet


Digest: mol-deacon-patrol

Patrol 3: All nominal


Digest: mol-deacon-patrol

Patrol 8: Routine


Digest: mol-deacon-patrol

Patrol 13: all quiet


gt mq retry: retry a failed MR

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

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 10: routine, healthy - midpoint


Extract magic values to named constants

Magic strings and numbers throughout codebase:

Shells list repeated 4x:
- start.go:729, 773, 907
- crew_helpers.go
Pattern: []string{"bash", "zsh", "sh", "fish", "tcsh", "ksh"}

Timing values:
- time.Sleep(500 * time.Millisecond) in multiple places
- WaitForCommand 15*time.Second
- WaitForShellReady 5*time.Second
- Debounce 100ms default

Other magic values:
- "gt-" session prefix
- priority = 2 default
- Mail preview length 500 chars
- Heartbeat ages 5min/15min
- Divergence thresholds 10/50 commits

Suggestion: Add to constants/constants.go:
- SupportedShells
- ShutdownNotifyDelay, ClaudeStartTimeout, ShellReadyTimeout
- SessionPrefix
- DefaultPriority
- MailPreviewMaxLength


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 swarm start: Does not spawn polecat sessions

gt swarm start marks swarm as 'active' but doesn't start any polecat sessions.

Repro:
1. gt swarm create gastown --epic gt-hw6 --worker Toast --worker Nux
2. gt swarm start gt-hw6
3. gt session list - shows no new sessions

Expected: Polecat sessions should start for each worker.
Actual: No sessions started, workers sit idle.


Digest: mol-deacon-patrol

Patrol 12: OK


Digest: mol-deacon-patrol

Patrol 5: 9 sessions healthy


gt-gastown-polecat-morsov

gt-gastown-polecat-morsov

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


mol sling command: attach molecule to agent hook

Add `gt mol sling <molecule-id>` command to attach a molecule to the current agent's hook.

## Behavior

```bash
gt mol sling mol-witness-patrol
```

1. Find agent identity from cwd (witness, polecat, crew, etc.)
2. Find or create agent's handoff bead
3. Attach molecule to handoff bead (attached_molecule field)
4. Create root issue for this molecule instance
5. Instantiate molecule steps under the root

## Difference from mol attach

- `mol attach` attaches to an existing pinned bead
- `mol sling` creates a fresh instance for execution

## Output

```
🧬 Slung mol-witness-patrol on gastown/witness
  Instance: gt-xyz (9 steps)
  First step: inbox-check
```

## Implementation

- Reuse InstantiateMolecule from molecule.go
- Create wrapper issue for the instance
- Set attached_molecule on handoff bead


Polecat identity confusion leads to direct main commits

When polecats spawn without proper identity (due to gt-si6am and gt-y41ep):
1. They think they're mayor
2. They may commit from wrong directory (mayor/rig instead of polecats/<name>)
3. Work goes directly to main, bypassing merge queue

Observed: slit pushed 'gt polecat recycle' directly to main instead of its branch

Root cause:
- gt-si6am: Wrong CLAUDE.md template (says 'Mayor Rig Context')
- gt-y41ep: Env vars not exported (falls back to mayor detection)

Impact: CRITICAL - merge queue entirely bypassed, no refinery review


Swarm doesn't track dynamically added workers

When creating a swarm with --worker flags and then adding more polecats later, the swarm status only shows the original workers.

Steps to reproduce:
1. gt swarm create gastown --epic gt-i26df --worker slit --worker rictus --start
2. Add more polecats: gt polecat add gastown capable
3. gt sling gt-xxx gastown/capable
4. gt swarm status gt-i26df -> only shows slit, rictus

Expected: Swarm tracks all workers that are working on swarm tasks.
Actual: Only original workers shown.


Evaluate pending async gates

Evaluate pending async gates.

Gates are async coordination primitives that block until conditions are met.
The Deacon is responsible for monitoring gates and closing them when ready.

**Timer gates** (await_type: timer):
Check if elapsed time since creation exceeds the timeout duration.

```bash
# List all open gates
bd gate list --json

# For each timer gate, check if elapsed:
# - CreatedAt + Timeout < Now → gate is ready to close
# - Close with: bd gate close <id> --reason "Timer elapsed"
```

**GitHub gates** (await_type: gh:run, gh:pr) - handled in separate step.

**Human/Mail gates** - require external input, skip here.

After closing a gate, the Waiters field contains mail addresses to notify.
Send a brief notification to each waiter that the gate has cleared.


Define meta-formula YAML schema

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

## Proposed Schema

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

## Key Decisions

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

## Deliverables

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


gt spawn --continue for resuming parked molecules

Add `--continue` flag to gt spawn for resuming parked molecules:

```bash
gt spawn --continue gt-mol-root
```

This:
1. Finds molecule root
2. Verifies molecule is in "parked" state (in_progress, no assignee)
3. Checks external deps are now satisfied
4. Spawns polecat with molecule context
5. Polecat reads handoff mail and continues from blocked step

Part of cross-project dependency system.
See: docs/cross-project-deps.md

Depends on: gt-zniu (gt park)
Depends on Beads: bd-zmmy (bd ready resolution)


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-f14c
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Digest: mol-deacon-patrol

Patrol 5: all clear


Digest: mol-deacon-patrol

Patrol 6: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 1: All healthy, no messages


Computed range expansion (for-each over expressions)

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

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

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

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


mol-swarm-cleanup: Post-swarm debris cleanup molecule

After a 20+ worker swarm completed, found significant beads debris:
- 18 stale messages (work assignments, lifecycle requests, swarm instructions)
- 3 completed issues still open/in_progress
- Test messages accumulated

Need: Document a post-swarm checklist or create gt swarm cleanup command that:
1. Closes stale work assignment messages
2. Reviews in_progress issues for completion
3. Closes orphaned lifecycle messages
4. Optionally archives test messages


Digest: mol-deacon-patrol

P11: stable


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

Patrol 8: quiet, 8 sessions healthy


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 6: All clear


test sling pinned


gt-polecat-gastown-testcat

gt-polecat-gastown-testcat

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


Digest: mol-deacon-patrol

Patrol 10: All healthy.


Digest: mol-deacon-patrol

Patrol 18: all healthy, handled 1 handoff msg


MR: gt-test (main)

branch: main
target: main
source_issue: gt-test


gt handoff deadlock at handoff.go:125

When running 'gt handoff -m "message"' after successful MR submit, go panics with 'fatal error: all goroutines are asleep - deadlock\!' at handoff.go:125. The shutdown request still appears to be sent successfully but the command crashes. Stack trace shows issue is in runHandoff select statement.


Update rig init to create refinery as worktree

Modify rig initialization to create refinery as a git worktree instead of a separate clone.

## Changes
- internal/rig/init.go or similar - change refinery setup
- Create worktree at <rig>/refinery/ with branch 'refinery'
- Remove clone logic for refinery
- Update any path assumptions

## Considerations
- Refinery worktree should track main (or its own branch?)
- May need to handle existing rigs (migration path)


gt-polecat-gastown-ace

gt-polecat-gastown-ace

role_type: polecat
rig: gastown
agent_state: running
hook_bead: gt-795e8
role_bead: null


Digest: mol-deacon-patrol

Patrol 17


CLI: rig commands (add, list, show, remove)

GGT needs rig management commands.

Missing Commands:
- gt rig add <git-url> [--name NAME] - Add rig to workspace
- gt rig list - List all rigs with status
- gt rig show <rig> - Show detailed rig info
- gt rig remove <rig> - Remove a rig

PGT Reference: gastown-py/src/gastown/cli/rig_cmd.py

Current State:
- gt init creates rig structure but no ongoing management
- Rig discovery in internal/rig/manager.go but not exposed via CLI


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

Patrol 2: All healthy, no actions


inspect-workers

Capture output for each working polecat.

```bash
gt peek <rig>/<polecat>
```

Needs: survey-workers


Digest: mol-deacon-patrol

Patrol 12: Quiet


Convert MR queue to wisp storage

MR queue should use wisp storage (.beads-wisp/) instead of durable beads.

## Design (Simplified)

With refinery as worktree, polecats and refinery share the same machine. No cross-machine MR coordination needed. Wisps are the natural fit.

### Storage
- Location: `.beads-wisp/mq/<mr-id>.json`
- Format: Same MRFields structure (branch, target, source_issue, worker, rig)
- Lifecycle: Create on submit, delete after merge

### Code Changes

1. **MR Creation** (done.go, mq_submit.go)
   - Write to `.beads-wisp/mq/` instead of `bd create --type=merge-request`
   - Generate ID: `mr-<timestamp>-<random>` or similar

2. **Refinery Query** (refinery/manager.go, engineer.go)
   - Read from `.beads-wisp/mq/` directory
   - List files, parse JSON, process in order

3. **Cleanup**
   - Delete MR file after successful merge
   - On failure, leave file (refinery retries)

### What Stays in Beads
- Source issues (the work being merged) - still tracked in beads
- Merge commits reference source issue ID
- `bd close <issue>` still happens on merge

### Benefits
- No sync overhead for transient MR state
- Simpler model (file per MR, delete when done)
- Consistent with wisp philosophy (ephemeral operational state)

### Not Needed
- Digest squashing (MRs are deleted, not accumulated)
- Cross-machine visibility (single-machine architecture)


Polecats should auto-cleanup after MR submission

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

## Desired Flow

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

## Implementation Options

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

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

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

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


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

## Bug

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

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

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

## Location

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

## Fix

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

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

## Impact

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


Merge: gt-rp0k

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


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

Patrol 13: All healthy


Update gt doctor to check new config locations

Doctor should validate new structure:
- Check mayor/config.json exists and is valid
- Check settings/ exists for each rig
- Warn if old .gastown/ files still exist
- Offer --fix to migrate old locations to new


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-on0i
bonded_ref: arm-toast
bonded_at: 2025-12-23T10:00:00Z


Digest: mol-deacon-patrol

Patrol 2: All systems nominal


Wire polecat-CLAUDE.md template into polecat spawn

The templates/polecat-CLAUDE.md file needs to be copied into each polecat worktree when spawned.

Location: templates/polecat-CLAUDE.md
Target: polecats/<name>/CLAUDE.md (with {{rig}} and {{name}} substituted)

Implementation:
- Update gt polecat spawn (or wherever worktrees are created)
- Template substitution for {{rig}}, {{name}} variables
- Ensure file is created before Claude session starts


Automatic spawn for ready work

Auto-spawn polecats for ready work:

When Witness has capacity (active_workers < max_workers):
1. Query bd ready for unblocked issues
2. Filter to rig-appropriate work (by prefix or epic)
3. For each ready issue up to capacity:
   - gt spawn --issue <id>
   - Track that we spawned for this issue

Configuration (in rig config.json):
- max_workers: 4 (default)
- spawn_delay: 5s between spawns
- auto_spawn: true/false

This enables 'fire and forget' swarming:
- Mayor creates epic with children
- Mayor tells Witness to work epic
- Witness spawns polecats automatically
- Witness cleans up as they complete


Merge: furiosa-1767059690595

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


Verify gt daemon start/stop works

Verify the daemon orchestrator:

```bash
gt daemon start   # Should start and stay running
gt daemon status  # Should show running
gt daemon stop    # Should stop cleanly
```

The daemon is responsible for:
- Respawning the deacon when it exits (context exhaustion)
- Heartbeat monitoring
- Clean shutdown coordination

Test: Start, verify deacon session appears, stop, verify clean exit.


Add gate timeout tracking and notification

Implement timeout and notification logic for gates.

## Timeout Behavior
1. Gate created with timeout (e.g., 30m)
2. Deacon tracks elapsed time during patrol
3. If timeout reached:
   - Notify all waiters: 'Gate timed out'
   - Close gate with timeout reason
   - Waiter can retry, escalate, or fail gracefully

## Notification
- Use gt mail send to notify waiters
- Include gate ID, await type, and reason in message
- Support multiple waiters notification

## Moved from beads
Originally bd-ykqu. Gate notifications are Deacon's job in gastown.


Digest: mol-deacon-patrol

Patrol 9: all clear


Digest: mol-deacon-patrol

Patrol 16: All healthy


Test Patrol for Bonding

Parent issue for mol bond CLI test


gt crew status: Show workspace status

Implement 'gt crew status [<name>]' command:
- Show session state (running/stopped)
- Show git status (branch, uncommitted changes, unpushed)
- Show last commit info
- Show mail inbox status (unread count)
- If no name given, show all crew workers


gt mail send to self: Auto-detect from cwd for handoff mail

When sending mail to yourself (common for handoffs), gt mail send from an agent directory should auto-detect both sender and recipient. Example: gt mail send -s 'HANDOFF' -m '...' from mayor/rig should send to mayor/.


Crew CLAUDE.md overwritten by polecat template

The crew worker CLAUDE.md files (crew/max, crew/joe, crew/jack) have been overwritten with the polecat-CLAUDE.md template content.

**Expected**: Crew workers should have mayor-like context (they share the rig repo, work on main branch, plan work)

**Actual**: Crew CLAUDE.md says 'Polecat ace' and includes polecat-specific instructions (don't push to main, wait for Witness to kill session, etc.)

**Impact**:
- Crew workers getting wrong identity context
- Ready Front planning guidance in gotchas section was lost
- Crew workers told not to push to main (but they should)

**Root cause**: Likely gt polecat template deployment hit crew directories

**Fix needed**:
- Restore crew CLAUDE.md template (or create one if missing)
- Ensure template deployment only targets polecats/ directories
- Add Ready Front planning section to crew template


Digest: mol-deacon-patrol

Patrol #18


mol-outpost-assign: Intelligent work routing to outposts

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

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

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

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

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

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

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

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

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


Expansion operators: expand and map (macros)

Implement macro-style expansion operators:
- expand(target, template) - apply template to single step
- map(molecule, template) - apply template to all matching steps

Templates use {target} substitution for step references.
Rule of Five is the canonical example.


Digest: mol-deacon-patrol

Patrol 8: all healthy


Digest: mol-deacon-patrol

Patrol cycle 16: routine


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.


Dynamic wisp modification: insert, reorder, bond mid-execution

## Vision

Wisps should be living documents that adapt mid-execution, not static scripts.

## Operations Needed

### bd mol insert
Insert a step into a running wisp:
```bash
bd mol insert <wisp-id> --after <step> --step 'security-gate: Review auth changes'
```

### bd mol reorder
Change step order in a running wisp:
```bash
bd mol reorder <wisp-id> --move process-branch --before current
```

### bd mol bond (to wisp)
Attach an entire molecule to a running wisp:
```bash
bd mol bond mol-weekly-maintenance <wisp-id> --after await-work
```

### bd mol skip
Skip a step (with reason):
```bash
bd mol skip <wisp-id> <step> --reason 'Queue empty, skipping summary'
```

## Use Cases

1. **Hotfix priority**: Reorder queue to process urgent MR first
2. **Security gate**: Insert review step when PR touches sensitive files
3. **Scheduled maintenance**: Bond maintenance mol on schedule
4. **Context adaptation**: Skip steps when they don't apply

## Why This Matters

Engine room problems emerge dynamically. The wisp's flexibility lets agents model situations as they evolve, not execute rigid scripts.

GUPP still applies: whatever's on your hook, you run. But the hook contents can adapt.

## Implementation

This requires Beads changes to support wisp mutation:
- Track step ordering in wisp storage
- Support step insertion/deletion/reordering
- Handle bond-to-wisp (spawn steps into existing wisp)
- Preserve audit trail of modifications


Digest: mol-deacon-patrol

Patrol #3: Stable, no changes


gt polecat add should spawn with --dangerously-skip-permissions

When adding polecats via gt polecat add, the subsequent Claude session needs --dangerously-skip-permissions flag to run autonomously.

Currently:
- gt polecat add creates worktree
- tmux new-session spawns 'claude' without flags
- Polecat gets stuck at permission prompts

Needed:
- gt polecat add (or gt sling) should spawn with --dangerously-skip-permissions
- Or store a config in polecat worktree indicating autonomous mode

This is critical for swarm automation - polecats can't self-approve permissions.


Load context

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

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


Digest: mol-deacon-patrol

Patrol 11: quiet


Digest: mol-deacon-patrol

Patrol 9: All healthy.


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy


gt prime should detect mayor role from any rig's mayor/ folder

Currently gt prime only detects the Mayor role when run from town root (~/gt). It should also detect Mayor when run from:
- ~/gt/gastown/mayor/rig (rig's internal mayor dir)
- Any path containing /mayor/ under a rig

This would allow the mayor session to work correctly regardless of which rig directory it's attached to.


generate-summary

Generate a summary for molecule squash.
File any remaining work as issues.

Document any important context for the squash digest.

Depends: submit-merge


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.


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)


Phase 4: Deacon Patrol Loop

$(cat /tmp/phase4.md)


Digest: mol-deacon-patrol

Patrol complete: inbox empty, all agents healthy, cleaned 4 orphans (gt-wx0w, gt-kp3s3, gt-6n1cy, gt-i4lo)


/restart: Personal slash command for in-place agent restart

Create ~/.claude/commands/restart.md that restarts current Gas Town agent in place.

## Detection
- Read tmux session name: gt-mayor, gt-witness-*, gt-refinery-*, gt-polecat-*
- Fallback: check GT_ROLE env var

## Behavior by role
- mayor: gt mayor restart (sends Ctrl-C, loop respawns)
- witness: gt witness restart
- refinery: gt refinery restart
- polecat: gt polecat restart (or witness-mediated)

## Command format
Uses backticks for inline bash to detect context, then instructs Claude to run appropriate restart.


Design: Polecat Beads write access

Design for granting polecats direct beads write access.

## Background

With Beads v0.30.0 tombstone-based rearchitecture, we have solid multi-agent support. Reversing the original read-only decision.

## Benefits

- Simplifies architecture (no mail-based issue filing proxy)
- Empowers polecats to file discovered work
- Beads handles work-disavowal

## Complications

For OSS projects where you cannot commit to project .beads/, need per-rig beads repo configuration.

## Subtasks (implementation)

- gt-zx3: Per-rig beads configuration schema
- gt-e1y: Worker prompting updates for beads access
- gt-cjb: Witness proxy removal
- gt-082: Beads sync in decommission checklist

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


gt mq list: show queue with status/priority/age

Implement 'gt mq list' command to display the merge queue.

Output format:
ID          STATUS       PRIORITY  BRANCH                    WORKER  AGE
gt-mr-001   ready        P0        polecat/Nux/gt-xyz        Nux     5m
gt-mr-002   in_progress  P1        polecat/Toast/gt-abc      Toast   12m
gt-mr-003   blocked      P1        polecat/Capable/gt-def    Capable 8m
            (waiting on gt-mr-001)

Options:
- --ready: show only ready-to-merge (no blockers, not in progress)
- --status STATUS: filter by status
- --worker WORKER: filter by worker
- --epic EPIC: show MRs targeting integration/EPIC

Under the hood: bd list --type=merge-request with filters.

Reference: docs/merge-queue-design.md#gt-mq-list


Work on ga-ct2: Add MR workflow to polecat completion. Wh...

Work on ga-ct2: Add MR workflow to polecat completion. When polecat completes work, auto-create MR to integration branch. When done, submit MR (not PR) to integration branch for Refinery.


Digest: mol-deacon-patrol

Patrol 13: Quiet


Crew workers getting wrong CLAUDE.md (shows Refinery)

## Problem

Crew workers (emma, dave) have CLAUDE.md that says they're the Refinery.

## Evidence

```
$ head -5 /Users/stevey/gt/beads/crew/emma/CLAUDE.md
# Claude: Beads Refinery
You are the **Refinery** for the **beads** rig...
```

## Expected

Should use crew.md.tmpl which correctly says:
```
# Crew Worker Context
You are a **crew worker** - the overseer's (human's) personal workspace...
```

## Impact

- Crew workers have wrong identity in static context
- `gt prime` correctly outputs crew context, but CLAUDE.md conflicts
- Confusing role information

## Fix

Check `gt crew create` or whatever populates CLAUDE.md for crew workers.


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.


Digest: mol-deacon-patrol

Patrol 6: OK


Digest: mol-deacon-patrol

Patrol 10: All clear


gt sling: use mail queue for patrol roles (witness, refinery, deacon)

When slinging work to patrol agents, queue via mail instead of replacing hook.

**Rationale:**
Patrol agents run continuous loops. Replacing their hook with discrete work breaks patrol continuity - when the task completes, the patrol stops.

**New behavior for patrol roles (witness, refinery, deacon):**
1. Check if patrol is running (hook has patrol molecule attached)
2. If patrol running:
   - Don't touch hook (patrol stays pinned)
   - Send work assignment mail
   - Print 'Queued for next patrol cycle'
3. If patrol NOT running:
   - Start default patrol for that role (mol-witness-patrol, mol-refinery-patrol, mol-deacon-patrol)
   - Send work assignment mail
   - Print 'Started patrol and queued work'

**New flags:**
- --urgent: Interrupt current patrol cycle, process this work immediately
- --replace: Explicitly terminate patrol and pin discrete work (break-glass)

**No change for:**
- Polecat, Crew, Mayor (discrete task agents - current behavior)

**Dependencies:**
- Patrol templates must have 'check inbox' step (verify/add)
- Need to know default patrol molecule for each role


ensure-beads-witness

Start the beads rig Witness.

## Action
```bash
gt witness start beads
```

## Verify
1. Session exists: `tmux has-session -t beads-witness 2>/dev/null`
2. Not stalled: `gt peek beads/witness` does NOT show "> Try" prompt
3. Heartbeat fresh: Last patrol cycle < 5 min ago

## OnStall
```bash
gt nudge beads/witness "Start patrol."
sleep 30
# Re-verify
```

## OnFail
Log error. Rig polecats will be unmonitored until Witness recovers.