Documentation humility pass

Update documentation with humble framing.

## Changes Needed

### README.md

- Add "Experimental" or "Alpha" badge
- Clarify current state vs future vision
- List what works vs what is planned
- Include honest limitations section

### Architecture docs

- Mark autonomous features as "planned"
- Distinguish implemented from designed
- Add "Current Status" sections

### CLAUDE.md files

- Remove claims about autonomous operation (where not true)
- Add "v0.1" qualifiers to features
- Be honest about manual steps required

## Tone

NOT: "Gas Town automatically manages agent lifecycles"
YES: "Gas Town provides infrastructure for agent lifecycle management.
     v0.1 requires some manual coordination."

NOT: "The Refinery processes merges autonomously"
YES: "The Refinery is designed for autonomous merge processing.
     v0.1 demonstrates the pattern with manual triggering."

## Files to Review

- README.md
- docs/architecture.md
- docs/quickstart.md (if exists)
- CLAUDE.md files for all roles


Replaceable notifications via Claude Code queue

Leverage Claude Code's ability to replace queued text for notifications that supersede previous ones.

## Problem

If daemon sends 10 heartbeats while agent is busy, agent returns to see 10 stacked messages. Wasteful and noisy.

## Solution

Use Claude Code's queue replacement for:
- Heartbeat messages (only latest matters)
- Status updates that supersede previous
- Progress notifications

## Implementation

Notifications get a 'slot' identifier. New notification in same slot replaces old one:
- Slot: 'heartbeat' → only one heartbeat queued at a time
- Slot: 'status-<rig>' → latest status per rig
- No slot → stacks normally (for unique messages)

## Research Needed

- How does Claude Code expose queue replacement?
- tmux send-keys behavior with pending input
- Alternative: clear + resend pattern


Create mol-install-go-binary molecule

Create a single-step molecule for building and installing the gt binary.

## Molecule Definition
\`\`\`markdown
## Molecule: install-go-binary
Single step to rebuild and install the gt binary after code changes.

## Step: install
Build and install the gt binary locally.

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

Verify the installed binary is updated:
\`\`\`
which gt
gt --version  # if we have version command
\`\`\`
\`\`\`

## Implementation
1. Add to builtin_molecules.go
2. Update SeedBuiltinMolecules to include it
3. Run gt molecule seed

## Acceptance
- [ ] mol-install-go-binary exists in beads
- [ ] Can be instantiated standalone
- [ ] Can be included by other molecules


EXTERNAL: Beads Messaging & Knowledge Graph (bd-kwro)

Tracking issue for external dependency on Beads v0.30.2 messaging features.

Beads epic: bd-kwro in ~/src/beads (steveyegge/beads repo)

This blocks GGT work that depends on:
- bd mail send/inbox/read/ack commands
- message issue type
- replies_to threading
- Hooks system for notifications
- Identity configuration

GGT mail commands will be thin wrappers around bd mail once available.

When bd-kwro ships in Beads v0.30.2, close this and unblock dependent work.


Molecule format bridge: convert embedded markdown to child issues

## Problem

Two molecule formats exist:
1. **Old (gastown builtin)**: Steps embedded as markdown in Description field, parsed by ParseMoleculeSteps()
2. **New (bd mol)**: Steps as child issues in proper beads DAG

The daemon's InstantiateMolecule() uses the old format. bd mol spawn uses the new format.

## Options

### Option A: Require child issues (new format)
- Update daemon to use bd mol spawn instead of InstantiateMolecule
- Deprecate embedded markdown format
- Pro: One format, simpler
- Con: Breaking change for existing molecules

### Option B: Build a bridge
- In InstantiateMolecule, detect format:
  - If Description has ## Step: markers → parse to child issues
  - If issue has children with template label → use directly
- Convert old format to new format on instantiation
- Pro: Backward compatible
- Con: More complexity

## Recommendation

Option B - build the bridge. On instantiation, convert markdown steps to child issues. This unifies execution while preserving authoring flexibility.


Integration test: agent waits for CI via gate

End-to-end test of the gate workflow.

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

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

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


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


Digest: mol-deacon-patrol

Patrol 15: all clear


Digest: mol-deacon-patrol

Patrol 4: Stable


Digest: mol-deacon-patrol

P16: stable


Digest: mol-deacon-patrol

Patrol 12: All agents healthy


Digest: mol-deacon-patrol

Patrol 17: Routine


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


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


Merge: gt-qna4

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


Digest: mol-deacon-patrol

Patrol 4: all healthy


Digest: mol-deacon-patrol

Patrol 19: All healthy


Implement handoffs using pinned beads

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

## Current Problem

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

## Solution

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

## Implementation

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

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

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

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

## Dependencies

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Digest: mol-deacon-patrol

Patrol 14: all clear


refinery Handoff

# Merge queue tracking
last_processed_branch: null
branches_merged_this_cycle: 0


Digest: mol-deacon-patrol

Patrol 6: nominal


Comprehensive help text and examples

Improve help text with examples and cross-references.

## Improvements

### 1. Examples Section
Add to Long description:
```go
var spawnCmd = &cobra.Command{
    Long: `Spawn a polecat with work assignment.

Examples:
  gt spawn gastown/Toast --issue gt-abc
  gt spawn gastown --issue gt-def          # auto-select polecat
  gt spawn gastown/Nux -m "Fix the tests"  # free-form task`,
}
```

### 2. Cross-References
Reference related commands:
```
See also:
  gt polecat list    List available polecats
  gt session attach  Attach to spawned session
