Document how to configure a Gas Town Harness

Create docs explaining what a harness is (private repo containing GT installation with rigs gitignored), why you'd want one, and how to set it up with beads redirects


Ephemeral rig support for ad-hoc batch work

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

## Use Case

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

## Interface

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

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

## Directory Structure

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

## Cleanup Trigger

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

## Note

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

## Reference

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


Mayor startup protocol prompting

Add startup protocol to Mayor CLAUDE.md template.

## On Session Start

1. Check for handoff:
   town inbox | grep "Session Handoff"

2. If handoff found:
   - Read it: town read <msg-id>
   - Process pending escalations (highest priority)
   - Check status of noted swarms
   - Verify rig health matches notes
   - Continue with documented next steps

3. If no handoff:
   town status     # Overall health
   town rigs       # Each rig
   bd ready        # Work items
   town inbox      # Any messages
   Build your own picture of current state.

4. After processing handoff:
   - Archive or delete the handoff message
   - You now own the current state

## Handoff Best Practices

- Be specific: 'Toast has merge conflict in auth/middleware.go' not 'Toast is stuck'
- Include context: Why decisions are pending, what you were thinking
- Prioritize next steps: What is most urgent
- Note time-sensitive items: Anything that might have changed since handoff


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

Work on gt-role-template: Refine witness/CLAUDE.md role template. See issue for details. Run 'bd show gt-role-template' to see the full issue.


Direct landing integration: gt land uses MR or bypasses

Integrate direct landing with merge queue.

'gt land --direct' should:
1. Check if MR exists for the polecat's work
2. If MR exists: process it directly (skip queue)
3. If no MR: create temporary MR, process, close

Options:
- --direct: bypass queue (existing)
- --via-queue: ensure goes through queue (new)
- --force: skip safety checks (existing)

This ensures direct landing still creates proper records.

Reference: docs/merge-queue-design.md#direct-landing-bypass-queue


Fix role detection for nested rig structures

When gastown/ has its own mayor/ dir, workspace detection finds it as town root instead of ~/ai. This breaks polecat/refinery/witness detection when running from within a rig.


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

## Context

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

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

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

## Background

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

## Investigation Steps

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

## Key Question

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

## Commands

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


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


Work on ga-y6b: Implement Refinery as Claude agent. Conve...

Work on ga-y6b: Implement Refinery as Claude agent. Convert from shell to Claude agent that processes MRs in merge queue, runs tests, merges to integration branch. When done, submit MR (not PR) to integration branch for Refinery.


Work assignment messages should auto-close on completion

When a polecat completes work on an issue, the work assignment message (msg-type:task) stays open. Found 7 stale work assignments in gastown after swarm completed.

Proposal: When bd close is called on an issue, auto-close any work assignment messages that reference that issue in their body.

Alternative: Work assignment messages could use a different lifecycle - perhaps they should be acked (closed) when the polecat starts working, not when they finish.


Molecule converge: iterate until AI says done

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

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

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

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

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

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


Session management: start, stop, attach, capture

Polecat session lifecycle management.

## Interface

```go
type SessionManager struct {
    tmux *Tmux
    rig  *Rig
}

func NewSessionManager(tmux *Tmux, rig *Rig) *SessionManager

// Lifecycle
func (sm *SessionManager) Start(polecat string, opts StartOptions) error
func (sm *SessionManager) Stop(polecat string) error
func (sm *SessionManager) IsRunning(polecat string) (bool, error)
func (sm *SessionManager) List() ([]SessionInfo, error)

// Interaction
func (sm *SessionManager) Attach(polecat string) error
func (sm *SessionManager) Capture(polecat string, lines int) (string, error)
func (sm *SessionManager) Inject(polecat string, message string) error

type StartOptions struct {
    WorkDir   string   // defaults to polecat clone dir
    Issue     string   // optional: issue to work on
    Command   string   // optional: override claude command
}

type SessionInfo struct {
    Polecat   string
    SessionID string
    Running   bool
    StartedAt time.Time
}
```

## Session Naming

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

## Start Flow

1. Verify polecat clone exists
2. Check no existing session
3. Create tmux session in polecat workdir
4. Send initial command: `claude` or custom
5. If issue provided, inject initial prompt

## Stop Flow

1. Capture final output (for logging)
2. Send exit/quit command
3. Wait briefly for graceful shutdown
4. Kill session if still running

## Capture

Uses tmux capture-pane to get recent output. Returns last N lines.

## Inject

Sends text to session via tmux send-keys. Used for:
- Mail notifications
- Witness nudges
- User messages


gt crew at/attach: Start session in crew workspace

Implement 'gt crew at <rig>/<name>' and 'gt crew attach <name>' commands:
- Start tmux session (optional - could just print cd instructions)
- Launch claude code in the workspace
- Deliver any pending mail
- Support --no-tmux to just print directory path
- 'attach' infers rig from cwd


Swarm: ephemeral rig support

PGT has ephemeral rigs for swarms - temporary worker groups that are destroyed after landing.

Missing Features:
- gt swarm init [--rig <name>|--git-url <url>] [--num-workers N]
- gt swarm worker add/remove/list <rig-id>
- gt swarm rigs - List ephemeral rigs
- gt swarm destroy <rig-id> - Destroy ephemeral rig

Directory structure:
<workspace>/mayor/workers/<rig-id>/
├── rig.json (metadata)
├── alice/ (git clone)
├── bob/
└── carol/

PGT Reference: gastown-py/src/gastown/ephemeral.py

Note: Beads issue gt-kmn.12 mentions this but implementation is missing.


gt done: Missing command referenced in polecat docs


Retry logic: exponential backoff for transient failures

Implement retry logic for transient failures.

Retryable failures:
- Push failed (network, auth transient)
- Test flaky (config: retry_flaky_tests)
- Fetch failed (network)

Retry strategy:
- Max retries: 3 (configurable)
- Backoff: 1s, 2s, 4s (exponential)
- On final failure: treat as permanent, assign back

Non-retryable failures:
- Merge conflict
- Test consistently fails
- Build error

Track retry count in MR metadata for debugging.

Reference: docs/merge-queue-design.md#failure-recovery


Phase 4.2: Witness/Refinery patrol molecules

Extend ephemeral patrol pattern to Witness and Refinery.

## Witness Patrol Cycle

mol-witness-patrol-cycle:
1. scan-polecats: Check each polecat status
2. detect-stalls: Find stuck/idle polecats
3. nudge-or-escalate: Take action on stalls
4. log-status: Record cycle results
→ Squash with summary

## Refinery Patrol Cycle

mol-refinery-patrol-cycle:
1. scan-queue: Check merge queue
2. process-ready: Merge ready MRs
3. handle-failures: Deal with conflicts/failures
4. log-status: Record cycle results
→ Squash with summary

## Quiescent Mode

When no work: just log 'no activity' summary.
Witness and Refinery can sleep between cycles until triggered.


Digest: mol-deacon-patrol

Test patrol cycle - verifying wisp flow


request-shutdown

Send shutdown request to Witness.
Wait for termination.

The polecat is now ready to be cleaned up.
Do not exit directly - wait for Witness to kill the session.

Depends: generate-summary


Implement pinned beads for handoff state

Add pinned bead support to beads:
- Pinned beads never close, only update
- Use for persistent state like Refinery handoffs
- bd create --pinned flag
- bd list --pinned to find them
- Update description to change state


Epic: Wisp Molecule Integration

## Vision

Integrate Beads wisp molecules into Gas Town. All orchestration work runs as wisp molecules - patrols, polecat workflows, batch operations. Only digests reach main beads.

## The Steam Engine Metaphor

```
Engine does work → generates steam
Steam wisps rise → execution trace
Steam condenses → digest (distillate)
Steam dissipates → cleaned up (burned)
```

## Architecture

```
Proto Molecules (templates)
    ↓ bd mol bond
Wisps (.beads-wisps/ or inline)
    ↓ bd mol squash + AI summary
Main Beads (digests only)
```

## Vocabulary

| Term | Meaning |
|------|---------|
| bond | Attach proto to work (creates wisps) |
| wisp | Temporary execution step (steam rising) |
| squash | Condense wisps into digest |
| burn | Destroy wisps without record |
| digest | Permanent condensed record (distillate) |

## Key Design Decisions

1. **Wisp location**: Per-rig or inline in main beads with wisp flag
2. **Summary generation**: Agent that did work generates summary (inversion of control)
3. **Squash timing**: Final step of molecule workflow, before signaling done
4. **Crash recovery**: Wisps persist, Witness detects stalls, new agent resumes
5. **Patrols**: Each cycle is fresh wisp molecule, squashed on completion

## Digest Contents

- Molecule type and instance ID
- Assignee, start/end times
- Source issue reference
- AI-generated summary
- Outcomes (issues closed, commits, branches)

## Integration Points

- gt rig init: Configure wisp storage
- gt spawn --molecule: Bond creates wisps
- gt prime: Show wisp molecule context
- Polecat CLAUDE.md: Summary + squash protocol
- gt doctor: Wisp health checks
- Deacon/Witness/Refinery: Patrol molecules

## Phases

