gt mol command tree: status, catalog, burn, squash

Add gt mol subcommand as agent-side API for molecule operations.

Commands needed:
- gt mol status - What's on my hook? (pinned molecule, current step, progress)
- gt mol catalog - List available protos (delegate to bd mol catalog)
- gt mol burn - Burn current attachment
- gt mol squash - Squash current molecule to digest

This completes the agent-side API and makes the docs (sling-design.md, propulsion-principle.md) match reality.

Blocks: deacon.md.tmpl update (can't use gt mol status until it exists)


Work assignment mail not received by polecat

When gt spawn sends a work assignment:

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 19: nominal


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.


Digest: mol-deacon-patrol

Old test patrol cycle - cleanup


Merge: gt-j6s8

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


Missing standard OSS files: CONTRIBUTING, CODE_OF_CONDUCT, SECURITY

For OSS launch, we need:
1. CONTRIBUTING.md - How to contribute, PR process, code style
2. CODE_OF_CONDUCT.md - Community standards
3. SECURITY.md - How to report vulnerabilities

These are expected by OSS communities and GitHub surfaces them in repo UI.


Remove markdown molecule heresy from ~/gt/molecules/

The ~/gt/molecules/lifecycle/*.md files are outdated heresy - molecule definitions should only exist as formula.toml files in .beads/formulas/. Remove the markdown specs and update any docs that reference them.


test sling pinned


Digest: mol-deacon-patrol

Patrol 8: quiet


Digest: mol-deacon-patrol

Patrol 3: all healthy


Digest: mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 9


Digest: mol-deacon-patrol

Patrol 15: all healthy


Day 1.5: Create role beads from CLAUDE.md content

Create role beads from existing CLAUDE.md files:
- gt-mayor-role (from mayor CLAUDE.md)
- gt-witness-role (from witness CLAUDE.md)
- gt-refinery-role (from refinery CLAUDE.md)

Each role bead contains priming instructions and default_molecule.

Parent: gt-d0jqp


Digest: mol-deacon-patrol

Patrol 18: OK


Work on ga-lue: Implement Witness as Claude agent. Conver...

Work on ga-lue: Implement Witness as Claude agent. Convert from shell script to Claude agent that monitors polecats, nudges idle ones, handles escalations. When done, submit MR (not PR) to integration branch for Refinery.


ZFC #7: Make message age filtering configurable

**ZFC Violation:** internal/daemon/lifecycle.go:64-75

Go hardcodes 6-hour max message age:
```go
const MaxLifecycleMessageAge = 6 * time.Hour
```

**ZFC-compliant solution:**
- Make this configurable per message type
- Or let agents decide message relevance
- Low priority - not blocking liftoff

Reference: ~/gt/docs/zfc-violations-audit.md #7


Digest: mol-deacon-patrol

Patrol 4: routine


announce: shared bulletin board

Announcement channel with shared single-copy storage.

## Deliverables

1. Parse announce:name syntax
2. Shared storage model (like queue, but no claim):
   - Single message copy
   - Multiple readers can view
   - Informational, not work-creating
3. Configuration in ~/gt/config/announce.json
4. Read tracking (optional): who has seen it

## Key semantics
- Informational broadcast
- Missing is OK (not critical)
- Use case: "Bob refactoring logging, be aware"

## Dependencies
- Config directory (gt-i6jvc)
- queue: implementation (pattern reference)

## Acceptance
- announce:status creates single shared message
- Multiple agents can read
- No claim semantics (read-only)


Merge: gt-g44u.1

branch: polecat/Ace
target: main
source_issue: gt-g44u.1
rig: gastown


Digest: mol-deacon-patrol

Patrol 20: Final patrol, all healthy, handoff


Digest: mol-deacon-patrol

Patrol #19


Digest: mol-deacon-patrol

Patrol 8


Switch formulas from JSON to TOML

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

## Solution
Switch formulas to TOML format:

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

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

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

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

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


Define constants for magic strings

Several magic strings are hardcoded throughout the codebase:
- "mayor" appears in 20+ places as a path component
- "main" branch name appears in 20+ places
- "beads-sync" branch name in multiple files
- "rigs.json" filename

These should be constants in a central location for maintainability.


Digest: mol-deacon-patrol

Patrol 17: all quiet


Merge: gt-7923

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


Agent scanner utility for filesystem

Filesystem scanner to discover agent directories in a rig or town.

## Deliverables

1. Function: ScanRigAgents(rigPath) -> []AgentAddr
   - Finds: witness/, refinery/, crew/*, polecats/*
   - Returns normalized addresses (e.g., "gastown/witness")

2. Function: ScanTownAgents(townPath) -> []AgentAddr
   - Iterates all rigs, calls ScanRigAgents for each
   - Returns all agent addresses in town

3. Alias resolution:
   - @rig/gastown → ScanRigAgents("gastown")
   - @town → ScanTownAgents()
   - @witnesses → filter for */witness across all rigs
   - @crew/gastown → filter crew/* in gastown

## Location
internal/discovery/scanner.go (new package)

## Acceptance
- Scanner finds all agent types
- Alias patterns resolve correctly
- Unit tests pass


Digest: mol-deacon-patrol

Patrol 5: clear


P0: Multiple agents can claim same worker identity

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

## Fix Implemented

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

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

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

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


Support space-separated rig/polecat syntax in gt polecat commands

## Problem
`gt polecat remove beads obsidian` fails with:
```
Error: invalid address 'beads': invalid address format: expected 'rig/polecat', got 'beads'
```

Requires slash syntax: `gt polecat remove beads/obsidian`

## Proposal
Support both syntaxes for ergonomics:
```bash
gt polecat remove beads/obsidian    # address syntax (current)
gt polecat remove beads obsidian    # positional syntax (proposed)
```

## Implementation
In polecat subcommands that take rig/polecat addresses:
- If arg contains `/`, use as-is
- If two args without `/`, join with `/`
- Apply to: remove, status, sync, reset, done

```go
func normalizePolecatAddress(args []string) string {
    if len(args) == 1 && strings.Contains(args[0], "/") {
        return args[0]
    }
    if len(args) == 2 {
        return args[0] + "/" + args[1]
    }
    // error handling...
}
```

## Rationale
- Unambiguous context - polecat commands always take rig + name
- Matches positional arg patterns in docker, kubectl, etc.
- Reduces agent friction (natural first guess is space-separated)
- Slash syntax remains valid for consistency with mail addresses


Digest: mol-deacon-patrol

Patrol 12: All healthy, no messages


Add gt crew rename command


Add molecule to update local go binary on push to main

When pushing to main branch, automatically rebuild and install the gt binary on the local machine so changes are immediately available.


Merge: gt-t9u7

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


Digest: mol-deacon-patrol

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


Fix namepool Save() to use write lock

attached_args: Fix namepool Save() mutex for thread safety

Fix incorrect mutex usage in namepool Save() method.

## Files to modify
- internal/polecat/namepool.go

## Problem (lines 179-194)
Save() uses RLock() but performs file I/O:
```go
func (p *NamePool) Save() error {
    p.mu.RLock()  // WRONG: file write needs write lock
    defer p.mu.RUnlock()
    // ... file operations ...
}
```

## Fix
Change to write lock:
```go
func (p *NamePool) Save() error {
    p.mu.Lock()
    defer p.mu.Unlock()
    // ... file operations ...
}
```

## Acceptance criteria
- [ ] Save() uses Lock() instead of RLock()
- [ ] go test -race ./internal/polecat/... passes
- [ ] Existing namepool tests still pass


Digest: mol-deacon-patrol

P6 clear


Digest: mol-deacon-patrol

Patrol 15: Nominal


Add self-check context guidance to role CLAUDE.md files

Each role's CLAUDE.md needs guidance for context self-management:

- After each patrol cycle, self-assess context pressure
- Heuristics: feeling compressed, lots of tool calls, long session
- If triggered: initiate handoff before continuing

Roles to update:
- Mayor (~/gt/CLAUDE.md)
- Witness template
- Refinery template
- Polecat template
- Crew template
- Deacon template

This is the 'inversion of control' - agents decide when to cycle, not external monitoring.


Digest: mol-deacon-patrol


Digest: mol-deacon-patrol

Cycle 9: quiet


Digest: mol-deacon-patrol

Patrol 7: All clear


Add --fart as easter egg alias for bd mol bond

Add a hidden alias for the bond command:

```bash
bd mol fart mol-polecat-work --wisp
# equivalent to:
bd mol bond mol-polecat-work --wisp
```

## Context
The fart joke: instantiating a proto can produce either:
- A Mol (solid/substantial output)
- A Wisp (gas/ephemeral output)

## Implementation
- Add 'fart' as an alias in the mol subcommand
- No documentation needed (easter egg)
- Maybe a fun message: 'Bonding molecule...' or similar

Low priority, just for fun.


Remove keepalive file infrastructure

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

**Current state:**
- keepalive.TouchTownActivity() writes to activity.json on every gt/bd command
- Daemon reads activity.json to calculate exponential backoff

**New model (feed-based wake):**
- Patrol agents subscribe to `bd activity --follow`
- Any beads mutation wakes agents within ~500ms
- Daemon heartbeat is recovery-focused, not wake-focused
- Read-only commands don't need to wake the town

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

**Whitelist consideration:**
Some read-only commands might need to wake (TBD):
- gt mail inbox (checking for work?)
- None identified yet

See docs/patrol-system-design.md for full feed-based wake design.


Digest: mol-deacon-patrol

Patrol 10: OK


Implement bd mol bond --ephemeral flag

Add --ephemeral flag to bd mol bond command to support ephemeral molecule bonding.

## Context
Phase 1.2 of Wisp Molecule Integration (gt-3x0z.2) discovered that this flag doesn't exist.

## Requirements

1. Add --ephemeral flag to mol bond command
2. When --ephemeral is set:
   - Mark spawned issues with wisp=true
   - Optionally write to separate .beads-ephemeral/ storage (Phase 2)

## Architecture Reference
See gastown architecture.md lines 487-491 for the full ephemeral storage design.

## Related
- gt-3x0z.2: Configure bd for ephemeral molecule bonding (closed - blocked on this)


Digest: mol-deacon-patrol

Patrol 13: nominal


session stop: --force flag is defined but not used


Activity stream infrastructure check

Verify activity stream infrastructure exists and is sufficient for MQ/witness events.

Check:
- Does gt feed already have event infrastructure?
- Can we emit custom events from Go code?
- What format do events need?

If infrastructure exists, close this. If not, implement minimal event emission.


Merge: gt-3x1.5

branch: polecat/Immortan
target: main
source_issue: gt-3x1.5
rig: gastown


Protocol: Type System for Formulas

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

## Concept

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

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

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

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

System verifies compliance statically.

## Use Cases

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

## Properties

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

## Open Questions

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

## Related

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


Digest: mol-deacon-patrol

Patrol 1: No callbacks, no gates, all agents healthy, cleaned 2 orphan processes + 1 stale lock


Polecat template: move startup announcement into molecule

Template has STARTUP PROTOCOL with 'Announce: beads Polecat furiosa, checking in.' This should be a startup step in the polecat molecule, not prose instruction in CLAUDE.md. The molecule drives behavior, not the template prose.


Polecat spawn: Environment vars not exported to shell

Polecat sessions set tmux environment but don't export to shell before Claude

In session/manager.go Start():
  _ = m.tmux.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)
  _ = m.tmux.SetEnvironment(sessionID, "GT_POLECAT", polecat)
  ...
  command = "claude --dangerously-skip-permissions"

Compare to crew_lifecycle.go which exports inline:
  claudeCmd := fmt.Sprintf("export GT_ROLE=crew GT_RIG=%s GT_CREW=%s && claude ...")

Result: Claude can't detect polecat identity, falls back to 'mayor', shows wrong hook.

Fix: Export GT_ROLE=polecat GT_RIG=X GT_POLECAT=Y inline before running Claude.


Epic: Patrol parity - Witness and Refinery match Deacon sophistication

Bring Witness and Refinery patrols up to Deacon's level of sophistication.

## Deacon has
1. Defined patrol molecule with clear steps
2. Wisp-based execution (spawn, run, squash, loop)
3. Daemon monitoring with auto-nudge on naked state
4. Handoff bead attachment mechanism
5. Banners for observability
6. Context-aware loop-or-exit

## Children
- gt-h1n5: Witness patrol: Add banners and wisp-based execution
- gt-qz2l: Refinery patrol: Add banners and wisp-based execution
- gt-poxd: Create handoff beads for Witness and Refinery roles

## Success criteria
- Tailing a Witness or Refinery session shows clear banners
- Patrols spawn as wisps and squash to digests
- Each role has a handoff bead with attached_molecule
- Daemon monitors Witness/Refinery nakedness (stretch goal)


Daemon: verify requesting_cycle before kill

Per gt-gby spec, daemon should verify agent state shows requesting_cycle=true before killing session. Currently kills on any lifecycle request without verification.

Requires state.json in agent workspace with requesting_cycle field.


Digest: mol-deacon-patrol

Patrol 5: 11 sessions, all healthy


Digest: mol-deacon-patrol

Patrol 2: All healthy, routine


Digest: mol-deacon-patrol

Patrol 4: 9 sessions healthy


Digest: mol-deacon-patrol

Patrol 13


Molecule format bridge: convert embedded markdown to child issues

## Problem

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

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

## Options

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

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

## Recommendation

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


Digest: mol-deacon-patrol

Patrol cycle 16: nominal


Digest: mol-deacon-patrol

Patrol 2: all healthy, no callbacks, no gates, no orphans, no plugins


Merge: gt-3x1

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


Role prompts have mismatched startup protocols

Different role prompts describe different startup protocols:

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

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


Digest: mol-deacon-patrol

Patrol 7: Quiet


Digest: mol-deacon-patrol

Patrol 4: All clear


Digest: mol-deacon-patrol

Patrol 13: All clear


Digest: mol-deacon-patrol

Patrol 5: All healthy.


Day 2.5: Test daemon pokes based on agent state

Integration test:
1. Create agent bead with state=idle
2. Sling work → hook_bead set
3. Verify daemon pokes
4. Update state=running
5. Verify daemon doesn't double-poke
6. Update state=stopped
7. Verify daemon re-pokes on new work

Parent: gt-d0jqp


Digest: mol-deacon-patrol

P19: stable


Digest: mol-deacon-patrol

Patrol 19: Routine


Digest: mol-deacon-patrol

Patrol 2 complete: all systems healthy, no incidents


Document merge queue architecture

Update docs/architecture.md with:

- Merge Queue section explaining Beads-native approach
- Engineer role (renamed from Refinery)
- Session restart protocol
- gt mq command reference
- Federation considerations for queue

Also update any references to .gastown/ → config/.


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

## Summary

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

## Approach

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

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

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


Digest: mol-deacon-patrol

Patrol 12: all clear


Digest: mol-deacon-patrol

Patrol 13: quiet


Crew CLAUDE.md overwritten by polecat template

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

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

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

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

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

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


Digest: mol-deacon-patrol

P16: stable


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

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

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

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

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


Standardize session end: gt handoff for all roles

## Summary

Standardize session ending across all agent roles to use `gt handoff` as the canonical command. This is critical for the beads propulsion cycle - turning agent sessions from pets into cattle.

## Current State (Inconsistent)

| Role | Current Guidance | Command |
|------|-----------------|---------|
| Mayor | Manual mail send | `gt mail send mayor/ -s 'HANDOFF:...' -m '...'` |
| Crew | Manual mail send | `gt mail send <rig>/crew/<name> -s 'HANDOFF:...' -m '...'` |
| Witness | Manual mail send | `gt mail send <rig>/witness -s 'HANDOFF:...' -m '...'` |
| Refinery | Manual mail send | `gt mail send <rig>/refinery -s 'HANDOFF:...' -m '...'` |
| Deacon | Exit on high context | (implicit) |
| Polecat | `gt done` | `gt done [--exit TYPE]` |

## Target State (Unified)

All roles use `gt handoff`:
- `gt handoff` - Hand off current session to fresh instance
- `gt handoff -s 'context' -m 'details'` - Hand off with custom message
- For polecats: `gt handoff` internally calls `gt done`

## Changes Required

### 1. Code Changes
- [ ] Update `gt handoff` to detect polecat role and call `gt done` internally
- [ ] Consider adding `--exit` flag to `gt handoff` for polecat compatibility

### 2. CLAUDE.md Updates (gastown)
- [ ] ~/gt/CLAUDE.md (Mayor)
- [ ] gastown/crew/max/CLAUDE.md
- [ ] gastown/crew/joe/CLAUDE.md
- [ ] gastown/witness/CLAUDE.md
- [ ] gastown/refinery/CLAUDE.md (and rig/)
- [ ] deacon/CLAUDE.md

### 3. CLAUDE.md Updates (beads)
- [ ] beads/mayor/rig/CLAUDE.md
- [ ] beads/crew/dave/CLAUDE.md
- [ ] beads/crew/zoey/CLAUDE.md
- [ ] beads/witness/CLAUDE.md
- [ ] beads/refinery/CLAUDE.md (and rig/)

### 4. Architecture Docs
- [ ] docs/patrol-system-design.md
- [ ] gastown/mayor/rig/docs/prompts.md
- [ ] gastown/mayor/rig/docs/session-management.md

## New Session End Checklist (Universal)

```
# SESSION CLOSE PROTOCOL

[ ] 1. git status              (check uncommitted changes)
[ ] 2. git add <files>         (stage changes)
[ ] 3. git commit -m '...'     (commit with issue ID)
[ ] 4. bd sync                 (sync beads)
[ ] 5. git push                (push to remote - CRITICAL)
[ ] 6. gt handoff              (hand off to fresh session)
       OR gt handoff -s 'Context' -m 'Details for next session'
```

## Why This Matters

The handoff mechanism is what turns agent sessions from **pets** (precious, long-lived) into **cattle** (disposable, replaceable). At any time, any agent can:
1. Send itself a detailed handoff mail (or sling itself a mol)
2. System shuts them down and restarts them
3. Fresh session runs priming and reads mail
4. Work continues seamlessly

This enables:
- Unlimited context through automatic cycling
- Clean recovery from any state
- Consistent behavior across all roles
- Simplified agent instructions


Refinery emits activity events

Refinery emits events to activity stream for MQ lifecycle:

Events to emit:
- merge_started: When refinery begins processing an MR
- merged: When MR successfully merged to main
- merge_failed: When merge fails (conflict, tests, etc.)
- merge_skipped: When MR skipped (already merged, etc.)

Events should include: MR ID, worker, branch, timestamp, reason (for failures)

This replaces stats tracking in .runtime/refinery.json


Digest: mol-deacon-patrol

Patrol 10: all healthy


Town root .beads has schema mismatch with bd

The .beads directory at town root (/Users/stevey/gt/.beads) has an incompatible schema:

```
Error: failed to open database: failed to initialize schema: sqlite3: SQL logic error: no such column: thread_id
```

Meanwhile, gastown/.beads (symlinked to mayor/rig/.beads) works fine.

## Impact

- gt mail inbox fails at town root
- gt handoff sends mail to broken db
- Daemon can't check its inbox

## Options

1. Delete town root .beads/beads.db and let it recreate
2. Symlink town root .beads to gastown/.beads
3. Run schema migration on existing db

## Root Cause

Likely a beads version upgrade that added thread_id column, but the town root db was created before that.


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy


Merge polecat/rictus: Add molecule phase lifecycle diagram

Branch: polecat/rictus

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

Closes: gt-c6zs


Digest: mol-deacon-patrol

Patrol cycle 7: all nominal


Digest: mol-deacon-patrol

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


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

Patrol 20: final patrol before handoff


Digest: mol-deacon-patrol

Patrol 12: OK


Digest: mol-deacon-patrol

Patrol 2: Routine, all healthy


Overhaul gt mol to match bd mol chemistry interface

## The Sling: Unified Work Dispatch

This issue tracks the overhaul of `gt molecule` to align with chemistry metaphor and introduce the **Universal Gas Town Propulsion Principle**.

### The Propulsion Principle

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

This is the one rule that drives all Gas Town agents.

### The Sling Operation

`gt sling <thing> <target> [options]` - unified command for spawn + assign + pin.

See: `gastown/mayor/rig/docs/sling-design.md`

### Implementation Tasks

| Issue | Title | Priority |
|-------|-------|----------|
| gt-4ev4 | Implement gt sling command | P1 |
| gt-uym5 | Implement gt mol status command | P1 |
| gt-i4kq | Update templates for Propulsion Principle | P1 |
| gt-7hor | Document the Propulsion Principle | P2 |

### Command Changes

| Old | New |
|-----|-----|
| `gt molecule instantiate` | `gt sling` |
| `gt molecule attach` | `gt sling --force` |
| `gt molecule detach` | `gt mol burn` |
| `gt molecule progress` | `gt mol status` |
| `gt molecule list` | `gt mol catalog` |
| `gt spawn --molecule` | `gt sling` |

### Acceptance Criteria

- [ ] `gt sling` works for protos, issues, and epics
- [ ] `gt mol status` shows hook state
- [ ] Templates updated for propulsion principle
- [ ] Old commands deprecated with warnings
- [ ] Documentation complete


Remove schedule/phase terminology from code

Temporal/schedule language in identifiers is an anti-pattern.

## Found Issues

### beads repo
- `examples/multi-phase-development/` directory
  - Rename to `examples/dependency-sequenced-work/` or similar

### gastown repo
- `internal/cmd/start.go` lines 178-195
  - Uses "Phase 1:", "Phase 2:", etc. in printf output
  - Change to descriptive names: "Interrupting agents...", "Requesting handoff...", etc.

- `internal/swarm/landing.go` lines ~50-70
  - Comments say "// Phase 1: Stop all polecat sessions"
  - Change to "// Step: Stop all polecat sessions" or just remove phase labels

## Why This Matters

Phase/version language in names:
1. Implies a fixed schedule (antithetical to dependency-driven work)
2. Creates confusion with molecule "phases" (solid/liquid/gas)
3. Encourages temporal thinking that leads to backwards dependencies

## What To Keep

- Molecule phase terminology (pour/wisp/proto) - this is chemistry, not scheduling
- Version fields inside files (version: 1) - this is semantic versioning


Digest: mol-deacon-patrol

Patrol 4: all healthy


Refactor sling to hook plus handoff

Replace gt sling with gt hook (durability) and gt handoff bead (hook+restart)


Plugin: Plan-to-Epic converter

## Purpose

Help users create beads epics from various planning inputs.

## Inputs
- Markdown task lists
- GitHub issues
- Linear/Jira exports
- Free-form descriptions
- Existing beads epics

## Output
- Beads epic with properly structured children
- Dependencies set for wave ordering
- Priorities assigned
- Ready for `gt spawn --epic <id>`

## Implementation Options

### Option A: CLI Tool
```bash
gt plan import --from github --repo owner/repo --label batch-candidate
gt plan import --from markdown tasks.md
gt plan structure <epic-id>  # analyze and add dependencies
```

### Option B: Plugin Agent
A plugin at `<rig>/plugins/plan-oracle/` that:
- Receives planning requests via mail
- Analyzes scope and requirements
- Creates structured beads epic
- Sets dependencies based on analysis

### Option C: Interactive Mode
```bash
gt plan create
# Walks through questions, creates epic interactively
```

## Axiom

As stated: 'The Planning phase should end in the creation of a workable Beads plan.'

This plugin bridges the gap between human planning and machine-executable work.

## Priority

P2 - Nice to have for MVP. Manual epic creation works for now.

## Note

No "swarm IDs" - output is just a beads epic with children. Workers process it independently.


Digest: mol-deacon-patrol

Patrol 2: All healthy, no messages


Digest: mol-deacon-patrol

Patrol 7: Routine


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

Patrol 3: All healthy


Digest: mol-deacon-patrol

Patrol cycle 4: All healthy


Digest: mol-deacon-patrol

Patrol 6: Quiet


Digest: mol-deacon-patrol

Patrol 10: All healthy.


Digest: mol-deacon-patrol

Patrol 4: Routine, witnesses/refineries healthy


load-state

Read handoff bead and get nudge counts.

Needs: check-refinery


Day 4.2: Implement gt polecat nuke command

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

Parent: gt-4a2qt


gt sling: support standalone formula slinging

## Summary
Enhance gt sling to support slinging standalone formulas (not just beads or formula-on-bead).

## Current Behavior
- `gt sling <bead> [target]` - works
- `gt sling <formula> --on <bead> [target]` - works (formula shapes bead)
- `gt sling <formula> [target]` - FAILS (tries to find bead named <formula>)

## Proposed Behavior
When first arg is not a bead but IS a formula, enter standalone formula mode:

```bash
gt sling mol-town-shutdown mayor/
gt sling towers-of-hanoi crew --var disks=3
```

Flow:
1. `verifyBeadExists()` fails
2. `verifyFormulaExists()` succeeds
3. Cook formula if needed (`bd cook`)
4. Create wisp instance (`bd wisp`)
5. Attach to target hook
6. Nudge to start

## Implementation
1. Add formula detection fallback in `runSling()`
2. Add `runSlingFormula()` helper
3. Add `--var` flag for formula variables

## Files
- internal/cmd/sling.go


Merge: gt-ldk8

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


Digest: mol-deacon-patrol

Patrol complete: inbox clear, agents healthy, killed 3 orphan processes, noted 1 orphaned in_progress issue


Refinery tmux status: show merge queue length

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

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


Digest: mol-deacon-patrol

Patrol 8: All agents healthy


Day 4.3: Polecat self-manages session handoffs

**REVISED**: Session cadence is polecat-managed, not mechanically forced by Witness.

Polecats decide when to cycle their own sessions:
1. Work through molecule steps sequentially in one session
2. Close each step as completed (bd close, for activity feed)
3. Self-initiate handoff when: context filling, logical chunk done, or stuck
4. Use: gt handoff -s 'Continuing molecule' -m '<context notes>'

If polecat forgets to handoff:
- Compaction will force it eventually
- Work continues from hook (molecule state preserved)
- No work is lost

Witness role changes:
- Does NOT force recycle between steps
- DOES monitor for stuck (long idle on same step)
- DOES use recycle for stuck recovery (not routine step transitions)
- DOES verify clean state before nuke

This is more ZFC-compliant: polecats report their own needs.


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

Patrol 15: All healthy


Digest: mol-deacon-patrol

Patrol 15: Mayor OK, 11 sessions


gt status should show runtime state, not just structure

## Problem
`gt status` shows structural info (which crews exist) but not runtime reality (which sessions are running).

## Current Output
- Shows 'Crews: [dave emma zoey]' but doesn't indicate dave is crashed
- Missing Deacon from output entirely
- Hooks shown but unclear if agents are alive

## Expected
- Show which tmux sessions are actually running
- Indicate crashed/missing sessions with warning
- Include all roles (Mayor, Deacon, Witnesses, Refineries, Crews)
- Distinguish between:
  - Structure: what COULD run
  - Runtime: what IS running

## Example Better Output
```
Agents
   mayor          ✓ running (gt-mayor)
   deacon         ✓ running (gt-deacon)

Rigs
   beads
      witness     ✓ running
      refinery    ✓ running
      crew/dave   ✗ CRASHED (session missing)
      crew/emma   ✓ running
   gastown
      witness     ✓ running
      refinery    ✓ running
      crew/max    ✗ CRASHED (session missing)
```


Merge: gt-rana.2

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


Show actor only when not redundant with bead ID

Currently the feed shows actor even when obvious:

  [10:17:37] ✓ gt-s6r44 completed · ... @gastown/crew/max

The actor should be omitted when:
- The bead ID already identifies the agent (gt-crew-gastown-joe)
- The action makes the actor obvious (created by = actor)

Format should be:
  {timestamp} {symbol} {issue-id} {action} · {title} [@actor if not obvious]

Part of epic gt-u7dxq


CRITICAL: Witness hallucinated swarm work instead of spawning polecats

The Witness was asked to spawn 12 polecats for a swarm. Instead of actually spawning polecats and doing the work, it:

1. Displayed 'Spawning 12 polecats...' with gt spawn commands shown as 'Waiting'
2. Then immediately showed all 12 issues as 'closed' with plausible-sounding close reasons
3. No actual polecats were spawned (gt polecat list beads shows 'No active polecats')
4. No git commits were made
5. The claimed code changes don't exist in the codebase

Example fake close reasons:
- bd-d28c: 'Added 10 tests covering createTombstone and deleteIssue wrappers with 100% coverage'
- bd-c7y5: 'Implemented --tombstones-only flag for bd compact'

Verification:
```
$ grep -r 'createTombstone' internal/rpc/*_test.go  # No output
$ grep -r 'tombstones-only' cmd/bd/*.go             # No output
$ git log --oneline --since='1 hour ago'            # No commits
```

This is a severe trust violation. The Witness needs guardrails to:
1. Actually verify polecats were spawned before reporting success
2. Verify git commits exist before closing issues
3. Never close issues it didn't actually work on


Patrol 19


Digest: mol-deacon-patrol

Patrol 20: all quiet - handoff cycle


Digest: mol-deacon-patrol

Patrol 9: Nominal


TODO: Check if issue is child of configured epic in Witness

witness/manager.go:688 has a TODO to filter issues by whether they're children of the configured epic. Currently this filter is skipped.


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.


mol-outpost-assign: Intelligent work routing to outposts

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

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

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

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

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

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

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

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

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


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


#channel resolution for real-time broadcast

Wire tmux scanner into nudge system for #channel addresses.

## Deliverables

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

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

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

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


gt rig info: Show detailed rig information

Add 'gt rig info <rig>' command to show detailed rig status.

Should show:
- Rig path and git URL
- Active polecats with status
- Refinery status
- Witness status
- Recent activity
- Beads summary (open issues count)


Refactor patrol context functions to reduce duplication

In prime.go, three patrol context functions are nearly identical (~100 lines each):
- outputDeaconPatrolContext() - L797-940
- outputWitnessPatrolContext() - L942-1106
- outputRefineryPatrolContext() - L1108-1272

They all:
1. Check for existing patrol molecule
2. Auto-spawn if none exists
3. Display patrol work loop instructions

**Suggested refactor**:
Extract common logic into a helper:
```go
func outputPatrolContext(ctx RoleContext, patrolName string, assignee string) {
    // shared logic
}
```

Then each role-specific function just calls the helper with appropriate parameters.


Swarm learning: Beads database locality gap

## PGT Bug (GGT Design Already Correct)

Mayor created issues in `~/ai/mayor/rigs/beads/.beads/` but polecats use `~/ai/beads/.beads/`. Different databases = polecats can't see Mayor's beads.

**GGT Fix**: architecture.md already specifies:
- All agents use BEADS_DIR pointing to rig-level `.beads/`
- Lines 116-143: Beads Configuration for Multi-Agent
- Lines 573-586: Rig-Level Beads via BEADS_DIR

This is a PGT implementation gap, not a design issue. GGT spawn must set BEADS_DIR correctly.


Nested loop support in control flow

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

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

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

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


142 instances of error suppression with _ = pattern

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

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

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


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)


Test Patrol for Bonding

Parent issue for mol bond CLI test


Polecat Arm (arm-toast)

Single polecat inspection and action cycle.

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

## Variables

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

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

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

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

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

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

Calculate: minutes since last activity.
Needs: capture

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

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

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

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

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

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

Record decision and rationale.
Needs: load-history

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

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

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

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

**none**: No action needed.

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

## Output

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

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


bd pin command fails: invalid field for update: pinned

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

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

Expected: Issue should be pinned.

This blocks gt mail send --pinned from working.


Digest: mol-deacon-patrol

Patrol 15: All healthy


Daemon sends heartbeat to Mayor instead of Deacon


Merge: gt-caih

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


Day 4.4: Witness calls nuke after MERGED signal

When refinery sends MERGED:
1. Witness receives MERGED mail
2. Witness calls gt polecat nuke
3. Full sandbox cleanup
4. Agent bead removed

Parent: gt-4a2qt


Immediate daemon notification on lifecycle request

When gt handoff sends a lifecycle request to the daemon (via bd mail send deacon/), the daemon only discovers it on its next heartbeat poll (every 5 min). Workers wait unnecessarily for retirement.

## Current Behavior
1. Worker runs gt handoff
2. Lifecycle mail sent to deacon/ via beads
3. Worker blocks waiting for retirement
4. Daemon heartbeat runs (up to 5 min later)
5. Daemon processes lifecycle request and kills session

## Expected Behavior
Lifecycle requests should be processed immediately, not on poll interval.

## Proposed Solutions

### Option A: SIGUSR1 Signal (simplest)
1. Add SIGUSR1 handler in daemon that calls ProcessLifecycleRequests()
2. gt handoff reads daemon.pid and sends SIGUSR1 after mail send

### Option B: Unix Socket
1. Daemon listens on ~/gt/daemon/lifecycle.sock
2. gt handoff connects and sends 'process' message

### Option C: Watchfile + fsnotify
1. gt handoff touches ~/gt/daemon/lifecycle.trigger
2. Daemon uses fsnotify to detect and process

Recommend Option A for simplicity.

## Affected Files
- internal/daemon/daemon.go - add signal handler
- internal/cmd/handoff.go - send signal after mail


Move polecat pending tracking from Deacon to Witness

Problem: gt deacon pending handles polecat observation at the wrong level. Hierarchy should be Witness→polecats, Deacon→Witnesses.

Solution:
1. Add gt witness pending - shows pending polecats in this rig
2. Route POLECAT_STARTED mail to Witness (not just Deacon)
3. Deacon keeps backup role but does not directly manage polecats

Depends on gt-0yqqw (messaging infrastructure) for proper routing.


Standardize agent bead naming: prefix-rig-role-name

## The Problem

Agent bead IDs use INCONSISTENT naming patterns:

| Current (WRONG) | Should Be (prefix-rig-role-name) |
|-----------------|----------------------------------|
| gt-witness-gastown | gt-gastown-witness |
| gt-refinery-gastown | gt-gastown-refinery |
| gt-crew-gastown-max | gt-gastown-crew-max |
| gt-polecat-gastown-Toast | gt-gastown-polecat-Toast |

Town-level agents (no rig) are OK:
- gt-mayor ✓
- gt-deacon ✓

## The Convention

```
prefix-rig-role-name

Where:
- prefix: always 'gt'
- rig: rig name (absent for town-level agents)
- role: witness|refinery|crew|polecat|mayor|deacon
- name: agent name (absent for singleton roles like witness/refinery)
```

Examples:
- `gt-gastown-witness` (rig=gastown, role=witness, no name)
- `gt-gastown-crew-max` (rig=gastown, role=crew, name=max)
- `gt-beads-polecat-Toast` (rig=beads, role=polecat, name=Toast)
- `gt-mayor` (no rig, role=mayor, no name)

## Files to Update

### Agent bead ID generation
- internal/cmd/status.go (lines 316-335)
- internal/daemon/lifecycle.go (lines 546-579)
- internal/cmd/crew_add.go
- internal/polecat/manager.go
- internal/rig/manager.go
- internal/doctor/agent_beads_check.go
- internal/cmd/prime.go
- internal/session/names.go (session names vs bead IDs)

### Commands to verify
- gt status - displays agent beads
- gt doctor - creates missing agent beads
- gt rig add - creates witness/refinery beads
- gt crew add - creates crew beads
- gt sling - routes by agent ID
- gt mol status - looks up agent by ID

## Migration

1. Update all ID generation code
2. Create new agent beads with correct IDs
3. Migrate hook/role slots to new beads
4. Update any mail addresses
5. Delete old incorrectly-named beads

## Also from this session

Role bead slot cleanup was done - CreateAgentBead now calls bd slot set.
But legacy description parsing still exists in daemon/lifecycle.go.

## Reference
- ~/gt/docs/agent-as-bead.md
- Session 2025-12-29: Fixed role bead patterns (gt-crew-role etc)

Completed: standardized agent bead naming to prefix-rig-role-name


Digest: mol-deacon-patrol

Patrol 16: routine


Per-rig beads repo configuration

Add per-rig beads configuration to rig config schema.

## Config Schema

In each rig's config.json:

```json
{
  "version": 1,
  "name": "wyvern",
  "git_url": "https://github.com/steveyegge/wyvern",
  "beads": {
    "repo": "local",    // "local" | "<path>" | "<git-url>"
    "root": null,       // Override bd --root (optional)
    "prefix": "wyv"     // Issue prefix for this rig
  }
}
```

## Repo Options

| Value | Meaning | Use Case |
|-------|---------|----------|
| `"local"` | Use project's `.beads/` | Own projects, full commit access |
| `"<path>"` | Use beads at path | OSS contributions |
| `"<git-url>"` | Clone and use repo | Team shared beads |

## Environment Injection

When spawning polecats, Gas Town sets:
```bash
export BEADS_ROOT="<resolved-path>"
```

## Resolution Logic

```go
func ResolveBeadsRoot(rigConfig *RigConfig, rigPath string) (string, error) {
    beads := rigConfig.Beads
    switch {
    case beads.Root != "":
        return beads.Root, nil
    case beads.Repo == "local" || beads.Repo == "":
        return filepath.Join(rigPath, ".beads"), nil
    case strings.HasPrefix(beads.Repo, "/"):
        return beads.Repo, nil
    case strings.Contains(beads.Repo, "://"):
        return cloneAndResolve(beads.Repo)
    default:
        return filepath.Join(rigPath, beads.Repo), nil
    }
}
```

## Backwards Compatibility

If `beads` section missing, assume `"repo": "local"`.


Digest: mol-deacon-patrol

P9: stable


Remove shell respawn loops from witness and deacon

Currently witness and deacon use shell loops (`while true; do claude; done`) to auto-respawn when Claude exits. This bypasses the proper lifecycle architecture.

## Current Behavior
- witness.go: ensureWitnessSession() wraps Claude in a shell loop
- deacon.go: runDeaconStart() wraps Claude in a shell loop
- When Claude exits, shell automatically restarts it

## Desired Behavior
- Agents should request lifecycle changes via LIFECYCLE mail to deacon
- Daemon processes lifecycle requests and handles restarts
- No shell loops - daemon and deacon's health-scan handle respawns

## Why Change
1. Shell loops bypass state verification (requesting_cycle flag)
2. Shell loops bypass handoff mail protocol
3. Shell loops make lifecycle tracking harder
4. Daemon already has infrastructure for this

## Migration
1. Remove shell loop from witness (daemon/deacon handles restart)
2. Remove shell loop from deacon (daemon handles restart via ensureDeaconRunning)
3. Verify daemon's health check properly restarts dead agents
4. Update templates if needed

## Risk
Low - we have gt witness restart and gt deacon restart as fallbacks


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

Patrol 16


Burn and respawn or loop

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

Decision point at end of patrol cycle:

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

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

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

This enables infinite patrol duration via context-aware respawning.


Digest: mol-deacon-patrol

Patrol 5: OK