```

### 3. Flag Descriptions
More detail on flags:
```go
cmd.Flags().StringVar(&issue, "issue", "",
    "Beads issue ID to assign. The polecat will work on this issue.")
```

### 4. Common Workflows
Add workflow docs to gt --help:
```
Common Workflows:
  Start a swarm:
    gt swarm preflight
    gt swarm create gastown --epic gt-abc --worker Toast --worker Nux --start
    gt refinery start gastown

  Check status:
    gt status
    gt swarm status <id>
```

## Files to Update
All internal/cmd/*.go files

## Acceptance Criteria
- [ ] All commands have Examples
- [ ] Related commands cross-referenced
- [ ] Flags have detailed descriptions
- [ ] Root help shows workflows


Account management for multi-account Claude Code usage

Enable Gas Town to manage multiple Claude Code accounts (e.g., personal vs work) with easy switching. Core mechanism: CLAUDE_CONFIG_DIR env var per account. See docs/design/account-management.md for full design.


Test Patrol Parent

Test parent for Christmas Ornament pattern


Test: Alpha to Beta

Sibling communication test


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


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.


Fix TestHasPolecat test failure in internal/session

TestHasPolecat in internal/session/manager_test.go fails because it expects
specific polecats (Toast, Cheedo) to exist in the test environment.

Error:
```
manager_test.go:46: expected hasPolecat(Toast) = true
manager_test.go:49: expected hasPolecat(Cheedo) = true
```

Fix: Either create test fixtures or mock the filesystem check.


Polecat role references deprecated 'swarm' terminology

prompts/roles/polecat.md line 12 says:
'Part of a swarm: Other polecats may be working on related issues in parallel'

But architecture.md explicitly states:
'There are no swarm IDs - just epics with children'

The swarm concept has been replaced by streams/dependency model.
Update polecat.md to remove swarm references.


Digest: mol-deacon-patrol

Patrol 15: All healthy


Ephemeral protos: Remove proto-as-bead storage, cook inline

## Summary

Refactor the molecular chemistry stack so protos are ephemeral in-memory data structures, not persisted beads with `[template]` labels.

## Current State

```
Formula (.formula.json)  → cook → Proto (bead with [template]) → pour/wisp → Mol/Wisp
```

Protos are stored as beads issues with `labels: ["template"]`, polluting the DB with template definitions that duplicate the formula files.

## Target State

```
Formula (.formula.json)  → pour/wisp (cook inline) → Mol/Wisp
```

Protos exist only as in-memory data structures during the cook→pour/wisp pipeline. Formula catalog IS the proto library.

## Changes Required

1. **Remove template bead storage** - `bd cook` no longer writes to DB
2. **`bd cook` becomes preview** - outputs proto JSON to stdout (like --dry-run)
3. **`bd pour`/`bd wisp` cook inline** - take formula name, cook on the fly
4. **`bd mol bond` accepts formula names** - cooks inline when bonding templates
5. **Remove `[template]` label handling** - no more template beads
6. **Update docs** - molecular-chemistry.md, molecule-algebra.md

## Benefits

- No DB pollution from template beads
- Single source of truth (formulas in .beads/formulas/)
- Simpler mental model: formulas → instances
- Faster (no DB round-trip for protos)

## Deferred

Staged parameterization (proto currying) - punt until someone needs it:
```bash
bd cook mol-feature --var team=backend  # Partially bound proto
bd pour <proto-id> --var priority=high  # Further binding
```

## Depends On

- gt-8tmz (Molecule Algebra) core work should be mostly complete first

## Context

Discussion: Mayor session 2025-12-25, ultrathink on proto storage


Remove redundant gt prime SendKeys from crew commands

The crew commands (gt crew at, gt crew restart) still send 'gt prime' via SendKeys after session creation:
- internal/cmd/crew_at.go:97, 121
- internal/cmd/crew_lifecycle.go:202

This is now redundant because SessionStart hook handles priming automatically.

**Low priority** - these aren't causing bugs (just duplicate work), unlike the spawn race condition that was fixed. Can be cleaned up when convenient.


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


Update documentation for new config architecture

Update docs to reflect new structure:
- docs/architecture.md: Directory structure section
- CLAUDE.md files: Config references
- Add docs/configuration.md with full reference


Merge: gt-yd98

branch: polecat/valkyrie
target: main
source_issue: gt-yd98
rig: gastown


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

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

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

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

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


gt nudge should accept partial/fuzzy session names

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

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

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


Tmux wrapper: session operations

Wrapper for tmux session operations via subprocess.

## Interface

```go
type Tmux struct{}