Phase 1: Wisp setup infrastructure
Phase 2: Spawn integration
Phase 3: Completion flow (summary + squash)
Phase 4: Patrol integration
Phase 5: Documentation and polish


Mayor handoff mail template

Add MAYOR_HANDOFF mail template to templates.py.

## Template Function

def mayor_handoff(
    active_swarms: List[SwarmStatus],
    rig_status: Dict[str, RigStatus],
    pending_escalations: List[Escalation],
    in_flight_decisions: List[Decision],
    recent_actions: List[str],
    delegated_work: List[DelegatedItem],
    user_requests: List[str],
    next_steps: List[str],
    warnings: Optional[str] = None,
    session_duration: Optional[str] = None,
) -> Message:
    metadata = {
        'template': 'MAYOR_HANDOFF',
        'timestamp': datetime.utcnow().isoformat(),
        'session_duration': session_duration,
        'active_swarm_count': len(active_swarms),
        'pending_escalation_count': len(pending_escalations),
    }
    # ... format sections ...
    return Message.create(
        sender='mayor/',
        recipient='mayor/',
        subject='Session Handoff',
        body=body,
        priority='high',
    )

## Metadata Fields

- template: MAYOR_HANDOFF
- timestamp: ISO format
- session_duration: Human readable
- active_swarm_count: Number of active swarms
- pending_escalation_count: Number of escalations

## Mail Priority

Use priority='high' to ensure handoff is seen on startup.


orphan-check

Find abandoned work. Check for in_progress issues with no active agent.


MR: gt-test (main)

branch: main
target: main
source_issue: gt-test


Molecules: Composable Workflow Beads

## Summary

Molecules are crystallized workflow patterns stored as Beads issues.
When instantiated, the molecule creates child beads forming a DAG.

## Key Insight: Molecules ARE Beads

Per HOP Decision 001: Beads IS the ledger. Molecules don't get a separate YAML format - they're issues with `type: molecule` containing prose-based step definitions.

Agents don't need rigid schemas. They parse natural language natively. A molecule is just instructions with enough structure for tooling.

## Example: Engineer in a Box

```markdown
id: mol-xyz
type: molecule
title: Engineer in a Box

This workflow takes a task from design to merge.

## Step: design
Think carefully about architecture. Consider existing patterns,
trade-offs, testability.

## Step: implement
Write clean code. Follow codebase conventions.
Needs: design

## Step: review
Review for bugs, edge cases, style issues.
Needs: implement

## Step: test
Write and run tests. Cover happy path and edge cases.
Needs: implement

## Step: submit
Submit for merge via refinery.
Needs: review, test
```

## Instantiation

```bash
# Attach molecule when spawning
gt spawn --issue gt-abc --molecule mol-xyz

# Creates child beads atomically:
gt-abc.design     ← ready first
gt-abc.implement  ← blocked by design
gt-abc.review     ← blocked by implement
gt-abc.test       ← blocked by implement
gt-abc.submit     ← blocked by review, test
```

Each step issue gets an `instantiated-from` edge to the molecule (with step metadata).

## Why This Matters

1. **Unified data plane**: Everything in Beads, no parallel YAML channel
2. **AI-native**: Prose instructions, not rigid schemas
3. **Error isolation**: Each step is a checkpoint - failure doesn't lose progress
4. **Scales with AI**: As agents get smarter, they handle more complex molecules

## Implementation Primitives

- `ParseMoleculeSteps()`: Extract steps from prose (convention-based)
- `InstantiateMolecule()`: Atomic transaction creating all steps + edges
- `instantiated-from` edge type: Track provenance
- Parameterization: `{{variable}}` substitution from context map


VC Pattern Integration: Bring validated ideas to Gas Town

Analysis of ~/src/vc identified 6 validated patterns from the 2nd orchestrator attempt that map cleanly to Gas Town primitives. VC achieved 254 issues closed, 90.9% gate pass rate, and 24 successful missions.

Key insight: VC built ~4300 lines of Go for features that become ~65 lines of YAML + CLI flags in Gas Town's architecture.

Child tasks track each pattern to integrate.


CloudRun worker container: Dockerfile and entrypoint

## Overview

Docker container image for Cloud Run workers.

## Dockerfile

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

FROM ubuntu:22.04

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

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

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

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

## Entrypoint

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

## Files

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

## Dependencies

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


submit-merge

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

gt done  # Signal work ready for merge queue

If there are CI failures, fix them before proceeding.

Depends: rebase-main


TIDY UP: Your previous work (patrol runner) was already m...

TIDY UP: Your previous work (patrol runner) was already merged to main. Check your git status is clean, sync beads, and if nothing to do, just run 'gt done'.


Merge: gt-5af.6

branch: polecat/Slit
target: main
source_issue: gt-5af.6
rig: gastown


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


Add unit tests for daemon package

The daemon package has no unit tests. Need tests for:
- Config and state serialization
- Session name pattern matching (isWitnessSession)
- Lifecycle request parsing
- Identity to session mapping


Implement gt sling command

The unified work dispatch command.

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

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

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


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


File locking for concurrent access

Add file locking for concurrent access safety.

## At-Risk Files
- .gastown/swarms.json (or per-swarm state.json)
- .gastown/refinery.json
- polecats/<name>/state.json
- inbox.jsonl files

## Go File Locking
Use syscall.Flock for advisory locking:
```go
type FileLock struct {
    file *os.File
}

func AcquireLock(path string, timeout time.Duration) (*FileLock, error) {
    f, err := os.OpenFile(path+".lock", os.O_CREATE|os.O_RDWR, 0644)
    if err != nil {
        return nil, err
    }
    // Use syscall.Flock with timeout
}

func (l *FileLock) Release() error
```

## Integration Pattern
```go
func (m *Manager) saveState(ref *Refinery) error {
    lock, err := AcquireLock(m.stateFile(), 5*time.Second)
    if err != nil {
        return fmt.Errorf("could not acquire lock: %w", err)
    }
    defer lock.Release()

    // Read-modify-write cycle
}
```

## New Package
internal/filelock/
├── lock.go     # FileLock, AcquireLock
└── lock_test.go

## Apply To
- internal/refinery/manager.go: loadState/saveState
- internal/cmd/swarm.go: SwarmStore
- internal/mail/mailbox.go: Append, rewrite
- internal/polecat/manager.go: state operations

## Timeout Handling
Default 5 second timeout. Return error if lock not acquired.

## Acceptance Criteria
- [ ] Lock files created (.lock extension)
- [ ] Timeout on lock contention
- [ ] All state files protected
- [ ] Locks released on error paths


Merge execution: merge, test, push

Implement the actual merge execution.

Steps:
1. git checkout <mr.target>
2. git merge <mr.branch> --no-ff -m 'Merge <branch>: <title>'
3. If config.run_tests:
   - Run test_command (from config)
   - If failed: git reset --hard HEAD~1, return Failure(tests_failed)
4. git push origin <mr.target>
5. Return Success(merge_commit=HEAD)

Configuration:
- run_tests: bool (default true)
- test_command: string (default 'go test ./...')

Handle push failures with retry logic.

Reference: docs/merge-queue-design.md#process-merge-steps


mol-polecat-work

Full polecat lifecycle from assignment to decommission.

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

Variables:
- {{issue}} - The source issue ID being worked on


Shutdown request handler

Handle polecat shutdown requests:

When polecat runs 'gt handoff --shutdown':
1. Polecat sends mail to <rig>/witness requesting shutdown
2. Witness receives mail
3. Witness verifies:
   - Git working tree is clean
   - Work is submitted (MR exists or in queue)
   - No uncommitted beads changes
4. If clean:
   - gt session stop <rig>/<polecat>
   - git worktree remove polecats/<name>
   - git branch -d polecat/<name>
5. If not clean:
   - Send nudge back to polecat
   - Track retry count

Depends on fixing gt-dsfi (handoff deadlock).


Epic: Refinery Engineer Autonomy

Make Refinery Engineer fully autonomous:

## Goal
Refinery can run indefinitely, processing all polecat work through merge queue, cycling sessions as needed, without human intervention.

## Key Components
1. Role prompting (CLAUDE.md, templates)
2. Handoff mechanism (pinned beads)
3. Context detection (gt prime)
4. Communication protocol (Witness, Deacon)
5. Future: Merge orchestration plugins

## Success Criteria
- Refinery starts, reads handoff, knows what to do
- Processes merges sequentially with conflict resolution
- Cycles sessions cleanly via Deacon
- Communicates results to Witness
- No work left behind


Refinery agent: merge queue processing loop

The Refinery agent processes the merge queue, merging polecat work to main.

## Interface

```go
type Refinery struct {
    rig    *Rig
    queue  *MergeQueue
    git    *Git
    mail   *Mailbox
    config RefineryConfig
}

type RefineryConfig struct {
    AutoMerge     bool          // Auto-merge passing MRs
    RunTests      bool          // Run tests before merge
    TestCommand   string        // Command to run tests
    RequireReview bool          // Require review before merge (future)
}

func NewRefinery(rig *Rig, ...) *Refinery

// Lifecycle
func (r *Refinery) Start() error
func (r *Refinery) Stop() error
func (r *Refinery) IsRunning() bool

// Processing
func (r *Refinery) ProcessQueue() error
func (r *Refinery) ProcessMR(mr *MergeRequest) error
```