func NewTmux() *Tmux

// Session lifecycle
func (t *Tmux) NewSession(name, workDir string) error
func (t *Tmux) KillSession(name string) error
func (t *Tmux) HasSession(name string) (bool, error)
func (t *Tmux) ListSessions() ([]string, error)

// Session interaction
func (t *Tmux) SendKeys(session, keys string) error
func (t *Tmux) CapturePane(session string, lines int) (string, error)
func (t *Tmux) AttachSession(session string) error

// Window operations (if needed)
func (t *Tmux) SelectWindow(session string, index int) error
```

## Session Naming

Convention: `gt-<rig>-<polecat>` (e.g., `gt-wyvern-Toast`)

## Implementation

- Shell out to tmux binary
- CapturePane uses `tmux capture-pane -p -t <session> -S -<lines>`
- SendKeys uses `tmux send-keys -t <session> '<keys>' Enter`

## Error Handling

- "no server running": tmux not started (not an error for HasSession)
- "session not found": session doesn't exist
- Wrap all tmux errors with context

## Environment

Requires TMUX_TMPDIR or uses default socket. Don't assume tmux is running.


Digest: mol-deacon-patrol

Patrol cycle 2: quick scan, no changes


Guardrail: Verify commits exist before closing polecat issues

## Updated Approach (ZFC)

The original proposal was for mechanical guardrails in bd close. This contradicts the ZFC principle: all decisions go to models, not code.

## Correct Solution

The verification should happen in **mol-polecat-arm** execute step, not bd close:

In the pre-kill-verify action:
```bash
# Current steps
git status                    # Must be clean
git log origin/main..HEAD     # Check for unpushed
bd show <assigned-issue>      # Verify closed/deferred

# ADD: Verify productive work
git log --oneline --grep='<issue-id>' | head -1
# If no commits AND issue being closed as 'done' → flag for review
```

The agent (Witness) makes the decision. The mol gives it the verification step.

## Why Not Code Guardrails

Polecats have legitimate reasons to close issues without commits:
- Already done (someone else fixed it)
- Deferred (out of scope)
- Escalated (needs human decision)
- Duplicate (merged with another issue)

A code guardrail would block all these. The mol step lets the agent verify AND make the judgment call.

## Implementation

Update mol-polecat-arm execute step to include commit verification for 'done' closures.


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


Digest: mol-deacon-patrol

Patrol 11: Nominal


Digest: mol-deacon-patrol

Final patrol cycle 20: all systems healthy


Add hook-attachment-valid doctor check

Add gt doctor check to verify attached molecules exist and are not closed.

Check: hook-attachment-valid
Error if: Hook's attached_molecule field points to non-existent or closed issue
Fix suggestion: Clear attachment with gt mol detach


gt crew restart command

Add a 'gt crew restart' command that kills the tmux session and restarts fresh. Useful when a crew member gets confused or needs a clean slate.

Should:
- Kill existing tmux session if running
- Start fresh session with claude
- Run gt prime to reinitialize context

Alias: gt crew rs


Digest: mol-deacon-patrol

Patrol #9


Digest: mol-deacon-patrol

Patrol 20: All healthy - final patrol


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


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)


Rename Engineer in Box to Shiny

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

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


Test Polecat Arm

Test child for bonding pattern


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Digest: mol-deacon-patrol

Patrol 13: All healthy


Advice operators: before, after, around

Implement Lisp-style advice operators for molecules:
- before(target, step) - insert step before target
- after(target, step) - insert step after target
- around(target, wrapper) - wrap target with before/after

Support glob patterns for targeting (*.implement, shiny.*, etc).


Selection operators: glob, filter, children

Implement selection operators for targeting:
- step(id) - specific step
- glob(pattern) - pattern match (*.implement)
- filter(predicate) - status/output predicates
- children(step), descendants(step) - tree traversal

Used by advice, expansion, and aspects for targeting.


Blocked issues: gt-um6q, gt-lz13, gt-5xph depend on missing beads features

Template/docs updates blocked on: bd-nurq (bd mol current), bd-29fb (bd close --continue). These gastown issues should be marked blocked on the beads issues once cross-rig deps work.


Digest: mol-witness-patrol

Patrol cycle 1: 3 polecats inspected (nux, slit, furiosa), all working. 4 initial nudges sent. Refinery nudged with 2 MRs. No escalations.


Conditional aspects (feature flags)

Apply aspects conditionally based on environment or config. Example: apply security-audit only when env.SECURITY_SCANNING == enabled. Adds 'when' clause to aspect composition.


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.


Activity Feed TUI

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


Swarm cleanup: delete merged polecat branches and reset state

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

## Current Problem

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

## Observed After Swarm

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

## Proposed Solution

Add cleanup commands:

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

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

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

## Manual Cleanup For Now

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


Fix docs: Formulas are JSON not YAML

The molecular chemistry docs (molecule-algebra.md, molecular-chemistry.md) incorrectly refer to formulas as YAML. Formulas are JSON (.formula.json). Fix all references: .formula.yaml -> .formula.json, 'YAML files' -> 'JSON files', 'formula YAML' -> 'formula JSON', code blocks from yaml to json syntax.


Digest: mol-deacon-patrol

Patrol 9: Routine


Digest: mol-deacon-patrol

Patrol 6: clear


ApplyBranches/ApplyGates mutate steps in place

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

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

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

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

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

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


Find abandoned work

Find abandoned work.

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

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

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


rebase-main

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

git fetch origin main
git rebase origin/main

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

Depends: self-review, verify-tests


Digest: mol-deacon-patrol

Patrol 18


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

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


ZFC Cleanup: Move Go heuristics to Deacon molecule

Remove Go code that makes workflow decisions. All health checking, staleness
detection, nudging, and escalation belongs in the Deacon molecule where Claude
executes it once per minute.

## The Problem

Go code currently implements polling-based health inference:
- Daemon watches heartbeats with hardcoded thresholds
- Decides if agents are "stuck" based on timestamps
- Sends nudges, triggers restarts
- Parses mail subjects with regex to extract intent

This is a ZFC violation. Go should be message transport, not decision-maker.

## The Fix

Move all health/oversight logic to Deacon patrol molecule:
- Deacon runs once per minute
- Claude reads molecule steps, executes them
- Claude decides if agents are stuck (by checking mail, activity, etc.)
- Claude sends nudges/escalations via mail
- Go just routes messages

## Scope

1. daemon/daemon.go - heartbeat staleness logic
2. daemon/backoff.go - exponential backoff decisions
3. daemon/lifecycle.go - regex parsing of lifecycle intent
4. keepalive/keepalive.go - staleness thresholds
5. deacon/heartbeat.go - heartbeat age classification
6. doctor/stale_check.go - staleness detection
7. polecat/manager.go - state derivation from issues

## Success Criteria

- Go code has no hardcoded time.Duration for health decisions
- No regex parsing of mail subjects for intent
- No switch statements deciding agent state
- Deacon molecule has all oversight logic
- Go daemon is just a message router


Add role-specific subcommands that delegate to core commands (agent UX)

## Problem

Agents naturally guess command patterns like:
- `gt witness nudge <polecat>`
- `gt polecat nudge <name>`
- `gt crew restart <member>`

But these don't exist - the actual commands are:
- `gt nudge <session> <message>`
- `gt polecat reset <name>`

This creates friction in agent UX. Agents shouldn't have to memorize the 'correct' command structure.

## Proposal

Add subcommands to each role that delegate to core commands with argument reordering:

```
gt witness nudge furiosa "Start working"
  → gt nudge gt-gastown-furiosa "Start working"

gt polecat nudge gastown/furiosa "Check mail"
  → gt nudge gt-gastown-furiosa "Check mail"

gt crew nudge gastown/max "Wake up"
  → gt nudge gt-crew-gastown-max "Wake up"