## Processing Loop

1. Check queue for pending MRs
2. For each pending MR:
   a. Fetch polecat branch
   b. Attempt merge to refinery/rig (local main)
   c. Run tests if configured
   d. If pass: push to origin, mark merged
   e. If fail: mark rejected, notify polecat
3. Sleep, repeat

## Merge Strategy

- Fast-forward when possible
- Merge commit when not
- On conflict: reject MR, polecat must rebase

## Test Integration

If tests configured:
```bash
cd refinery/rig
git merge polecat/branch
<test_command>  # e.g., go test ./...
```
Result determines merge/reject.

## Notifications

On merge success:
- Mail to polecat: "Your work merged"
- Update bead if issue tracked

On merge failure:
- Mail to polecat: "Merge failed: <reason>"
- Include conflict details if applicable

## Dependencies

Needs: Rig management, Git wrapper, Mail system, Merge queue


Batch Work System: Integration branch, merge queue, landing

## Overview

This epic tracks batch work coordination in GGT. Key insight: **work is a stream, not discrete swarms**.

There are no "swarm IDs" - the epic IS the grouping, the merge queue IS the coordination. "Swarming an epic" is colloquial for spawning multiple workers on its children.

## Architecture

- **Epics** group related work
- **Issues** are individual tasks
- **Dependencies** encode ordering (multi-wave emerges automatically)
- **Merge queue** coordinates completed work
- **Workers** process issues independently

See Key Decision #11 in docs/architecture.md: "Work is a Stream (No Swarm IDs)"

## What This Epic Covers

1. Integration branch management for batch merges
2. Refinery semantic merge processing
3. Witness landing protocol (cleanup)
4. Report generation (epic-based, not swarm-ID-based)
5. Git safety auditing
6. Work reconciliation

## What Was Removed

- Swarm IDs (sw-1, sw-2, etc.)
- Per-swarm directories (.gastown/swarms/<id>/)
- Swarm manifest/state/events files
- swarm-started/swarm-landed beads

These were redundant - beads already provides hierarchy, status, dependencies, and history.

## References