```

## Benefits

1. **Discoverable**: Agents explore `gt witness --help` and find nudge
2. **Lenient**: Multiple valid ways to express the same intent
3. **Role-contextual**: Commands under the role namespace feel natural
4. **Extensible**: Pattern works for future subcommands (status, reset, etc.)

## Implementation

Each role command (witness, polecat, crew, refinery) gets thin wrapper subcommands:

```go
// In witness.go
witnessCmd.AddCommand(&cobra.Command{
    Use:   "nudge <polecat> <message>",
    Short: "Nudge a polecat (delegates to gt nudge)",
    RunE: func(cmd *cobra.Command, args []string) error {
        session := formatSession(rig, args[0])
        return runNudge(session, args[1])
    },
})
```

## Future Candidates

Other subcommands to add as role-specific aliases:
- `gt polecat status <name>` (already exists, good pattern)
- `gt witness check <polecat>` → trigger a manual check
- `gt refinery merge <mr-id>` → process specific MR
- `gt crew send <member> <message>` → mail to crew member


Split PGT/GGT harness or migrate to GGT-only

Current ~/ai harness is shared by PGT and GGT with confusing overlap. Options:
1. Keep separate (document the coexistence)
2. Migrate fully to GGT structure
3. Create separate harnesses

This affects the beads redirect, Mayor home location, and rig structure.


bd create should support molecule type

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


Test Patrol Parent

Test parent for Christmas Ornament pattern


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.


Phase 5: Integration and Demo

$(cat /tmp/phase5.md)


Add --account flag to gt spawn and gt crew attach

Add --account=<handle> flag. Precedence: GT_ACCOUNT env > --account flag > default from config.


Merge: gt-oiv0

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


Digest: mol-deacon-patrol

Patrol 2: All healthy - no changes from cycle 1


Digest: mol-deacon-patrol

Patrol 15: All healthy


Digest: mol-deacon-patrol

Patrol 18: All healthy


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 12: All healthy


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


Test Patrol Parent

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

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

Original description:
Test parent for Christmas Ornament pattern


Digest: mol-deacon-patrol


Execute registered plugins

Execute registered plugins.

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

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

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

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

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

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


Document Overseer role (human operator)

Document the Overseer role in Gas Town architecture.

## The Overseer

The **Overseer** is the human operator of Gas Town. Not an agent - a person.

## Responsibilities

| Area | Overseer Does | Mayor/Agents Do |
|------|---------------|-----------------|
| Strategy | Define project goals | Execute toward goals |
| Priorities | Set priority order | Work in priority order |
| Escalations | Final decision on stuck work | Escalate to Overseer |
| Resources | Provision machines | Use allocated resources |
| Quality | Review & approve swarm output | Produce output |
| Operations | Run gt commands, monitor dashboards | Do the work |

## Key Interactions

### Overseer → Mayor
- Start/stop Mayor sessions
- Direct Mayor via conversation
- Review Mayor recommendations
- Approve cross-rig decisions

### Mayor → Overseer (Escalations)
- Stuck workers after retries
- Resource decisions (add machines, polecats)
- Ambiguous requirements
- Architecture decisions

## Operating Cadence

Typical Overseer workflow:
1. Morning: Check status, review overnight work
2. During day: Monitor, respond to escalations, adjust priorities
3. End of day: Review progress, plan next batch

## Commands for Overseers

```bash
gt status              # Quick health check
gt doctor              # Detailed diagnostics
gt doctor --fix        # Auto-repair issues
gt inbox               # Messages from agents
gt stop --all          # Emergency halt
```

## Documentation Updates

Add to docs/architecture.md:
- Overseer section under Agent Roles
- Clarify Mayor reports to Overseer
- Add Overseer to workflow diagrams


Digest: mol-deacon-patrol

Patrol 11: All clear


working

Actively working. Monitor for stuck.

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

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


Digest: mol-deacon-patrol

Patrol 16: routine


Merge: gt-83k0

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


Test Polecat Arm

Test child for bonding pattern


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.


Auto-handoff: self-cycling with guaranteed work pickup

## Summary

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

## Use Case

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

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

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

## Key Requirements

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

## Design Questions

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

## Related

- Molecules system
- Deacon lifecycle management
- Handoff hooks


Digest: mol-deacon-patrol

Patrol complete: 0 messages, agents healthy, no cleanup needed


Digest: mol-deacon-patrol

Patrol 6: All healthy


Nested loop support in control flow

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

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

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

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


Digest: mol-deacon-patrol

Patrol 13: All healthy


Refinery patrol: Add banners and wisp-based execution

Bring Refinery patrol up to Deacon's level of sophistication:

## Current state
- mol-refinery-patrol exists (needs verification)
- Basic merge queue processing

## Needed
1. **Banners** - Print step banners like Deacon does:
   ```
   ═══════════════════════════════════════════════════════════════
     ⚗ QUEUE-CHECK
     Processing merge queue entries
   ═══════════════════════════════════════════════════════════════
   ```

2. **Wisp-based execution** - Spawn patrol as wisp, squash when complete
3. **Handoff bead attachment** - Refinery needs its own handoff bead with attached_molecule
4. **Loop-or-exit step** - Context-aware cycling like Deacon
5. **Patrol summary banner** at end of each cycle

## Reference
See Deacon patrol implementation in ~/gt/deacon/CLAUDE.md


gt session capture: Support positional line count argument

Make 'gt session capture gastown/Toast 50' work.

Currently requires: gt session capture gastown/Toast -n 50
Should also accept: gt session capture gastown/Toast 50

Agent UX principle: commands should work the way agents guess they work.


Bug: MRs appearing in bd ready output

merge-request beads are showing up in `bd ready` output alongside actual work items.

## Problem
`bd ready` is meant to show work available for polecats to claim. MRs are internal workflow items processed by the Refinery, not polecat work.

## Example
```
| P1 | merge-request | bd-3zzh | Merge: bd-tvu3 |
| P1 | merge-request | bd-fcl1 | Merge: bd-au0.5 |
```

## Possible Fixes
1. **Filter by type** - `bd ready` excludes type=merge-request, type=gate, type=molecule
2. **Set assignee on submit** - MR assigned to refinery/ when created, so not 'unassigned'
3. **Set status=in_progress** - MR starts in_progress since it's queued for processing

## Related
- gate beads also showing (bd-hyp6, bd-wu62) - same issue


Digest: mol-deacon-patrol

Patrol 8: all quiet


Digest: mol-deacon-patrol

Patrol complete: routine cycle


Digest: mol-deacon-patrol

Patrol 10: Nominal - halfway point


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

Patrol 2: All healthy, no actions


Digest: mol-deacon-patrol

Patrol 2: Quick scan, no changes


mol-deacon-patrol

Mayor's daemon patrol loop.

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


mol-deacon-patrol


Fix patrol role priming

Patrol roles (deacon, witness, refinery) need proper context priming.

Current issue: Sessions start but may not have proper CLAUDE.md context.

Fix:
1. Ensure role templates include patrol formula reference
2. Verify SessionStart hook runs gt prime
3. Check that patrol loop starts automatically

Related: Role templates in internal/templates/roles/*.md.tmpl


Deacon trigger-pending-spawns: Auto-nudge polecats when ready

The Deacon's mol-deacon-patrol defines a trigger-pending-spawns step, but it's not implemented.

## Problem
After gt spawn creates a polecat session, Claude initializes for 10-20s. Nobody sends the initial 'Begin.' message to start work, so polecats sit at prompts forever.

## Current Workaround
Manual: gt nudge gt-<rig>-<polecat> 'Begin.'

## Required Implementation
1. Track pending spawns (polecats spawned but not triggered)
2. In Deacon patrol, poll WaitForClaudeReady for each pending spawn
3. When ready, send 'Begin.' via NudgeSession
4. Mark as triggered

## Evidence
Tracer bullet 2025-12-23: Had to manually nudge polecat/tracer to start work.


Digest: mol-deacon-patrol

Patrol 14: All clear


Execute registered plugins


Daemon should auto-start as part of town bootstrap

The Go daemon should be started automatically when the town boots up (mol-gastown-boot). Currently it requires manual 'gt daemon start'.

The daemon is critical infrastructure - it monitors the Deacon and nudges it when naked. Without it, the Deacon patrol loop doesn't run.


Merge: gt-rana.2

branch: polecat/nux
target: main
source_issue: gt-rana.2
rig: gastown


Digest: mol-deacon-patrol

Patrol 13: Mayor OK, 11 sessions


Digest: mol-deacon-patrol

Patrol 1: All healthy, no mail, no action needed


Polecat template cleanup

Collection of improvements to the polecat role template (polecat.md.tmpl). Focus: reduce prose redundancy, move behavior into molecules, fix terminology, improve clarity.


Design GGT prompt architecture

Audit PGT prompts and design canonical prompt system for GGT. Create docs/prompts.md with inventory, gap analysis, and Witness prompt design.


Digest: mol-deacon-patrol

Patrol 14: Quick cycle, all quiet


Async Coordination Gates

Agents wait for external events without polling.

## Problem
Agents cannot wait for external conditions (CI completion, human approval, timers) without wasteful polling or losing state on handoff.

## Requirements
- Gate issue type in beads (type=gate)
- bd gate create --await timer:5m / gh:run:123 / human:approve / mail:pattern
- Deacon evaluates pending gates each patrol cycle
- Agents park work on gate, resume when condition met
- Gate timeout and notification

## Gate Types
- timer:<duration> - Simple delay (5m, 1h, 24h)
- gh:run:<id> - GitHub Actions run completion
- gh:pr:<id> - PR merged/closed
- human:<prompt> - Human approval required
- mail:<pattern> - Wait for mail matching pattern

## Success Criteria
- Agent can create gate and suspend work
- Deacon wakes agent when gate condition met
- Gates survive session cycling

Consolidates gt-31eg. Parallel work with no dependencies.


Digest: mol-deacon-patrol

Patrol 2: routine, all healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Test Patrol Parent

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

Original description:
Test parent for Christmas Ornament pattern


Digest: mol-deacon-patrol

Patrol 3: Quiet, all healthy


Digest: mol-deacon-patrol

Patrol 20: Final cycle, all services healthy, handoff


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

Patrol 18


Digest: mol-deacon-patrol

Patrol 19


End-to-end integration test

Create and run end-to-end integration test.

## Test Scenario

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

## Test Script

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

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

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

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

# 4. Watch
gt status
gt polecats gastown

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

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

## Success Criteria

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


Witness commands: gt witness start/stop/status needed

## Summary

No `gt witness` command exists. The witness should:
- Monitor polecats for stuck/idle state
- Nudge polecats that seem blocked
- Report status to mayor
- Handle polecat lifecycle

## Expected Commands

```bash
gt witness start gastown   # Start witness for rig
gt witness stop gastown    # Stop witness
gt witness status          # Show witness status
```

## Current State

- Witness directory exists: /Users/stevey/gt/gastown/witness/
- Has state.json but no active process
- gt status shows 'Witnesses: 0'

## Context

Full polecat flow needs witness monitoring for production use.


Add migration path for existing rigs

Existing rigs have refinery as clone. Need migration path.

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

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


Test issue for spawn molecule


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


Witness role describes incorrect commands

prompts/roles/witness.md line 44 shows:
  gt polecat list {{ rig }}

But polecats are worktrees managed by Refinery/Mayor's clone,
not a separate polecat manager. The witness shouldn't manage
polecats directly.

Review and update witness role to match actual architecture.


Plugin system: subprocess JSON protocol

Language-agnostic plugin system via subprocess JSON protocol.

## Concept

Allow extending Gas Town with external scripts/programs. Plugins communicate via stdin/stdout JSON.

## Protocol

Request (gt → plugin):
```json
{"method": "check", "params": {"rig": "wyvern", "polecat": "Toast"}}
```

Response (plugin → gt):
```json
{"result": {...}, "error": null}
```

Error response:
```json
{"result": null, "error": {"code": 1, "message": "..."}}
```

## Interface

```go
type Plugin struct {
    Name    string
    Path    string  // executable path
    Methods []string
}

type PluginManager struct {
    plugins map[string]*Plugin
}

func NewPluginManager() *PluginManager
func (pm *PluginManager) Register(plugin *Plugin) error
func (pm *PluginManager) Call(plugin, method string, params any) (any, error)
func (pm *PluginManager) Discover(dir string) error  // auto-discover plugins
```

## Plugin Discovery

Look in:
1. `<town>/plugins/`
2. `~/.config/gastown/plugins/`
3. System path with `gt-plugin-*` prefix

## Built-in Hooks

Plugins can register for events:
- `polecat.started` - Polecat session started
- `polecat.done` - Polecat signals done
- `merge.requested` - MR submitted
- `merge.completed` - MR merged

## Use Cases

- Custom health checks
- Integration with external systems (Slack, etc.)
- Custom merge policies
- Metrics collection

## Future

Consider MCP integration for richer plugin capabilities.


Digest: mol-deacon-patrol

Patrol 20: Final cycle, all clear, handoff triggered


gt rig add / gt doctor: patrol awareness and wiring

## Problem

When a rig is installed or audited, we need to ensure all built-in patrols and role hooks are properly wired up.

## gt rig add Changes

When adding a rig, automatically:

1. **Create patrol molecules** for each role:
   - mol-deacon-patrol (town-level)
   - mol-witness-patrol (per-rig)
   - mol-refinery-patrol (per-rig)

2. **Set up hooks** that trigger patrols:
   - Deacon: daemon timer / heartbeat
   - Witness: daemon timer / polecat lifecycle events
   - Refinery: MR submission events / daemon timer

3. **Configure daemon** to manage these patrols:
   - Register patrol molecules in daemon config
   - Set up respawn behavior for each role

4. **Create plugin directories**:
   - ~/gt/plugins/ (town-level)
   - <rig>/plugins/ (rig-level, if needed)

## gt doctor Changes

Add patrol health checks:

### patrol-molecules-exist
- Verify mol-deacon-patrol, mol-witness-patrol, mol-refinery-patrol exist
- Check they parse correctly (valid steps, dependencies)

### patrol-hooks-wired
- Verify hooks trigger patrol execution
- Check daemon is configured to manage patrols

### patrol-not-stuck
- Detect wisps that have been in-progress too long
- Flag orphaned patrol molecules (no active session)

### patrol-plugins-accessible
- Verify plugin directories exist and are readable
- Check plugin frontmatter parses correctly

### patrol-roles-have-prompts
- Verify prompts/roles/*.md exist for each role
- Check they reference the correct patrol molecule

## Auto-fix

gt doctor --fix can:
- Create missing patrol molecules
- Wire up missing hooks
- Create plugin directories
- NOT restart stuck patrols (needs human decision)

## Related
- gt-7920 (mol-refinery-patrol)
- gt-7921 (await-work and plugin-run)
- docs/wisp-architecture.md


Digest: mol-deacon-patrol

Patrol 4: All healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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


Digest: mol-deacon-patrol

P6 clear


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)


Add 'wit' alias for witness command

ref works as alias for refinery, but wit doesn't work for witness. Add Aliases: []string{"wit"} to witnessCmd.


mol-deacon-patrol


self-review

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

Fix any issues found before proceeding.

Depends: implement


Digest: mol-deacon-patrol

Patrol 6: All healthy


Digest: mol-deacon-patrol

Old test patrol cycle - cleanup


Digest: mol-deacon-patrol

Patrol 14: All healthy, read Mayor handoff (info)


Digest: mol-deacon-patrol

Patrol 11


test message


Hardcoded session ID prefixes and paths

Multiple hardcoded values throughout code:
- internal/mail/router.go: 'gt-mayor', 'gt-' session prefixes
- internal/lock/lock.go: '.runtime', 'agent.lock' paths
- Session ID generation uses string literals

Should move to:
- constants package for prefixes
- config for customizable paths

Low priority but improves maintainability.


Digest: mol-deacon-patrol

Patrol 20: all quiet - handoff cycle


gt rig reset: clear stale mail on reset/land

## Problem

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

## Current State

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

## Proposed Behavior

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

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

## Implementation

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


gt park command for parking molecules on external deps

Add `gt park` command for when polecat hits external dependency:

```bash
gt park --step=gt-mol.3 --waiting="beads:mol-run-assignee"
```

This command:
1. Adds blocked_by: external:beads:mol-run-assignee to the step
2. Clears assignee on the step
3. Clears assignee on molecule root
4. Sends handoff mail to self with context
5. Shuts down polecat session

The molecule enters "parked" state (derived: in_progress + no assignee + blocked step).

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

Depends on Beads: bd-om4a (external: blocked_by support)


Digest: mol-deacon-patrol

Patrol 16: all quiet


Digest: mol-deacon-patrol

Patrol 15: All clear


Add tests for gt crew restart --all

Add integration tests for the crew restart flow:

- Test getAgentSessions() correctly identifies crew sessions
- Test --rig filtering works correctly
- Test --dry-run outputs correct targets
- Test session kill/recreate cycle (without Claude)

Consider extracting a SessionStarter interface to mock the claude-launching bit.

Related: gt crew restart --all was just implemented.


Keepalive signal from bd/gt commands

Every bd and gt command should touch a keepalive file to signal 'agent is alive/working'.

## Implementation

Touch `<workspace>/.gastown/keepalive.json`:
```json
{"last_command": "bd show gt-99m", "timestamp": "2025-12-18T13:45:00Z"}
```

## Usage by Daemon

- Fresh (< 2 min) → agent is working, skip heartbeat
- Stale (2-5 min) → might be thinking, gentle poke
- Very stale (> 5 min) → likely idle, safe to interrupt

## Benefits

- Zero cost (just file I/O)
- Works during long tool calls
- Doesn't require agent cooperation
- Foundation for smarter backoff strategies


Digest: mol-deacon-patrol

Patrol 14: All healthy, no messages


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol 9: all quiet