- Architecture: docs/architecture.md (Key Decision #11, Multi-Wave Work Processing)
- PGT: swarm/manager.py, swarm/landing.py (behavioral reference, but ignore swarm ID patterns)


Phase 1.1: gt rig init creates .beads-ephemeral/

Add ephemeral beads repo creation to rig initialization.

## Implementation

In `gt rig init` (or equivalent setup):
1. Create `<rig>/.beads-ephemeral/` directory
2. Initialize as git repo
3. Create minimal beads config (no sync-branch needed)
4. Add to .gitignore if not already

## Config

```yaml
# .beads-ephemeral/config.yaml
ephemeral: true
# No sync-branch - ephemeral is local only
```

## Verification

```bash
gt rig init gastown
ls gastown/.beads-ephemeral/  # Should exist
```


Bubbletea TUI dashboard

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


Verify architecture.md shows correct harness and rig structure

Review architecture.md diagrams:
- Verify town-level structure shows harness correctly
- Confirm rig-level mayor/rig/ is shown (it appears to be there at line 197)
- Check mermaid diagrams match ASCII diagrams
- Update if any inconsistencies found
- Cross-reference with new harness.md docs


SSHOutpost: Full Gas Town clone on remote VM

## Overview

Implement SSHOutpost for running workers on remote VMs via SSH.

## Model

Remote VM has a full Gas Town clone. SSHOutpost:
- Connects via SSH
- Spawns tmux sessions on remote
- Uses remote git clone for code/beads
- Syncs via git push/pull

## Implementation

```go
type SSHOutpost struct {
    name       string
    host       string
    user       string
    keyPath    string
    townPath   string  // e.g., /home/steve/ai
    maxWorkers int
    conn       *ssh.Client
}

func NewSSHOutpost(config OutpostConfig) (*SSHOutpost, error)

func (o *SSHOutpost) Spawn(issue string, cfg WorkerConfig) (Worker, error) {
    // SSH: create tmux session on remote
    // SSH: start claude in session
    // Return SSHWorker
}

func (o *SSHOutpost) Ping() error {
    // Test SSH connectivity
}
```

## SSHWorker

```go
type SSHWorker struct {
    outpost *SSHOutpost
    id      string
    session string
    issue   string
}

func (w *SSHWorker) Attach() error {
    // SSH + tmux attach (opens terminal)
}

func (w *SSHWorker) Logs() (io.Reader, error) {
    // SSH: tmux capture-pane
}
```

## Prerequisites on Remote VM

1. Gas Town clone at townPath
2. Claude Code installed
3. Git credentials configured
4. SSH key access

## Integration with gt-f9x.7-8

This builds on the Connection interface from gt-f9x.7/8. SSHOutpost uses SSHConnection internally for remote operations.

Depends on: gt-9a2.1 (interfaces), gt-f9x.7 (Connection interface)


mol-crew-session: Startup/shutdown protocols for crew workers

Crew workers (like joe, max) don't have patrol molecules keeping them fresh. When gt gets rebuilt, they have stale binaries that cause hangs and bugs.

## Problem

- Crew binaries get stale when gt is rebuilt elsewhere
- No automatic pull/rebase/rebuild on session start
- No standardized shutdown protocol (sync, push, handoff)

## Solution: mol-crew-session

A molecule template for crew sessions:

### Startup Phase
1. `git pull --rebase` - get latest code
2. `bd sync` - sync beads
3. `go build -o gt ./cmd/gt` - rebuild gt (if in gastown)
4. `gt prime` - load context

### Work Phase
- Open-ended human interaction
- No molecule steps - just work until done

### Shutdown Phase
1. `git status` - check for uncommitted changes
2. `bd sync` - sync beads
3. `git push` - push code
4. Handoff if incomplete work

## Implementation

1. Define mol-crew-session in builtin_molecules.go
2. Update crew CLAUDE.md to reference the protocol
3. Optionally: gt prime auto-runs startup steps

## Dependencies

- Should implement after deacon/witness/polecat patrols are stable
- Consider: gt-3x0z.10 (Witness patrol molecules)

## Related

- gt-3x0z.9: Deacon wisp patrol (done)
- fix-gt script: Current workaround for binary freshness


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.


gt mq list: doesn't show submitted MRs

After submitting MRs with gt mq submit, gt mq list gastown shows empty queue.

## Reproduction
1. gt mq submit --issue gt-h5n.5 --branch polecat/Scabrous
2. gt mq list gastown → (empty)
3. bd list --type=merge-request → shows the MR

## Expected
gt mq list should show submitted MRs

## MR example
gt-ts4u has rig: gastown in description, type=merge-request, status=open


Consider splitting large files (800+ lines)

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

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


gt mq integration create: create integration branch for epic

Implement 'gt mq integration create <epic>' command.

Actions:
1. Verify epic exists
2. Create branch: integration/<epic-id> from main
3. Push to origin
4. Store integration branch info in epic metadata

Usage:
  gt mq integration create gt-auth-epic
  # Creates integration/gt-auth-epic from main

Future MRs for this epic's children will auto-target this branch.

Reference: docs/merge-queue-design.md#integration-branches


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


Simplify Go daemon to Deacon-watcher

Refactor internal/daemon to only: (1) check deacon/heartbeat.json every 60s, (2) poke gt-deacon if stale, (3) restart Deacon and mail for help if very stale. Remove all lifecycle processing and agent poking.


gt orphans: Find lost polecat work

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

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

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

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

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


Add gt hook command (wrapper for bd hook)

Add a thin wrapper command `gt hook` that calls `bd hook` to inspect what's pinned to an agent's hook.

## Usage

```bash
gt hook                    # Show what's on current agent's hook
gt hook --agent deacon     # Show Deacon's hook
gt hook --agent gastown/furiosa  # Show polecat's hook
```

## Implementation

Thin wrapper in gt that:
1. Determines current agent identity
2. Calls `bd hook [--agent <name>]`
3. Formats output for gt context

## Why gt wrapper?

- Consistent with gt ecosystem (gt mail, gt status, etc.)
- Can add gt-specific context (session status, etc.)
- Easier discovery for gt users

## Related

- bd hook command (implemented by Dave)
- Chemistry UX design: gastown/mayor/rig/docs/chemistry-design-changes.md


Swarm learning: Refinery merge queue automation

Manually merging 15 polecat branches was painful and error-prone. Refinery should automate: detect completed work, run tests, merge to main, handle conflicts. This is core Refinery value prop.


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.


Deacon tmux status bar: heartbeat timing and patrol state

## Problem

The deacon shows patrol output but lacks real-time observability:
- No indication of when last heartbeat occurred
- No indication of when next heartbeat is scheduled
- No visibility into current patrol step

## Desired Behavior

The tmux status bar for gt-deacon should show:

```
⛪ Deacon | ❤ 2m ago | ⏰ 3m | 📍 health-scan (3/7)
```

Components:
- **Role icon**: ⛪ (deacon identity)
- **Last heartbeat**: ❤ 2m ago (time since last heartbeat file update)
- **Next heartbeat**: ⏰ 3m (time until daemon would poke)
- **Current step**: 📍 health-scan (3/7) (current patrol atom, step N of M)

## Implementation

1. **Read heartbeat.json** for last update time
2. **Calculate next poke** based on daemon interval (default 5m)
3. **Read current wisp** from .beads-wisp/ to get patrol progress
4. **Update tmux status** periodically or on state change

Options:
- tmux status-right with shell script
- gt deacon status --tmux for formatted output
- Hook into patrol step completion

## Related

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


implement

Implement the solution for gt-test123. 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.

Depends: load-context


Refinery tmux status: show merge queue length

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

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


Consolidate configuration architecture: three-tier model

Rationalize Gas Town's scattered configuration into a clean three-tier model:

## Current Problems
- Config split across mayor/, .gastown/, and rig/config.json
- Runtime state mixed with configuration
- Hidden directories (.gastown/) are missed by agents
- Category confusion: identity vs config vs runtime state

## Proposed Architecture

### Tier 1: Town Config (mayor/)
```
mayor/
├── town.json      # Town identity (unchanged)
├── rigs.json      # Rig registry (unchanged)
└── config.json    # NEW: Town-level configuration
    # theme defaults, daemon settings, etc.
```

### Tier 2: Town Runtime (.runtime/)
```
~/gt/.runtime/                    # NEW: Gitignored
├── daemon.json                   # {pid, started_at, heartbeat}
├── deacon.json                   # {cycle, last_action}
└── agent-requests.json           # Lifecycle requests
```

### Tier 3: Rig Config (settings/)
```
<rig>/
├── config.json                   # Rig identity only (type, git_url, beads.prefix)
├── settings/                     # NEW: Visible, git-tracked
│   ├── config.json               # theme, merge_queue, max_workers
│   ├── namepool.json             # pool settings (style, max)
│   └── roles/                    # Per-role overrides (optional)
└── .runtime/                     # NEW: Gitignored
    ├── witness.json              # {state, started_at, stats}
    ├── refinery.json             # {state, started_at, stats}
    └── namepool-state.json       # {in_use, overflow_next}
```

## Key Principles
1. **Visible > Hidden** for config agents need to find
2. **Git-tracked** for identity and config; **gitignored** for runtime
3. **Separation of concerns**: identity, config, runtime are distinct
4. **Locality**: town config at town root, rig config at rig root

## Migration
- Move .gastown/ contents to appropriate new locations
- Update all code that reads/writes these files
- Update .gitignore patterns
- Update documentation (architecture.md, CLAUDE.md)


gt spawn should auto-start refinery/witness if not running

When spawning a polecat, the infrastructure (refinery, witness) should already be running.

## Current Behavior
spawn.go only:1. Assigns issue to polecat2. Sends work mail3. Starts polecat session

The refinery and witness must be started separately.

## Expected Behavior (per user feedback)
When spawning a polecat, if the rig's refinery or witness is not running, auto-start them.

## Options

### Option A: spawn auto-starts infrastructure
Check if refinery/witness running before spawn, start if not.

### Option B: gt swarm start <rig> command
Explicit command that:
1. Starts refinery
2. Starts witness
3. Optionally spawns polecats on bd ready issues

### Option C: gt rig start <rig>
Similar to Option B but as rig lifecycle command.

## Related
- gt-n7z7: refinery --foreground race condition bug
- gt-u1j.18: witness CLI commands


Town Doctor molecule for harness health checks

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

## Concept

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

## Why a Molecule?

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

## Proposed Checks (molecule steps)

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

## Integration

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

## Related

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


Merge: gt-5wb7

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


mol-christmas-launch: 3-day execution plan

---

## Wisp Integration Wave Plan (added 2025-12-21)

Dependency-ordered execution for gt-3x0z (Wisp Molecules) + gt-rana (Patrol System):

### Wave 1 (parallel - no blockers)
- gt-3x0z.1: gt rig init creates .beads-ephemeral/
- gt-3x0z.2: Configure bd for ephemeral molecule bonding
- gt-3x0z.3: gt doctor checks for ephemeral health
- gt-rana.1: Attachment field on pinned beads
- gt-rana.3: mol-deacon-patrol definition

### Wave 2 (after Wave 1)
- gt-3x0z.4: gt spawn --molecule bonds ephemeral (GATE 1)
- gt-rana.2: Daemon attachment detection

### Wave 3-5 (sequential)
- gt-3x0z.5, gt-3x0z.6 → gt-3x0z.7 → gt-3x0z.8 (GATE 2: squash)

### Wave 6+ (patrol integration)
- gt-rana.4: Basic patrol runner (needs gt-rana.3 + gt-3x0z.8)
- gt-3x0z.9: mol-deacon-patrol uses wisp (needs gt-rana.3 + gt-3x0z.8)
- Then: gt-rana.5-7, gt-3x0z.10-12

### Key Gates
1. gt-3x0z.4 - spawn/bond unlocks Phase 2
2. gt-3x0z.8 - squash unlocks patrol integration
3. gt-rana.4 - patrol runner unlocks Phase 2+ patrol


Add gt deacon start/stop/status commands

Add CLI commands: gt deacon start (spawn gt-deacon session), gt deacon stop (kill session), gt deacon status (show health state). Similar to gt mayor commands.


Merge: gt-3x1

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


Outpost assignment policy: Smart work routing

## Overview

Policy engine for deciding which outpost gets which work.

## Policy Configuration

```yaml
policy:
  # Default order of preference
  default_preference: [local, gce-burst, cloudrun-burst]

  # Rules applied in order
  rules:
    # Background work → Cloud Run (cheap)
    - condition: "priority >= P3"
      prefer: cloudrun-burst

    # Long tasks → VM (persistent)
    - condition: "estimated_duration > 30m"
      prefer: gce-burst

    # Specific epic → specific outpost
    - condition: "epic == gt-abc"
      prefer: local
```

## Implementation

```go
type AssignmentPolicy struct {
    DefaultPreference []string
    Rules             []PolicyRule
}

type PolicyRule struct {
    Condition string   // Simple expression
    Prefer    string   // Outpost name
    Require   string   // Must use this outpost
}

func (p *AssignmentPolicy) SelectOutpost(
    issue Issue,
    outposts map[string]Outpost,
) Outpost {
    // Check rules in order
    for _, rule := range p.Rules {
        if rule.Matches(issue) {
            if op, ok := outposts[rule.Prefer]; ok {
                if op.ActiveWorkers() < op.MaxWorkers() {
                    return op
                }
            }
        }
    }

    // Fall back to default preference
    for _, name := range p.DefaultPreference {
        if op, ok := outposts[name]; ok {
            if op.ActiveWorkers() < op.MaxWorkers() {
                return op
            }
        }
    }

    return nil  // All outposts at capacity
}
```

## Condition Language

Simple expressions, not a full DSL:

```
priority >= P3
priority == P0
estimated_duration > 30m
epic == gt-abc
type == bug
label contains "urgent"
```

## Files

- `internal/outpost/policy.go`
- `internal/outpost/condition.go`

Depends on: gt-9a2.3 (config)


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.


Session cycling UX: smooth transitions via TUI wrapper

## Problem

Current CLI agent session cycling is painful:
- Shell → CC starts → priming → context loads → ready → work → exit/crash → repeat
- Each cycle is 30-60 seconds of cold boot
- No continuity between shell and agent's inner state
- Raw "session not running, starting..." loop is the baseline

## GGT Advantages (already have)

- Beads: Work state survives session death completely
- Mail: Handoff notes from past-self to future-self
- Prime commands: Structured context reload

## Gap: Transition Mechanics

Ideas to explore when actively using CLI:

1. **In-band cycling** - `/restart` or `/cycle` command, agent handles own restart without dropping to shell

2. **Hot standby** - TUI maintains pre-warmed session in background, switch to already-primed agent

3. **Persistent wrapper** - Bubbletea TUI stays running across session cycles, CC sessions come/go inside it

4. **Session pooling** - Keep 2-3 primed sessions ready, never wait for cold start

## Deferred

Deliberately P4 until we're actively using the simpler CLI and feel the pain firsthand.


Swarms of One: Lightweight single-worker task dispatch

Design and implement a lightweight pattern for firing off single workers to handle tasks without full swarm overhead.

## Context

Currently we have:
- town spawn: Creates a polecat in a rig with issue assignment
- Swarms (sw-*): Full lifecycle tracking with manifest, state, events, reports
- Ephemeral rigs (rig-*): Temporary worker groups for swarms

What's missing: A simple way to say 'fire off a worker to do X' without swarm ceremony.

## Design Questions

1. Should this be a new command like 'gt fire' or an option on existing commands?
2. Should single tasks still get swarm IDs (sw-N) for consistency/queryability?
3. Should it default to creating new workers or support --reuse for idle polecats?
4. How does this relate to crew workers (gt-cik)?

## Possible Interface

gt fire --rig gastown --issue gt-xyz [--prompt '...']
gt fire gastown/QuickTask --issue gt-xyz

## Related

- gt-cik: Overseer Crew (user-managed persistent workspaces)
- gt-kmn: Swarm System epic


Fix TestHasPolecat test failure


Plugin: work-oracle (pre-dispatch analysis)

Plugin for pre-dispatch task analysis and decomposition.

## Purpose

Before dispatching workers for an epic, ask work-oracle to:
- Validate task breakdown
- Identify parallelization opportunities
- Predict conflicts between tasks
- Suggest worker count

## Hook Point

Mayor consults work-oracle before spawning workers.

## Interface

Input (via mail):
- Epic ID with proposed child issues
- Rig context (current state of codebase)

Output (via mail + bead):
- Recommended task groupings
- Dependency suggestions
- Risk assessment (which files might conflict)
- Optimal worker count

## Structure

```
<rig>/plugins/work-oracle/
├── CLAUDE.md       # Analysis prompts
├── mail/inbox.jsonl
└── state.json
```

Uses existing plugin-as-agent architecture.

## Note

Was "swarm-oracle" - renamed because there are no swarm IDs. This plugin helps plan batch work, not manage swarm entities.


Post-work discovery: AI analysis finds follow-on issues

AI analyzes completed work to discover: bugs, punted work, follow-on tasks.

**From VC**: Supervisor.AnalyzeResult() with iterative refinement. ~300 lines.

**Gas Town implementation**: Post-work hook in molecule:
```yaml
post_work:
  discover:
    - bugs
    - punted_items
    - follow_on_work
  file_as: beads
```

Polecat output gets analyzed by AI, discovered work becomes beads issues.

**Value**: Nothing gets forgotten. VC found ~25% more issues with refinement.

**Key**: Use semantic deduplication (gt-xxx) to avoid pollution.


CLI: gt refinery commands (start, stop, status, queue)

CLI commands for managing the Refinery agent.

## Commands

```bash
gt refinery start <rig>      # Start refinery for a rig
gt refinery stop <rig>       # Stop refinery
gt refinery status <rig>     # Show refinery status
gt refinery queue <rig>      # Show merge queue
```

## gt refinery start

Starts the Refinery daemon for the specified rig.

Options:
- --foreground: Run in foreground (default: background)
- --auto-merge: Enable auto-merge (default: from config)

## gt refinery stop

Stops a running Refinery. Gracefully finishes current MR if processing.

## gt refinery status

Shows:
- Running state (running/stopped)
- Current MR being processed (if any)
- Queue length
- Last merge time
- Recent activity

## gt refinery queue

Shows the merge queue:
```
Merge queue for 'wyvern':
  1. [pending] Toast/polecat-auth-fix (15m ago)
  2. [pending] Capable/polecat-new-feature (5m ago)

1 merged today, 0 rejected
```

## Implementation

Uses gt-ov2 (Refinery agent) for daemon functionality.


MQ metrics: pending count, processing time, success rate

Implement merge queue metrics collection.

Metrics to track:
- mq_pending_count: MRs waiting
- mq_processing_time: Time from submit to merge (histogram)
- mq_success_rate: Merges vs rejections
- mq_conflict_rate: How often conflicts occur
- mq_test_failure_rate: Test failures

Storage options:
- Simple: JSON file with rolling stats
- Advanced: Prometheus-compatible metrics endpoint

Display via:
- gt mq stats: summary statistics
- Dashboard widget (separate task)

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


Phase 3.2: mol-polecat-work squash step

Add summary+squash as final steps in mol-polecat-work.

## Current Steps

1. read-assignment
2. understand-task
3. implement-solution
4. verify-tests
5. commit-work
6. signal-done

## Updated Steps

1. read-assignment
2. understand-task
3. implement-solution
4. verify-tests
5. commit-work
6. **generate-summary** ← NEW
7. **squash-molecule** ← NEW
8. signal-done

## Step Definitions

### generate-summary
Agent writes a concise summary following the template.
Save to a local variable or temp file.

### squash-molecule
Run: bd squash $MOLECULE_ROOT --summary "$SUMMARY"
This creates digest in main beads, cleans ephemeral.

## Update Location

This requires updating the mol-polecat-work definition in beads molecule catalog.


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.


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)


Witness session startup (gt witness start)

Implement gt witness start <rig>

Should:
1. Verify rig exists and has witness/ directory
2. Check for existing witness session (don't double-start)
3. Create tmux session: gt-<rig>-witness
4. Start Claude Code with --dangerously-skip-permissions
5. Send gt prime to load context
6. Send startup prompt

Similar pattern to refinery startup in internal/refinery/manager.go


Add molecule phase lifecycle diagram to architecture.md

Create a clear lifecycle diagram showing molecule phases:

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

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


Witness updates: Remove issue filing proxy

Update Witness prompting to remove issue filing proxy, since polecats now have direct beads access.

## Remove from Witness Prompting

The following is NO LONGER Witness responsibility:
- Processing polecat 'file issue' mail requests
- Creating issues on behalf of polecats
- Forwarding issue creation requests

## Add: Legacy Request Handling

If Witness receives an old-style 'please file issue' request:

1. Respond with update:
   town inject <polecat> "UPDATE: You have direct beads access now. Use bd create to file issues yourself."

2. Do not file the issue - let the polecat learn the new workflow.

## Keep in Witness Prompting

- Monitoring polecat progress
- Nudge protocol
- Pre-kill verification
- Session lifecycle management


Batch work landing report generation

Generate reports on batch work completion.

## Trigger

When all children of an epic are closed, generate a completion report.

## Report Contents

- Epic metadata (ID, title, created by, duration)
- Task summary (completed counts, timing)
- Per-task details (issue, assignee, time taken)
- Git stats (commits merged, lines changed)
- Cleanup stats (branches deleted)

## Output Locations

1. Mail to Mayor - summary report
2. Optional: save to file with --save flag

## Command

```bash
gt report --epic <epic-id> [--save report.md]
```

## Format

Markdown with sections:
- Summary
- Tasks
- Workers
- Timeline

## Note

This replaces the swarm-based reporting (gt-662). Reports are generated from epic/issue data, not from separate swarm state files.

## Reference

PGT: swarm/report.py (for format ideas, ignore swarm ID patterns)


load-context

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

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


Work assignment mail not received by polecat

When gt spawn sends a work assignment:

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

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

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

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

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


Test Task 2: Add comment to version.go


Review and audit all GGT beads

Thorough review of all filed beads in gastown GGT repo. Check for: consistency, completeness, correct dependencies, accurate descriptions, proper prioritization. Ensure beads are self-contained and dont rely on external docs.


Work on ga-yp3: Polecat inbox system for reliable work as...

Work on ga-yp3: Polecat inbox system for reliable work assignment. This is P1 priority. See bd show ga-yp3 for full design spec.


Mayor session cycling prompting

Add session cycling section to Mayor CLAUDE.md template.

## When to Cycle

Cycle proactively when:
- Running for several hours
- Context feels crowded (losing track of earlier state)
- Major phase completed
- About to start complex new work

## Composing Handoff Notes

1. Gather information:
   town status    # Overall health
   town rigs      # Each rig state
   town inbox     # Pending messages
   bd ready       # Work items

2. Compose note with this structure:

[HANDOFF_TYPE]: mayor_cycle
[TIMESTAMP]: <current time>
[SESSION_DURATION]: <how long running>

## Active Swarms
<per-rig swarm status>

## Rig Status
<table of rig health>

## Pending Escalations
<issues needing your decision>

## In-Flight Decisions
<decisions being made>

## Recent Actions
<last 5-10 things you did>

## Delegated Work
<work sent to refineries>

## User Requests
<pending user asks>

## Next Steps
<what next session should do>

## Warnings/Notes
<critical info for next session>

3. Send handoff:
   town mail send mayor/ -s "Session Handoff" -m "<note>"

4. End session - next instance picks up from handoff.


Refinery-Witness communication protocol

Define mail protocol between Refinery and Witness:

FROM Witness → Refinery:
- 'Polecat ready': polecat X completed work, ready for merge
- 'Rework complete': polecat Y finished requested rework

FROM Refinery → Witness:
- 'Merge success': polecat X merged, can be cleaned up
- 'Merge failed': polecat X needs rework on <reason>
- 'Rework request': please have a polecat rebase X on current main

Implement as structured mail with parseable format.


Update templates for Propulsion Principle

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

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

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

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


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

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


plugin-run

Execute plugins from ~/gt/plugins/. Check gates, run eligible plugins.


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


CLI: polecat commands (add, remove, list, wake, sleep)

Polecat management CLI commands.

## Commands

### gt polecat list
List polecats in a rig.
```
gt polecat list <rig> [--json]
gt polecat list --all [--json]
```
Output:
- Name
- State (idle/active/working/done/stuck)
- Current issue (if any)
- Session status (running/stopped)

### gt polecat add
Add a new polecat to a rig.
```
gt polecat add <rig> <name>
```
- Creates polecat directory
- Clones rig repo
- Creates work branch
- Initializes state

### gt polecat remove
Remove a polecat from a rig.
```
gt polecat remove <rig>/<polecat> [--force]
```
- Fails if session running
- Warns if uncommitted changes
- --force bypasses checks

### gt polecat wake
Mark polecat as active (ready for work).
```
gt polecat wake <rig>/<polecat>
```
Transitions: idle → active

### gt polecat sleep
Mark polecat as idle (not available).
```
gt polecat sleep <rig>/<polecat>
```
Transitions: active → idle
Fails if session running (stop first).

## Address Format

`<rig>/<polecat>` for operations on specific polecat.
`<rig>` for list command.

## Implementation

```go
var polecatCmd = &cobra.Command{Use: "polecat"}
polecatCmd.AddCommand(listCmd, addCmd, removeCmd, wakeCmd, sleepCmd)
```


Heartbeat convention: simple liveness signal for agents

Lightweight liveness signal extracted from Deacon epic (gt-5af).

**Implementation**: Each agent writes a timestamp file on activity:
```bash
echo '{"ts":"'$(date -Iseconds)'"}' > ~/gt/<role>/heartbeat.json
```

**Integration points**:
- SessionStart hook writes heartbeat
- Periodic activity (mail check, work completion) refreshes it
- `gt status` shows staleness (e.g., 'mayor: 5m ago')

**Weight**: ~5 lines per agent
**Value**: Quick debugging - see which agents are active at a glance

No monitoring daemon needed - human checks `gt status` when curious.


Test2

Testing gt mail


Molecule Phase Terminology Documentation

Document the three-phase molecule lifecycle with consistent terminology:

## The Phases (States of Matter)

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

## Documentation Gaps Identified

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

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

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

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


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


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


CloudRun protocol types: WorkRequest, WorkEvent, WorkResult

## Overview

HTTP protocol types for Cloud Run work dispatch. **Types only** - server and client are separate tasks.

## Request Type

```go
type WorkRequest struct {
    IssueID string          `json:"issue_id"`
    Rig     RigConfig       `json:"rig"`
    Beads   BeadsConfig     `json:"beads"`
    Branch  string          `json:"worker_branch"`
    Context map[string]any  `json:"context,omitempty"`
}

type RigConfig struct {
    URL    string `json:"url"`
    Branch string `json:"branch"`
}

type BeadsConfig struct {
    URL    string `json:"url"`
    Branch string `json:"branch"`
}
```

## Response Types (streaming NDJSON)

```go
type WorkEvent struct {
    Type     string `json:"type"`  // status, log, progress, result, error
    Status   string `json:"status,omitempty"`
    Line     string `json:"line,omitempty"`
    Percent  int    `json:"percent,omitempty"`
    Branch   string `json:"branch,omitempty"`
    PRURL    string `json:"pr_url,omitempty"`
    Code     string `json:"code,omitempty"`
    Message  string `json:"message,omitempty"`
}

type WorkResult struct {
    Status  string `json:"status"`  // done, failed
    Branch  string `json:"branch"`
    PRURL   string `json:"pr_url,omitempty"`
    Error   string `json:"error,omitempty"`
}
```

## Files

- `internal/cloudrun/protocol.go` - All types above

## Notes

This is just types. Server (gt-9a2.7b) and client (gt-9a2.7c) are separate tasks.
Small, focused task - can complete quickly.


request-shutdown

Send shutdown request to Witness.
Wait for termination.

The polecat is now ready to be cleaned up.
Do not exit directly - wait for Witness to kill the session.

Depends: generate-summary


Pinned bead naming convention for all roles

Establish consistent naming convention for pinned beads across all roles.

## Problem

Every role needs a pinned bead for molecule attachment, handoff state, and identity.
We need a consistent naming convention so gt tools can find the pinned bead for any role.

## Proposed Convention

  {role}.pinned                    - Singleton roles (deacon, mayor)
  {rig}-{role}.pinned              - Per-rig roles (witness, refinery)
  {rig}-{name}.pinned              - Named agents (polecats, crew)

Examples:
- deacon.pinned
- mayor.pinned
- gastown-witness.pinned
- gastown-refinery.pinned
- gastown-furiosa.pinned (polecat)
- gastown-max.pinned (crew)

## Storage Location

| Role | Pinned Bead Location |
|------|---------------------|
| Mayor | ~/gt/.beads/ (town level) |
| Deacon | ~/gt/.beads/ (town level) |
| Witness | {rig}/.beads/ (rig level) |
| Refinery | {rig}/.beads/ (rig level) |
| Polecat | {rig}/polecats/{name}/.beads/ |
| Crew | {rig}/crew/{name}/.beads/ |

## Why This Matters

1. Name recycling: Polecats reuse names so their pinned beads persist
2. Molecule attachment: gt mol bond needs to find the pinned bead
3. gt prime: Can show you are working on X from pinned bead
4. Crash recovery: Resume from pinned beads attached molecule

## Tasks

- Document naming convention in architecture.md
- Update gt prime to find pinned bead by convention
- Update gt mol bond to use conventional name
- Create pinned beads on role startup if missing
- Add gt pinned command to show/manage pinned beads

## Related

- gt-rana.1: Attachment field on pinned beads (closed)
- gt-id36.2: Deacon marching orders (pinned bead)


bd ready --type: missing type filter for MQ integration

bd ready lacks --type flag that engineer.go expects.

## Code (internal/refinery/engineer.go)
readyMRs, err := e.beads.ReadyWithType("merge-request")

## Actual bd ready
No --type flag - only supports assignee, label, priority filters.

## Impact
Refinery can't find merge-requests in queue, so MQ doesn't process anything.

## Fix Options
1. Add --type flag to bd ready
2. Use bd list --type=merge-request --status=open instead
3. Both (ready filters for unblocked, list for all)

This is blocking the entire MQ pipeline.


Swarm state persistence: manifest + state + events

Upgrade swarm persistence to match PGT pattern.

## Current State
Single .gastown/swarms.json with all swarms.

## Target State (per-swarm)
```
.gastown/swarms/
└── <swarm-id>/
    ├── manifest.json  # Immutable config
    ├── state.json     # Mutable progress
    ├── events.jsonl   # Audit log
    └── report.md      # Generated report
```

## File Schemas

### manifest.json (immutable after creation)
```json
{
  "id": "sw-1",
  "title": "Epic description",
  "epic_id": "gt-abc",
  "rig": "gastown",
  "base_commit": "abc123",
  "integration_branch": "swarm/sw-1",
  "target_branch": "main",
  "workers": ["Toast", "Nux"],
  "tasks": [{"id": "gt-xyz", "title": "..."}],
  "created_at": "2024-01-01T00:00:00Z"
}
```

### state.json (mutable)
```json
{
  "state": "active",
  "task_states": {
    "gt-xyz": {"state": "merged", "assignee": "Toast"}
  },
  "updated_at": "2024-01-01T01:00:00Z",
  "error": null
}
```

### events.jsonl (append-only audit)
```jsonl
{"event": "created", "ts": "...", "data": {...}}
{"event": "task_assigned", "ts": "...", "data": {...}}
{"event": "task_merged", "ts": "...", "data": {...}}
```

## Benefits
- Audit trail via events.jsonl
- Manifest immutability prevents corruption
- Cleaner separation of concerns
- Per-swarm isolation

## Migration
Keep backward compat with swarms.json during transition.

## Files to Modify
- internal/swarm/manager.go: Refactor persistence
- internal/cmd/swarm.go: SwarmStore → directory-based

## Acceptance Criteria
- [ ] Per-swarm directory structure
- [ ] Events logged to JSONL
- [ ] Manifest immutable after creation
- [ ] List command aggregates from directories


Merge: gt-qna4

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


Interrupt vs Queue mail semantics

Add priority/delivery semantics to mail messages.

## Semantics

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

## Implementation

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

## Agent Side

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


Merge: gt-y5o

branch: polecat/Doof
target: main
source_issue: gt-y5o
rig: gastown


Merge: gt-unrd

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


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


Create .runtime/ for town-level runtime state

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


MR: gt-svi.1 (polecat/Furiosa)

branch: polecat/Furiosa
target: main
source_issue: gt-svi.1


Add godoc comments to exported functions

Several exported functions lack godoc comments. While not critical, adding documentation would improve code maintainability. Focus on:

- Public API functions in each package
- Exported types and their methods
- Functions that have non-obvious behavior

Can be addressed incrementally as code is touched.


Merge: gt-3x0z.2

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


Mail orchestrator daemon

Background mail orchestrator daemon.

## Command
```
gt mail orchestrate [--interval N] [--once] [--verbose]
```

## Purpose
Background process that:
1. Monitors outbox for pending mail
2. Delivers to recipient inboxes
3. Handles offline recipients (retry later)
4. Cleans delivered messages from outbox

## Why Needed?
Current mail is synchronous. If recipient is offline or mailbox locked, send fails.
Orchestrator enables async delivery with retry.

## Implementation
```go
func (o *Orchestrator) Run(interval time.Duration) error {
    ticker := time.NewTicker(interval)
    for range ticker.C {
        o.processOutbox()
    }
}

func (o *Orchestrator) processOutbox() {
    // List outbox/*.json
    // For each, attempt delivery
    // On success, delete from outbox
    // On failure, increment retry count
}
```

## Outbox Structure
```
<town>/mayor/mail/outbox/
├── msg-abc123.json
└── msg-def456.json
```

## Lower Priority
Current synchronous delivery works. Orchestrator is optimization.

## Acceptance Criteria
- [ ] Background daemon mode
- [ ] Retry failed deliveries
- [ ] --once for single pass
- [ ] Configurable interval


Refinery semantic merge processing loop

Implement the Refinery semantic merge loop for processing polecat work.

## Overview

The Refinery is a fully empowered Claude Code agent that:
1. Fetches polecat branches
2. Merges to integration branch
3. Resolves conflicts semantically (re-implements if needed)
4. Runs tests
5. Escalates only when truly stuck

## Processing Loop

1. Check queue for completed tasks (polecat done, not yet merged)
2. For each task:
   - Fetch polecat branch
   - Attempt merge to integration/<swarm-id>
   - On conflict: semantic resolution (understand intent, re-implement)
   - Run tests if configured
   - On success: mark merged, file bead, notify witness
   - On failure: notify polecat (test fail) or escalate (stuck)
3. When all tasks merged: land integration to main

## Semantic Merge

When git merge fails, Refinery:
1. Reads polecat changes and beads issue
2. Understands intent
3. Re-implements on current integration branch
4. Only escalates if truly blocked

## Daemon Poking

Refinery is poked by:
- Daemon heartbeat (periodic)
- Witness notification (polecat done)
- Mayor request (check queue)

## Dependencies

Needs: gt-u1j.6 (mail), gt-u1j.3 (git), gt-u1j.14 (merge queue)

## Reference

See PGT ephemeral.py for branch operations.


Create rig settings/ directory for rig configuration

Replace .gastown/ with visible settings/ at rig level:
- Create <rig>/settings/ directory
- Move .gastown/config.json → settings/config.json (theme, merge_queue, max_workers)
- Create settings/namepool.json for pool settings (style, max - not state)
- Create settings/roles/ for per-role overrides (optional)
- Update RigConfig type to reference settings/
- Update loader to read from settings/


Default polecat names: Mad Max theme instead of AdjectiveNoun

Current default naming for new polecats uses AdjectiveNoun convention.
Since rigs already provide namespacing, we can use more thematic names.

Suggestion: Use Mad Max / Fury Road character and vehicle names as defaults.
Examples: Furiosa, Nux, Slit, Morsov, Toast, Rictus, Warboy, etc.

Could also include:
- War Rig parts: Guzzler, Tanker, Pursuit
- Citadel roles: Imperator, Blackthumb, Organic
- Wasteland terms: Chrome, Witness, Shiny

Implementation:
- Add name generator in internal/polecat/ or similar
- Use when --create flag is used without explicit name
- Cycle through pool to avoid duplicates within a rig


gt mq integration land: merge integration branch to main

Implement 'gt mq integration land <epic>' command.

Actions:
1. Verify all MRs targeting integration/<epic> are merged
2. Verify integration branch exists
3. Merge integration/<epic> to main (--no-ff)
4. Run tests on main
5. Push to origin
6. Delete integration branch
7. Update epic status

Options:
- --force: land even if some MRs still open
- --skip-tests: skip test run
- --dry-run: preview only

This creates a single merge commit for the entire epic's work.

Reference: docs/merge-queue-design.md#integration-branches


Polecat name pooling: Bounded reusable names

Polecats reuse names from a bounded pool (50) with overflow to sequence numbers.

## Naming Scheme
- Pool: polecat-01 through polecat-50 (prefer low numbers)
- Overflow: <rigname>-<sequenceNumber> (e.g., beads-51, gastown-52)

## Design
- Witness tracks which pool names are in use
- On spawn: pick first available from pool
- If pool exhausted: use rigname-N format
- On completion: pool name returns, sequence numbers don't

## Why?
- User experience: tmux sessions survive polecat restarts
- Users stay attached, see new polecat start (like mayor respawn loop)
- Bounded resource usage for common case
- Scales beyond 50 when needed

## Implementation
- Witness maintains name allocation in beads or local state
- Tmux session runs respawn loop (like mayor)
- Name released on graceful exit or when witness detects dead session


Adaptive backoff for daemon heartbeat

Track agent responsiveness and adjust heartbeat frequency.

## Per-Agent State

```go
type AgentBackoff struct {
    BaseInterval    time.Duration  // 60s default
    CurrentInterval time.Duration  // grows when busy
    MaxInterval     time.Duration  // 10min cap
    ConsecutiveMiss int            // pokes with no response
}
```

## Strategy Options

- **Fixed**: Always 60s (current, simple)
- **Geometric**: 60s → 90s → 135s → 202s (factor 1.5)
- **Exponential**: 60s → 120s → 240s (factor 2, aggressive)

## Recovery

When agent responds (runs a command):
- Reset ConsecutiveMiss to 0
- Return to BaseInterval immediately

## Benefits

- Reduces noise for busy agents
- Saves resources during quiet periods
- Still catches stuck agents (max interval cap)


Beads CLI wrapper: shell out to bd

Wrapper for bd (beads CLI) commands.

## Interface

```go
type Beads struct {
    workDir string
}

func NewBeads(workDir string) *Beads

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

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

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

## Data Types

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

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

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

## Implementation

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

## Error Handling

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


Step recovery: timeout and release

Implement recovery mechanism for stuck molecule steps.

## Problem
When a worker dies mid-step, the step stays in_progress forever.
Need timeout/release mechanism for nondeterministic idempotence.

## Solution
1. Track step start time (claimed_at timestamp)
2. Timeout: After 30 min in_progress, step returns to pending
3. Manual release: bd release <step-id>

## Implementation Options

### Option A: Beads-level timeout
- Add claimed_at field to issues
- bd ready excludes items in_progress < 30 min
- bd ready includes items in_progress > 30 min (auto-recovery)

### Option B: Daemon-level timeout
- Daemon watches in_progress items
- Moves back to pending after timeout

### Option C: Manual only (MVP)
- bd release <id> manually moves in_progress → pending
- Document recovery procedure
- Witness can automate for polecats

## Recommendation
Start with Option C (manual) for Christmas. Add Option A later.

## Acceptance
- [ ] bd release command works
- [ ] Stuck steps can be recovered
- [ ] Documented recovery procedure


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

## Problem

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

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

## Current State

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

## Target State

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

## Benefits

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

## Implementation

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


MVP Cutover: GGT replaces PGT for batch work

When this is closed, stop using town and start using gt.

## Acceptance Criteria

1. gt spawn assigns issue to polecat and starts session
2. gt spawn --epic spawns workers for all epic children
3. gt session manages tmux lifecycle
4. gt send / gt inbox work for mail
5. Refinery processes merge queue with semantic merges
6. Integration branches created and landed correctly
7. gt stop --all halts all sessions
8. One successful test batch completed end-to-end

## What Must Work

- Spawn polecat with issue assignment
- Spawn workers for epic children
- Session start/stop/attach
- Mail send/inbox/read
- Refinery merge loop (semantic)
- Integration branch → main landing
- Witness cleanup protocol
- Emergency stop

## What Can Be Deferred

- Doctor checks (use PGT)
- TUI dashboard
- Plugin system
- Federation
- Ephemeral rigs
- Detailed landing reports

## Test Plan

1. Create epic with 2 tasks, spawn 2 workers
2. Verify polecats get assigned and sessions start
3. Simulate task completion
4. Verify Refinery merges to integration
5. Verify landing to main
6. Verify cleanup

## Validation

Run one real batch implementing GGT issues using GGT.

## Note

No "swarm IDs" - just spawn workers for epic, let merge queue coordinate.


Merge fix/spawn-beads-path branch to main

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

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

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


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.


Design: Failure modes and recovery

Document failure modes and recovery strategies for Gas Town operations.

## Critical Failure Modes

### 1. Agent Crash Mid-Operation

**Scenario**: Polecat crashes while committing, Witness crashes while verifying

**Detection**:
- Session suddenly gone (tmux check fails)
- State shows 'working' but no session
- Heartbeat stops (for Witness)

**Recovery**:
- Doctor detects via ZombieSessionCheck
- Capture any recoverable state
- Reset agent state to 'idle'
- For Witness: auto-restart via supervisor or manual gt witness start

### 2. Git State Corruption

**Scenario**: Merge conflict, failed rebase, detached HEAD

**Detection**:
- Git commands fail
- Dirty state that won't commit
- Branch diverged from origin

**Recovery**:
- gt doctor reports git health issues
- Manual intervention recommended
- Severe cases: remove clone, re-clone

### 3. Beads Sync Conflict

**Scenario**: Two polecats modify same issue

**Detection**:
- bd sync fails with conflict
- Beads tombstone mechanism handles most cases

**Recovery**:
- Beads has last-write-wins semantics
- bd sync --force in extreme cases
- Issues may need manual dedup

### 4. Tmux Failure

**Scenario**: Tmux server crashes, socket issues

**Detection**:
- All sessions inaccessible
- "no server running" errors

**Recovery**:
- Kill any orphan processes
- tmux kill-server && tmux start-server
- All agent states reset to idle
- Re-spawn active work

### 5. Claude API Issues

**Scenario**: Rate limits, outages, context limits

**Detection**:
- Sessions hang or produce errors
- Repeated failure patterns

**Recovery**:
- Exponential backoff (handled by Claude Code)
- For context limits: session cycling (mail-to-self)
- For outages: wait and retry

### 6. Disk Full

**Scenario**: Clones, logs, or beads fill disk

**Detection**:
- Write operations fail
- git/bd commands error

**Recovery**:
- Clean up logs: rm ~/.gastown/logs/*
- Remove old polecat clones
- gt doctor --fix can clean some cruft

### 7. Network Failure

**Scenario**: Can't reach GitHub, API servers

**Detection**:
- git fetch/push fails
- Claude sessions hang

**Recovery**:
- Work continues locally
- Queue pushes for later
- Sync when connectivity restored

## Recovery Principles

1. **Fail safe**: Prefer stopping over corrupting
2. **State is recoverable**: Git and beads have recovery mechanisms
3. **Doctor heals**: gt doctor --fix handles common issues
4. **Emergency stop**: gt stop --all as last resort
5. **Human escalation**: Some failures need Overseer intervention

## Implementation

- Document each failure mode in architecture.md
- Ensure doctor checks cover detection
- Add recovery hints to error messages
- Log all failures for debugging


Polecat Mood Plugin (standard)

Standard witness plugin that assesses polecat emotional state.

## Location
`<rig>/plugins/witness/polecat-mood/`

## Mood Emojis
| Mood | Emoji | Detection |
|------|-------|-----------|
| working | 😺 | Active tool calls, making progress |
| productive | 😸 | Completing tasks, tests passing |
| idle | 🐱 | Waiting at prompt, no recent activity |
| confident | 😼 | Self-reviewing, about to submit |
| struggling | 😿 | Repeated errors, test failures |
| stuck | 🙀 | No progress for 10+ min |
| done | 😽 | Work complete, requesting shutdown |
| blocked | 😾 | Explicitly waiting on dependency |

## Plugin Config (plugin.yaml)
```yaml
name: polecat-mood
description: Assess polecat emotional state from session activity
trigger: patrol
tier: haiku
input: session-capture
```

## Output
Plugin outputs gt commands:
```
gt polecat mood Rictus 😺
gt polecat mood Nux 😿
```

## Customization
Users can fork and modify prompt.md to change assessment criteria or add custom moods.


Refinery gates: test/lint/build before merge

Before merging polecat work to main, run configurable quality gates.

**From VC**: internal/gates/ - parallel execution with timeout, any failure = overall failure.

**Gas Town implementation**: Refinery config with gate commands:
```yaml
gates:
  test:
    cmd: go test ./...
    timeout: 5m
  lint:
    cmd: golangci-lint run
    timeout: 2m
  build:
    cmd: go build ./...
    timeout: 3m
parallel: true
```

If gates fail, don't merge. Polecat can iterate and retry.

**Value**: Prevents broken code from reaching main. VC had 90.9% gate pass rate.

**VC complexity**: ~200 lines Go
**Gas Town complexity**: ~10 lines YAML


Recover stale polecat work: 4 branches with unpushed commits

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

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

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

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


Merge: gt-3x0z.3

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


VM outpost setup: Terraform and documentation

## Overview

Documentation and optional Terraform for setting up VM outposts.

## Manual Setup Guide

```markdown
# Setting Up a VM Outpost

## Prerequisites
- GCE VM (or any Linux machine with SSH access)
- SSH key pair
- Git configured on VM

## Steps

1. Install Claude Code on VM:
   ```bash
   ssh user@vm
   npm install -g @anthropic-ai/claude-code
   ```

2. Clone Gas Town:
   ```bash
   mkdir -p ~/ai
   cd ~/ai
   gt install .
   ```

3. Configure Git credentials:
   ```bash
   git config --global user.name "Your Name"
   git config --global credential.helper store
   ```

4. Add outpost to local config:
   ```bash
   gt outpost add ssh \
     --name gce-burst \
     --host 10.0.0.5 \
     --user steve \
     --key ~/.ssh/gce_worker \
     --town-path /home/steve/ai \
     --max-workers 8
   ```

5. Test connectivity:
   ```bash
   gt outpost ping gce-burst
   ```
```

## Terraform Module (Optional)

```hcl
# deploy/terraform/vm-outpost/main.tf

variable "project" {}
variable "zone" { default = "us-central1-a" }
variable "machine_type" { default = "e2-standard-4" }

resource "google_compute_instance" "outpost" {
  name         = "gastown-outpost"
  machine_type = var.machine_type
  zone         = var.zone

  boot_disk {
    initialize_params {
      image = "ubuntu-2204-lts"
      size  = 100
    }
  }

  network_interface {
    network = "default"
    access_config {}
  }

  metadata_startup_script = file("${path.module}/startup.sh")
}

output "external_ip" {
  value = google_compute_instance.outpost.network_interface[0].access_config[0].nat_ip
}
```

## Files

- `docs/vm-outpost-setup.md`
- `deploy/terraform/vm-outpost/` (optional)

Depends on: gt-9a2.5 (SSHOutpost)


Rig doctor checks: Refinery health, clones, gitignore

Rig-level doctor checks.

## Checks

### RigIsGitRepo
- Verify .git/ directory exists
- Verify git status works
- Fix: Cannot auto-fix

### GitExcludeConfigured
- Check .git/info/exclude contains Gas Town dirs
- Required entries: polecats/ witness/ refinery/ mayor/
- Fix: Append missing entries

### WitnessExists
- Verify witness/ directory exists
- Verify witness/rig/ is a git clone
- Verify witness/mail/inbox.jsonl exists
- Fix: Create structure, clone repo

### RefineryExists
- Verify refinery/ directory exists
- Verify refinery/rig/ is a git clone
- Verify refinery/mail/inbox.jsonl exists
- Fix: Create structure, clone repo

### MayorCloneExists
- Verify mayor/ directory exists
- Verify mayor/rig/ is a git clone
- Fix: Create structure, clone repo

### PolecatClonesValid
- For each polecat in polecats/:
  - Verify is a git clone
  - Verify on polecat branch
  - Warn if has uncommitted changes
- Fix: Cannot auto-fix (data loss risk)

### BeadsConfigValid (if applicable)
- If .beads/ exists, verify bd commands work
- Check beads sync status
- Warn if out of sync
- Fix: Run bd sync

## Implementation

```go
var RigChecks = []Check{
    &RigIsGitRepoCheck{},
    &GitExcludeConfiguredCheck{},
    &WitnessExistsCheck{},
    &RefineryExistsCheck{},
    &MayorCloneExistsCheck{},
    &PolecatClonesValidCheck{},
    &BeadsConfigValidCheck{},
}
```


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)


MCP beads tools fail from polecat directories

The beads MCP plugin (plugin:beads:beads) fails to find issues when invoked from polecat directories.

## Observed
- Polecat in /gt/gastown/polecats/dementus
- MCP tool: plugin:beads:beads - show (issue_id: 'gt-th7')
- Error: 'bd command failed: Error: no issue found matching gt-th7'

## Expected
MCP tools should work the same as running bd directly.

## Note
This may be related to gt-tmm (beads sync issue) rather than an MCP-specific bug. The MCP tool uses bd under the hood, and bd can't find the issue because the polecat's beads database is stale.


town handoff command (optional)

CLI commands for session handoff workflow (optional convenience).

## Commands

### gt handoff
Generate handoff interactively.
```
gt handoff [--send]
```
- Collects current state (status, inbox, beads)
- Prompts for additional notes
- --send: Mail to self and exit

### gt resume
Check for and display pending handoff.
```
gt resume
```
- Checks inbox for handoff message
- Displays formatted handoff if found
- Suggests next actions

## Implementation

These are convenience wrappers. The same workflow can be done manually:
```bash
# Manual handoff
town status > /tmp/handoff
town inbox >> /tmp/handoff
bd ready >> /tmp/handoff
# Edit and send
town mail send mayor/ -s "Session Handoff" -f /tmp/handoff
```

## Priority

P2 - Optional. Manual workflow works fine. Nice to have for UX.

## Notes

Part of session cycling workflow designed in gt-u82.


CLI: names commands for polecat naming pool

Polecat naming pool for auto-generated names.

## Commands

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

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

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

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

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

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

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

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

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


Spawn inject: Enter not submitted after multiline paste

When gt spawn injects a multiline context (85+ lines), Claude Code shows
'[Pasted text #1 +85 lines]' but the prompt is not submitted.

The tmux SendKeys function does include 'Enter' but it appears to not work
for long pasted text:

```go
func (t *Tmux) SendKeys(session, keys string) error {
    _, err := t.run("send-keys", "-t", session, keys, "Enter")
    return err
}
```

Possible fixes:
1. Use tmux paste-buffer instead of send-keys for long text
2. Send Enter separately after the text
3. Use bracketed paste mode correctly

Reproduction:
```bash
gt spawn gastown/Nux --issue gt-u1j.13 --create
# Session shows pasted text but waits at prompt
```