Digest: mol-deacon-patrol

Patrol complete: both rigs healthy, handoff threshold reached


Move disk 4: B → A

Move disk 4 from peg B to peg A. (Move 376/1023)


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 531/1023)


Proto debugging and inspection tools

Proto debugging and inspection tools.

With ephemeral protos (gt-4v1eo), this becomes:
- `bd cook <formula> --dry-run` - preview cooked output without persisting
- `bd cook <formula> --json` - output proto as JSON for inspection
- `bd cook <formula> --graph` - visualize step DAG

No persistent proto beads to inspect - formulas are the source of truth.


Digest: mol-deacon-patrol

Patrol 3: 3 rigs healthy, no incidents


Meta-formulas: formula generators

Support meta-formulas that generate multiple formulas from a template. Example: multi-lang-shiny that generates shiny-go, shiny-python, shiny-typescript from a for-each loop over languages. Enables DRY formula libraries.


Digest: mol-deacon-patrol

Patrol 18: All healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 358/1023)


Automatic spawn for ready work

Auto-spawn polecats for ready work:

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

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

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


gt spawn: Notify Deacon and Witness on polecat start

When gt spawn creates a polecat, it should mail both Deacon and Witness:

```
gt mail send <rig>/witness -s 'POLECAT_STARTED furiosa' -m 'Issue: gt-xxx'
gt mail send deacon/ -s 'POLECAT_STARTED gastown/furiosa' -m 'Issue: gt-xxx'
```

This enables:
- Witness to bond a lease to its patrol wisp
- Deacon to verify worker started (redundancy)
- Both to nudge if worker is idle at prompt

Part of the village self-monitoring architecture.


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 467/1023)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 559/1023)


gt sling: Set status=hooked instead of pinned

Update gt sling to use the new 'hooked' status when attaching work to an agent's hook.

## Current Behavior

gt sling sets status='pinned' on the work item.

## New Behavior

gt sling sets status='hooked' on the work item.

## Files to Update

- internal/cmd/sling.go (or wherever sling logic lives)
- Any tests that expect pinned status after sling

## CROSS-RIG DEPENDENCY

**BLOCKED BY: bd-s00m.1** (Schema: Add 'hooked' as valid status)

This task cannot start until the beads schema change is deployed. The 'hooked' status must be valid before gt can use it.

## Verification

1. gt sling gt-xyz gastown/furiosa
2. bd show gt-xyz → status should be 'hooked'
3. bd ready should NOT show gt-xyz's dependents


Merge: organic-1767106082951

branch: polecat/organic-1767106082951
target: main
source_issue: organic-1767106082951
rig: gastown


Enhance gt status with role hierarchy view

Show identity and role hierarchy in gt status:

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

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

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

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


Digest: mol-deacon-patrol

Patrol 20: routine, all healthy


Digest: mol-deacon-patrol

Patrol 16: healthy


Digest: mol-deacon-patrol

Patrol 7: All healthy, no messages


Digest: mol-deacon-patrol

Patrol 8: All healthy, no messages


Pick next branch. Rebase on current main.

```bash
git checkout -b temp origin/<polecat-branch>
git rebase origin/main
```

If rebase conflicts and unresolvable:
- git rebase --abort
- Notify polecat to fix and resubmit
- Skip to loop-check for next branch

instantiated_from: mol-refinery-patrol
step: process-branch


Implement git merge logic in Engineer.ProcessMR

The Engineer module in internal/refinery/engineer.go has stub implementations for ProcessMR() and ProcessMRFromQueue() that need actual git merge logic.

## Current State
- ProcessMR() logs intent but returns failure
- ProcessMRFromQueue() same - logs and returns failure
- handleSuccess() and handleFailure() are implemented

## Required Implementation
1. **Fetch source branch**: git fetch origin <branch>
2. **Conflict check**: git merge --no-commit --no-ff to test
3. **Run tests** if configured (config.RunTests, config.TestCommand)
4. **Perform merge**: git merge with appropriate commit message
5. **Push to origin**: git push origin <target>
6. **Handle failures**: conflicts, test failures, push failures

## Context
- There are 28+ pending merge-request issues waiting for this
- Infrastructure (config, result types, success/failure handlers) is ready
- Just needs the core git operations

## Files
- internal/refinery/engineer.go - ProcessMR(), ProcessMRFromQueue()
- internal/git/git.go - may need Merge(), Fetch() methods


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 785/1023)


Digest: mol-deacon-patrol

Patrol cycle 28: All healthy, no incidents


Work on gt-fix-bugs: Fix blocking infrastructure bugs. Se...

Work on gt-fix-bugs: Fix blocking infrastructure bugs. See issue for details. Run 'bd show gt-fix-bugs' to see the full issue.


bd formula list/show commands

Implement formula management commands:

  bd formula list
  # Lists formulas from all search paths

  bd formula show rule-of-five
  # Shows formula details, steps, compose rules

Search paths (in order):
1. .beads/formulas/ (project)
2. ~/gt/.beads/formulas/ (town)
3. ~/.beads/formulas/ (user)
4. Built-in formulas (embedded)


Digest: mol-deacon-patrol

Patrol cycle 2: all healthy


mol-deacon-patrol


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 147/1023)


Cross-project dependency workflow (Gas Town side)

Gas Town integration for cross-project dependencies.

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

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

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

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


Replace WaitForClaudeReady with gt peek for steady-state agent observation

## Problem

WaitForClaudeReady uses regex to detect Claude's prompt, which is a ZFC violation.

## Architectural Fix

**Bootstrap (ZFC violation acceptable):**
During cold town startup, no AI is available. Regex to get Deacon online is acceptable.

**Steady State (proper ZFC):**
Once any agent is running, AI should observe AI:
- Deacon starting polecats → Deacon uses gt peek
- Deacon restarting → Mayor watches via gt peek
- Mayor restarting → Deacon watches via gt peek

## Implementation

1. Keep WaitForClaudeReady for daemon bootstrap only
2. Update gt deacon trigger-pending to use gt peek
3. Document bootstrap vs steady-state distinction


Swarm completion detection and auto-close

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 257 complete: no incidents


Digest: mol-deacon-patrol

Patrol cycle 11: All healthy.


Improve test coverage in low-coverage packages

Several packages have low test coverage:
- internal/cmd: 6.8%
- internal/mail: 3.6%
- internal/daemon: 12.1%
- internal/doctor: 14.5%
- internal/refinery: 20.6%
- internal/session: 27.8%
- internal/git: 28.8%

Priority should be given to mail, cmd, and daemon packages which handle critical functionality.


Digest: mol-deacon-patrol

Patrol 9: All healthy


Digest: mol-deacon-patrol

Patrol cycle 63: All healthy


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

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


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 975/1023)


test pin fix 2


Digest: mol-deacon-patrol

Quick patrol: no messages, all healthy


Digest: mol-deacon-patrol

Patrol 16: All healthy.


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 250/1023)


Add molecules.jsonl as separate catalog file for template molecules


Polecat Lifecycle Events: Refinery-Witness Coordination

## Problem

Polecat work completion is currently treated as a single event (MR submission), but the true completion is when the Refinery merges the work. This creates a lifecycle gap:

1. Polecat submits MR → considered "done" by Witness
2. But MR might fail to merge (conflicts, test failures)
3. No one notifies anyone when merge actually succeeds

## Solution: Two-Event Lifecycle

**Event 1: MR Submitted**
- `gt mq submit` notifies Witness
- Witness verifies submission was clean
- Polecat can go idle (but worktree retained)
- If submission had issues, Witness can help

**Event 2: MR Merged**
- Refinery sends `LIFECYCLE: work merged` to Witness
- Witness updates polecat state to `merged`
- Worktree now eligible for full cleanup/recycling

## Village Sibling Watch

For robustness, patrol roles check on their siblings:
- Refinery checks Witness via `gt peek`
- Witness checks Refinery via `gt peek`
- Creates defense in depth - if primary notification fails, someone catches it

## Recovery

If Refinery misses sending lifecycle notification:
- Witness polecat-scan can detect: polecat in mr_submitted but MR shows merged
- Deacon orphan-check can detect: merged MRs with stale polecats


Implement context-checking for agent sessions

Implement the context-checking step that allows agents to assess their remaining context capacity.

## Challenge

Agents don't have direct access to token counts. Need heuristics:

### Approach 1: Message count heuristic
- Count messages in conversation
- Estimate tokens per message
- Compare to model's context window

### Approach 2: External tool
- Claude Code could expose a /context command
- Returns estimated usage percentage
- Agent queries before each work item

### Approach 3: Conservative fixed limits
- After N work items, always handoff
- Simple but may waste context or handoff too early

### Approach 4: Hook-based injection
- SessionStart hook injects context estimate
- Updated periodically via tool call

## Recommendation

Start with Approach 3 (fixed limits) as MVP:
- Default: 3-5 work items per session
- Agent can override via variable
- Upgrade to smarter heuristics later

## Integration

- Add check-context step to mol-ready-work
- Implement handoff trigger logic
- Test with various context states


Digest: mol-deacon-patrol

Patrol 11: all healthy


CI: GitHub Actions workflow for integration tests

Set up CI to run integration tests:

## Requirements
- Run on PRs touching: internal/cmd/install.go, internal/cmd/rig.go, internal/config/
- Use build tag: //go:build integration
- Timeout: 5 minutes max
- Cache Go modules

## Workflow structure
```yaml
name: Integration Tests
on:
  pull_request:
    paths:
      - 'internal/cmd/install.go'
      - 'internal/cmd/rig.go'
      - 'internal/config/**'
      - 'internal/routing/**'
jobs:
  integration:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
      - run: go test -tags=integration ./...
```


Digest: mol-deacon-patrol

Patrol 19: healthy


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


Digest: mol-deacon-patrol

Patrol 20: All healthy, routine cycle complete


Add bulk polecat remove command (gt polecat remove --all)

When decommissioning a rig, need to remove multiple polecats one at a time. A --all or --rig flag would allow: gt polecat remove --rig gastown --force


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 115/1023)


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Fetch and conflict check: git operations for MR

Implement git operations for MR processing.

Steps:
1. git fetch origin <mr.branch>
2. git checkout <mr.target> (main or integration/xxx)
3. git merge --no-commit --no-ff <mr.branch> (test merge)
4. Check for conflicts
5. If conflicts: abort and return Failure(conflict, files)
6. If clean: abort (actual merge in next step)

Helper functions:
- FetchBranch(branch string) error
- CheckConflicts(source, target string) ([]string, error)

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


Digest: mol-deacon-patrol

Patrol OK: 0 mail, all agents healthy, 3 polecats working


MessagingConfig: Add Type field for schema consistency

MessagingConfig lacks a Type field that other config types have (TownConfig has 'town', RigConfig has 'rig', etc). Add Type: 'messaging' for consistency.


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 265/1023)


Move disk 3: A → B

Move disk 3 from peg A to peg B. (Move 892/1023)


Merge: gt-rana.2

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


Merge: gt-g44u.3

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


Liftoff test: Add timestamp comment to manager.go

Simple liftoff test task.

Add a comment at the top of internal/polecat/manager.go with the current timestamp, like:
// Liftoff test: <timestamp>

This tests the full polecat → refinery → witness cycle.


Digest: mol-deacon-patrol

Patrol 1: 3 rigs healthy, no incidents


Move disk 7: A → B

Move disk 7 from peg A to peg B. (Move 832/1023)


Digest: mol-deacon-patrol

Patrol cycle 7: All healthy.


Test Patrol for Bonding

Parent issue for mol bond CLI test


Digest: mol-deacon-patrol

Patrol 9: Quiet


Digest: mol-deacon-patrol

Patrol 15: all clear


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 305/1023)


Digest: mol-deacon-patrol

Patrol 23: Quick cycle, no changes. All agents healthy.


Digest: mol-deacon-patrol

Patrol 6


Task A: Setup foundation


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


Digest: mol-deacon-patrol

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


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 903/1023)


Digest: mol-deacon-patrol

Patrol 7: All healthy


Digest: mol-deacon-patrol

Patrol 33: all quiet


Nudge newly spawned polecats


Merge: coma-mjwjczb0

branch: polecat/coma-mjwjczb0
target: main
source_issue: coma-mjwjczb0
rig: gastown
agent_bead: gt-gastown-polecat-coma


Move disk 4: A → C

Move disk 4 from peg A to peg C. (Move 296/1023)


Merge: furiosa-1767079892643

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


gt sling: nudge witness+refinery when dispatching to polecat

When gt sling dispatches work to a polecat, wake the rig's witness and refinery.

## Boot+Nudge Pattern

```go
// After successful polecat dispatch
func wakeRigAgents(rig string) {
    // Level 2: Start if asleep
    exec.Command("gt", "rig", "boot", rig).Run()

    // Level 1: Clear backoff if running
    t := tmux.NewTmux()
    t.NudgeSession(fmt.Sprintf("gt-%s-witness", rig), "wake")
    t.NudgeSession(fmt.Sprintf("gt-%s-refinery", rig), "wake")
}
```

## Graceful Behavior

- `gt rig boot` is idempotent (no-op if already running)
- Nudge failures are silent (session might not exist yet)
- Agents discover what happened by checking reality

## Reference

See ~/gt/docs/patrol-system-design.md (Two-Level Wake section)


Find abandoned work

Find abandoned work.

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

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

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


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 61/1023)


gt mail reply: Reply to messages

Add `gt mail reply` command.

```
gt mail reply <id> -m BODY
gt mail reply <id>  # opens editor
```

- Auto-set To: from original sender
- Auto-set Subject: 'Re: <original subject>'
- Set reply_to field to original message ID
- Set thread_id to track conversation

**Implementation:**
- Add `replyCmd` to internal/cmd/mail.go
- Look up original message, extract sender/subject
- Use existing send infrastructure with reply metadata

**Note:** This enables threaded conversations for agent coordination.


Check own context limit

Check own context limit.

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

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

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

This enables the Deacon to burn and respawn cleanly.


Digest: mol-deacon-patrol

Patrol complete: all healthy


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 454/1023)


Move disk 2: C → B

Move disk 2 from peg C to peg B. (Move 150/1023)


BUG: Cross-beads slot references silently fail

When slinging work from town beads (hq-*) to a polecat whose agent bead is in rig beads (gt-*), the hook_bead update silently fails.

**Reproduction:**
```
# From mayor (town root):
gt sling hq-oosxt gastown/polecats/nux

# This runs (in updateAgentHookBead):
bd slot set gt-gastown-polecat-nux hook hq-oosxt
# FAILS: can't find hq-oosxt (different beads directory)
# Error is silently ignored!
```

**Result:**
- Agent bead keeps stale hook_bead value
- gt hook shows wrong/old work
- Agent doesn't know what they're actually assigned

**Root cause:**
sling.go line 812-814 silently ignores UpdateAgentState errors:
```go
if err := bd.UpdateAgentState(agentBeadID, "running", &beadID); err != nil {
    // Silently ignore - agent bead might not exist yet
    return
}
```

**Fix options:**
1. Log warnings instead of silent ignore
2. Support cross-beads slot references (store as 'hq-oosxt@town' or similar)
3. Use external: prefix for cross-beads hooks
4. Always store hook in the WORK bead's directory, not agent bead

Discovered during investigation of stale hook issue.


Digest: mol-deacon-patrol

P14: stable


Move disk 5: B → C

Move disk 5 from peg B to peg C. (Move 336/1023)


Update rig init to create refinery as worktree

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

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

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


Better error messages when bd daemon fails to start

Surface the actual error (e.g. 'legacy database detected'). Provide one-liner fix command. Currently fails silently.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Digest: mol-deacon-patrol

Patrol #2: Quick cycle, all witnesses running. No messages.


Mol Mall: Formula Package Registry

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

## Concept

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

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

## Resolution Hierarchy

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

## Package Manifest

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

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

## Distribution Scenarios

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

## Open Questions

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

## Related

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


mol-deacon-patrol


Move disk 7: A → B

Move disk 7 from peg A to peg B. (Move 64/1023)


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.


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 65/1023)


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 849/1023)


ZFC #9: Explicit MR registration instead of branch parsing

**ZFC Violation:** internal/refinery/manager.go:346-370

Go infers work metadata from branch naming conventions:
```go
pattern := regexp.MustCompile(`^polecat/([^/]+)(?:/(.+))?$`)
worker := matches[1]
issueID = matches[2]
```

**ZFC-compliant solution:**
Polecats register MRs with explicit structured data:
- `gt mq submit --worker=nux --issue=gt-xyz --branch=polecat/nux/gt-xyz`
- Creates MR bead with explicit fields
- No regex parsing of branch names

**Benefits:**
- Work metadata is explicit, not inferred
- Branch naming can evolve without breaking refinery
- Audit trail in beads

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


Digest: mol-deacon-patrol

Patrol 12


Digest: mol-deacon-patrol

Patrol 12: All agents healthy


Merge: slit-mjw3n5iw

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


Digest: mol-deacon-patrol

Patrol cycle 52: All healthy


Verify initial state

All 3 disks stacked on peg A. Largest on bottom.


gt swarm status fails to find issues via rig discovery

gt swarm status gt-1tpts fails with 'issue not found' but bd swarm status gt-1tpts works. The rig discovery in getAllRigs() may not be finding rigs correctly, or the bd commands are running from wrong directory.


Digest: mol-deacon-patrol

Patrol 4: 9 sessions healthy


Move disk 4: C → B

Move disk 4 from peg C to peg B. (Move 504/1023)


Digest: mol-deacon-patrol

Patrol complete: No callbacks, no gates, witness/refinery healthy, no orphans, clean cycle


Digest: mol-deacon-patrol

P19: stable


Support numeric shortcuts in mail read (e.g., 'mail read 1')

When inbox shows numbered messages like:
* 1. gm-19b29031...  2025-12-16  mayor  Subject...
* 2. gm-19b26d51...  2025-12-16         Subject...

Users should be able to run 'gt mail read 1' instead of needing the full message ID 'gt mail read gm-19b29031f6a172206'.

Implementation:
- Track inbox message order in display
- Map numeric indices to actual message IDs
- Accept both numeric shortcuts and full IDs in 'mail read' command


Move disk 1: C → B

Move disk 1 from peg C to peg B.


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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 2: Quick pass, all healthy


Digest: mol-deacon-patrol

Patrol 74: Routine


Hook reading in gt prime

Enhance gt prime to check and display hook contents.

## Current Behavior

gt prime loads context:
- Reads CLAUDE.md
- Injects beads workflow info
- Shows status

## New Behavior

After loading context, check hook:

```go
// In prime.go
func checkHook(agent string) {
    wispPath := ".beads-wisp/hook-" + agent + ".wisp.yaml"
    if wisp := readWisp(wispPath); wisp != nil {
        // Inject hook info into prime output
        showSlungWork(wisp)
    }
}
```

## Output Format

When hook has slung work:

```markdown
## Your Hook

You have work assigned:

**Bead:** gt-xxx
**Title:** Fix authentication bug
**Priority:** P1

Context from previous session:
> Continue where I left off...

**BEGIN WORK NOW.** Claim it with:
  bd update gt-xxx --status=in_progress
```

## Files Modified

- cmd/gt/prime.go - Add hook checking
- internal/wisp/hook.go - Hook reading utilities


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 2/1023)


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 309/1023)


Code review: await-signal command (gt-vdprb.1)

Review the await-signal molecule step implementation in internal/cmd/molecule_await_signal.go


Map expansion should match nested child steps


GGT vs PGT Gap Analysis Summary

Summary of gaps comparing GGT (~4,500 LOC) to PGT (~27,700 LOC).

## Critical Gaps (P1) - Existing Issues
- gt-u1j.17: Polecat CLI (add, list, wake, sleep) - DETAILED
- gt-u1j.16: Rig CLI (add, list, show, remove) - DETAILED
- gt-u1j.18: Witness CLI (start, stop, status) - DETAILED
- gt-f9x.4: Doctor framework - DETAILED
- gt-f9x.5: Workspace doctor checks - DETAILED
- gt-f9x.6: Rig doctor checks - DETAILED

## Critical Gaps (P1) - New Issues
- gt-a95: Refinery background daemon mode - ENHANCED
- gt-hgk: Mail message types and threading - ENHANCED

## Significant Gaps (P2) - New Issues
- gt-d46: Mail CLI archive/purge/search - ENHANCED
- gt-e9k: Swarm preflight/postflight - ENHANCED
- gt-662: Swarm report generation - ENHANCED
- gt-69l: Hook system - ENHANCED
- gt-3yj: Agent monitoring - ENHANCED
- gt-1ky: Workspace CLI (may overlap f9x.3) - ENHANCED
- gt-9j9: Worker status reporting - ENHANCED
- gt-qao: Mayor CLI - ENHANCED
- gt-7o7: Session pre-shutdown checks - ENHANCED
- gt-c92: Batch all command - ENHANCED
- gt-lno: Swarm state persistence - ENHANCED
- gt-a9y: File locking - ENHANCED
- gt-30o: Error handling improvements - ENHANCED

## Significant Gaps (P2) - Existing Issues
- gt-kmn.12: Ephemeral rig support - DETAILED

## Lower Priority (P3) - New Issues
- gt-3fm: Mail orchestrator daemon - ENHANCED
- gt-2kz: Cleanup commands - ENHANCED
- gt-ebl: Names commands - ENHANCED
- gt-1u9: Interactive prompts - ENHANCED
- gt-8lz: Help text improvements - ENHANCED

## Closed as Duplicates
- gt-3tz → gt-u1j.17 (polecat CLI)
- gt-e1r → gt-u1j.16 (rig CLI)
- gt-86w → gt-f9x.4/5/6 (doctor)
- gt-alx → gt-kmn.12 (ephemeral rigs)

## Execution Order Recommendation
1. P1 CLI commands (existing detailed issues ready to implement)
2. gt-a95: Refinery daemon (blocks autonomous operation)
3. gt-7o7: Pre-shutdown checks (prevents data loss)
4. gt-a9y: File locking (prevents corruption)
5. gt-hgk + gt-d46: Mail improvements
6. gt-69l: Hook system (enables extensibility)
7. Remaining P2s in any order
8. P3s as time permits


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 636/1023)


Merge: furiosa-mjw1p03l

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


Digest: mol-deacon-patrol

Patrol 124: All healthy, 2 new polecats


Move disk 3: A → B

Move disk 3 from peg A to peg B. (Move 1012/1023)


Mail inbox from witness/refinery dirs shows Mayor inbox

When running `gt mail inbox` from the witness or refinery directories, it shows the Mayor's inbox instead of the agent's own inbox.

Reproduction:
```
$ cd ~/gt/beads/witness && gt mail inbox
📬 Inbox: mayor/ (1 messages, 1 unread)
  ● 🤝 HANDOFF: Swarm session complete...
```

Expected: Should show beads/witness inbox

Likely cause: The cwd-based identity resolution isn't recognizing witness/refinery as valid mail identities, so it falls back to Mayor.


Digest: mol-deacon-patrol

Patrol cycle 72: All healthy


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 609/1023)


Molecule CLI: bd molecule commands

Add molecule commands to bd:

## Commands

```bash
bd molecule list              # List molecules (type: molecule)
bd molecule show <id>         # Show molecule with parsed steps
bd molecule parse <id>        # Validate and show parsed structure
bd molecule instantiate <mol-id> --parent=<issue-id>  # Create steps
bd molecule instances <mol-id>  # Show all instantiations
```

## gt spawn integration

```bash
gt spawn --issue <id> --molecule <mol-id>
```

This should:
1. Call `bd molecule instantiate` (creates child beads atomically)
2. Spawn polecat on first ready step
3. Polecat grinds through via `bd ready`

## Output Examples

```
$ bd molecule show mol-abc

mol-abc: Engineer in a Box
Type: molecule

Steps (5):
  design      → (ready first)
  implement   → Needs: design
  review      → Needs: implement
  test        → Needs: implement
  submit      → Needs: review, test

Instances: 3
```

```
$ bd molecule instances mol-abc

Parent          Status    Created
gt-xyz          done      2025-12-15
gt-abc          active    2025-12-17 (3/5 complete)
gt-def          pending   2025-12-18
```


Digest: mol-deacon-patrol

Cycle 190: 10-cycle checkpoint, all agents healthy


Digest: mol-deacon-patrol

Patrol 147: All healthy, 2 polecats working


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 427/1023)


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 554/1023)


Digest: mol-deacon-patrol

Patrol cycle 10: all healthy


Digest: mol-deacon-patrol

Patrol 8: All healthy


gt-gastown-polecat-splendid

gt-gastown-polecat-splendid

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: gt-zqt4d
role_bead: gt-polecat-role
cleanup_status: null
active_mr: gt-rbjo3
notification_level: null


Polecat identity confusion leads to direct main commits

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

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

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

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


Check own context limit

Check own context limit.

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

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

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

This enables the Deacon to burn and respawn cleanly.


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

Session management CLI commands.

## Commands

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

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

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

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

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

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

## Address Format

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

## Implementation

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


Digest: mol-deacon-patrol

Patrol 145: All healthy


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

GGT needs rig management commands.

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

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

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


Digest: mol-deacon-patrol

Patrol 93: All healthy


attached_args: Extract molecule_lifecycle boilerplate

Extract duplicate boilerplate in molecule_lifecycle.go.

## Files to modify
- internal/cmd/molecule_lifecycle.go

## Current duplication
runMoleculeBurn (lines 17-53) and runMoleculeSquash (lines 121-165) share ~50 lines of identical target detection code:
- Get cwd
- Find workspace
- Parse target argument
- Determine rig from address or role

## Implementation
Extract helper function:
```go
type AgentContext struct {
    TownRoot string
    RigName  string
    Role     string
    Target   string  // polecat name or crew name
}

func getTargetAgentContext(args []string) (*AgentContext, error) {
    cwd, err := os.Getwd()
    if err != nil {
        return nil, fmt.Errorf("getting current directory: %w", err)
    }
    townRoot, err := workspace.FindFromCwd()
    if err != nil {
        return nil, fmt.Errorf("finding workspace: %w", err)
    }
    if townRoot == "" {
        return nil, fmt.Errorf("not in a Gas Town workspace")
    }
    // ... rest of target detection logic ...
}
```

## Acceptance criteria
- [ ] AgentContext struct defined
- [ ] getTargetAgentContext function extracts shared logic
- [ ] runMoleculeBurn uses getTargetAgentContext
- [ ] runMoleculeSquash uses getTargetAgentContext
- [ ] Duplicate code eliminated (diff shows net negative lines)
- [ ] go build ./... passes
- [ ] go test ./internal/cmd/... passes


Move disk 2: C → B

Move disk 2 from peg C to peg B. (Move 234/1023)


Digest: mol-deacon-patrol

Patrol 3: Routine. All healthy.


Digest: mol-deacon-patrol

Patrol 2: All clear


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 946/1023)


Digest: mol-deacon-patrol

Patrol 2: No callbacks, 2 convoys in progress, all agents healthy


Merge: dementus-mjxaqvb9

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


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 817/1023)


Move disk 4: A → C

Move disk 4 from peg A to peg C. (Move 536/1023)


Consolidate design docs into beads descriptions

The markdown design docs (swarm-shutdown-design.md, polecat-beads-access-design.md, mayor-handoff-design.md) will decay. Extract key decisions and prompting templates into the beads descriptions themselves, then archive or remove the markdown files. Beads are the source of truth.


Digest: mol-witness-patrol

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


Phase 5: Integration and Demo

$(cat /tmp/phase5.md)


Digest: mol-deacon-patrol

Patrol 12: all clear


Move disk 3: C → A

Move disk 3 from peg C to peg A. (Move 236/1023)


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


mol-deacon-patrol


Day 1.1: Add type=agent to bead schema

Add agent as a valid bead type in the schema. This is the foundation for agent-as-bead.

Parent: gt-d0jqp

Re-opened: Close reason referenced non-existent commit 927e8374. Type=agent not yet implemented in bd CLI.


Add Boot shutdown to gt shutdown

gt shutdown should stop Boot if running. Currently Boot is only spawned by daemon but never explicitly stopped.


Digest: mol-deacon-patrol

Patrol 55: All healthy


Move disk 2: C → B

Move disk 2 from peg C to peg B. (Move 582/1023)


Merge: nux-1767073376184

attached_args: Code review this merge request

branch: polecat/nux-1767073376184
target: main
source_issue: nux-1767073376184
rig: gastown


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

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


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 239/1023)


Merge: nux-mjtj9d8q

branch: polecat/nux-mjtj9d8q
target: main
source_issue: nux-mjtj9d8q
rig: gastown


Digest: mol-deacon-patrol

Patrol 9: All healthy.


Validate rig names to reject hyphens and special characters

GHI #23: Add validation in Manager.AddRig() to reject rig names with hyphens (and other special chars) that break agent ID parsing.

**Problem**: Agent IDs use format `<prefix>-<rig>-<role>[-<name>]` with hyphens as delimiters. Hyphenated rig names like `op-baby` cause parsing failures.

**Fix location**: internal/rig/manager.go:172 (AddRig function)

**Implementation**:
1. Add validation after RigExists check (~line 173)
2. Reject names containing: hyphens, spaces, dots
3. Suggest sanitized alternative in error message

Example:
```go
if strings.Contains(opts.Name, "-") {
    return nil, fmt.Errorf("rig name %q contains hyphens which break agent ID parsing; use %q instead",
        opts.Name, strings.ReplaceAll(opts.Name, "-", ""))
}
```

Ref: https://github.com/steveyegge/gastown/issues/23


Deacon Role Definition

You are the Deacon - the town-level lifecycle manager.

You run patrol cycles checking the health of all agents across all rigs,
nudging stuck workers, and managing session lifecycles.

session_pattern: gt-deacon
work_dir_pattern: {town}
needs_pre_sync: false
start_command: exec claude --dangerously-skip-permissions

default_molecule: mol-deacon-patrol
capabilities:
  - health_monitoring
  - session_lifecycle
  - cross_rig_visibility
  - agent_nudging

## Core Responsibilities

1. Run patrol cycles across all rigs
2. Monitor agent health and progress
3. Nudge stuck agents
4. Manage session lifecycles (kill/restart)
5. Escalate systemic issues to Mayor

## Patrol Cycle

Each patrol:
1. Check all agent sessions (gt status)
2. Identify stuck or idle agents
3. Nudge or restart as needed
4. Log patrol results
5. Sleep until next cycle

## Propulsion Principle

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

Your work is the mol-deacon-patrol wisp. Execute patrol steps continuously.

## Commands

- gt status - Check all agents
- tmux kill-session -t <session> - Kill stuck session
- gt mail send <addr> - Communicate with agents
- gt mail send mayor/ - Escalate to Mayor

## Session Cycling

When context fills, hand off to fresh session:
gt handoff -s "Deacon patrol handoff" -m "Completed N cycles..."


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 639/1023)


Digest: mol-deacon-patrol

Patrol cycle 2: Witnessed escalation re: 14 polecats with unpushed work. All agents healthy. No pending work.


Formula inheritance trees for organizational policies

Support organizational formula hierarchies where teams extend a company-base-formula. Each team can add required aspects (accessibility audit for frontend, SQL injection scan for backend). Enables policy enforcement across an organization.


Digest: mol-deacon-patrol

Patrol 1: all healthy, 17 sessions, 3 rigs online


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 363/1023)


Merge: gt-ci84

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


Digest: mol-deacon-patrol

Patrol complete: inbox empty, polecats healthy (furiosa/nux idle), witness/refinery running, no orphans


Merge: gt-oiv0

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


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 298/1023)


Digest: mol-deacon-patrol

Patrol cycle 16: All 6 agents healthy


Digest: mol-deacon-patrol

Patrol 15


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 706/1023)


Digest: mol-deacon-patrol

Patrol #11: Stable


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 660/1023)


Digest: mol-deacon-patrol

Patrol 8: All agents healthy


Digest: mol-deacon-patrol

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


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


Design: Additional design issues (placeholder)

Placeholder for additional design issues the user wants to raise and work through. Convert to specific subtasks as issues are identified.


Merge: dementus-1767073385126

attached_args: Code review this merge request

branch: polecat/dementus-1767073385126
target: main
source_issue: dementus-1767073385126
rig: gastown


Digest: mol-deacon-patrol

Patrol 14


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 945/1023)


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

role_type: crew
rig: gastown
agent_state: running
hook_bead: gt-7aw1m
role_bead: gt-crew-role
cleanup_status: null


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Merge: gt-3x1.5

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


Digest: mol-deacon-patrol

Cycle 15


Merge: gt-83k0

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


gt crew list: List crew workspaces

Implement 'gt crew list [--rig <rig>]' command:
- List all crew workers in rig(s)
- Show status (session running, last activity)
- Show current branch and git status summary
- Support --json output


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 758/1023)


Create internal/tui/ package with feed model

Create the TUI infrastructure for gt feed.

## Package structure
```
internal/tui/
  feed/
    model.go       # bubbletea Model struct
    view.go        # View() rendering
    update.go      # Update() message handling
    events.go      # Event stream subscription (tail .feed.jsonl)
    styles.go      # lipgloss styles
    keys.go        # Key bindings
```

## Model components
1. **AgentTree** - Collapsible tree of agents by role
2. **EventStream** - Scrollable viewport of recent events
3. **StatusBar** - Current filter, help hints
4. **FilterPopup** - Modal for setting filters

## Key bindings
- j/k - scroll events
- J/K - scroll agent tree
- tab - switch focus (tree/stream)
- enter - expand/details
- / - search
- f - filter popup
- q - quit
- ? - help

## Event subscription
- Tail ~/gt/.feed.jsonl using fsnotify or polling
- Parse JSONL events
- Send as bubbletea messages to update model


gt mail archive/purge: Archive management

Add `gt mail archive` and `gt mail purge` commands.

### gt mail archive
```
gt mail archive [--older-than DAYS] [--all-read] [--dry-run]
```
- Move messages from inbox.jsonl to archive.jsonl
- Default: archive read messages older than 7 days

### gt mail purge
```
gt mail purge [--older-than DAYS] [--dry-run] [--force]
```
- Permanently delete from archive.jsonl
- Confirm unless --force

**Implementation:**
- Add to internal/cmd/mail.go
- Add Archive(), Purge() to internal/mail/mailbox.go
- Create archive.jsonl in same directory as inbox.jsonl


Execute registered plugins

Execute registered plugins.

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

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

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

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

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

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


Epic: Async Gates for Agent Coordination

## Summary

Agents need an async primitive for waiting on external events (CI completion,
API responses, human approval). Currently they either poll wastefully or cant
resume after handoff.

## Design: Deacon-Managed Gates

### Core Concepts

**Gate** = wisp issue that blocks until external condition is met
- Type: `gate`
- Phase: wisp (never synced, ephemeral)
- Assignee: `deacon/` (Deacon monitors it)
- Fields: `await_type`, `await_id`, `timeout`, `waiters[]`

**Await Types:**
- `gh:run:<id>` - GitHub Actions run completion
- `gh:pr:<id>` - PR merged/closed
- `timer:<duration>` - Simple delay (e.g., "5m", "1h")
- `human:<prompt>` - Human approval required
- `mail:<pattern>` - Wait for mail matching pattern

### Commands

```bash
bd gate create --await <type>:<id> --timeout <duration> --notify <addr>
bd gate show <id>
bd gate list
bd gate close <id> --reason "completed"
bd gate wait <id> --notify <addr>
```

## Children (suggested breakdown)

1. Add `gate` issue type to beads
2. Add gate fields: await_type, await_id, timeout, waiters
3. Implement `bd gate create/show/list/close/wait` commands
4. Add gate checking to Deacon patrol loop
5. Implement await type handlers (gh:run, gh:pr, timer, human, mail)
6. Add gate timeout tracking and notification
7. Integration test: agent waits for CI via gate

## Open Questions

- Should gates live in wisp storage or main storage with wisp flag?
- Do we need a gate catalog (like molecule catalog)?
- Should `waits-for` dep type work with gates?


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


Beads witness sends HEALTH_OK to mayor instead of deacon

The beads/witness is responding to deacon health checks by sending to 'mayor/deacon' or 'mayor/' instead of 'deacon/'.

Current behavior:
gt mail send mayor/deacon -s "HEALTH_OK" ...

Expected behavior:
gt mail send deacon/ -s "HEALTH_OK" ...

The gastown witness was fixed and now correctly sends to deacon/. The beads witness needs the same fix.


Digest: mol-deacon-patrol

Patrol cycle 69: All healthy


Digest: mol-deacon-patrol

Patrol 10: all healthy


gt spawn should create fresh polecat worktree, never reuse

Currently gt spawn tries to reuse existing polecats, which causes:

1. Stale beads database
2. Stale code (behind main/integration)
3. Old inbox messages
4. Git history pollution

## Current Behavior

gt spawn:
1. Looks for idle polecat in pool
2. If found, reuses existing worktree
3. Assigns new issue

## Desired Behavior

gt spawn:
1. Always create FRESH polecat from current main/integration
2. Fresh worktree with clean beads
3. No reuse of old worktrees

## Name Pool Still Useful

Keep name pool for:
- Allocating themed names (mad-max, etc.)
- Tracking which names are in use

But worktrees should be created fresh each time.

## Implementation

In spawn.go, before starting work:
1. If worktree exists: remove it first
2. Create fresh worktree from integration branch
3. Sync beads from rig to polecat
4. Then proceed with work assignment

This ensures polecats always start with latest code and beads.


mol-sync-workspace: Split handle-dirty-state into focused steps


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 353/1023)


Digest: mol-deacon-patrol

P11: stable


Dogs: Deacon's Helper Workers

## Overview

Dogs are reusable workers managed by the Deacon for infrastructure and cleanup tasks.
They parallel how Polecats serve the Witness, but at town level with cross-rig scope.

## Key Concepts

- **Dogs**: Deacon-managed, reusable, infrastructure/cleanup tasks
- **Kennel**: Where dogs live (`deacon/dogs/`)
- **Multi-rig worktrees**: Dogs have worktrees into multiple rigs for cross-rig work

## Cats vs Dogs

| Aspect | Polecats | Dogs |
|--------|----------|------|
| Manager | Witness | Deacon |
| Scope | Per-rig | Town (cross-rig) |
| Lifecycle | Ephemeral | Reusable |
| Work | Features | Infrastructure |
| Location | `<rig>/polecats/` | `deacon/dogs/` |

## Implementation

### Phase 1: Dog Infrastructure
- `gt dog add/remove/list/call/status` commands
- Kennel directory structure (`~/gt/deacon/dogs/`)
- Multi-rig worktree creation
- Dog state tracking

### Phase 2: Deacon Dispatch
- Sling support for `deacon/dogs` target
- Pool management (spawn/retire logic)
- Completion mail handling

### Phase 3: Infrastructure Formulas
- mol-convoy-cleanup
- mol-dep-propagate
- mol-digest-generate

### Phase 4: Deacon Refactor
- Patrol becomes detect → dispatch
- Heavy work moves to dog slings

## Reference

- docs/patrol-system-design.md#dogs-deacons-helper-workers
- docs/PRIMING.md (Role Taxonomy)


Digest: mol-deacon-patrol

Patrol 48: All healthy


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Idle Town Principle

**The Deacon should be silent/invisible when the town is healthy and idle.**

- Skip HEALTH_CHECK nudges when no active work exists
- Sleep 60+ seconds between patrol cycles (longer when idle)
- Let the feed subscription wake agents on actual events
- The daemon (10-minute heartbeat) is the safety net for dead sessions

This prevents flooding idle agents with health checks every few seconds.

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Digest: mol-deacon-patrol

Patrol 11: quick pass


gt-gastown-polecat-eli

gt-gastown-polecat-eli

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: null
role_bead: gt-polecat-role
cleanup_status: has_uncommitted


Digest: mol-deacon-patrol

Patrol cycle 11: all healthy


Merge: warboy-1767106060799

branch: polecat/warboy-1767106060799
target: main
source_issue: warboy-1767106060799
rig: gastown


gt-gastown-polecat-bix

gt-gastown-polecat-bix

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


Digest: mol-deacon-patrol

Patrol 96: All healthy


Day 2.3: Agent writes state on lifecycle events

Agents update their bead state using bd agent state command:
- On startup: bd agent state gt-<role> running
- On shutdown: bd agent state gt-<role> stopped
- On stuck: bd agent state gt-<role> stuck

State is self-reported, not inferred.

Implementation: Wire up agent lifecycle hooks (SessionStart, SessionEnd, health checks) to call bd agent state.

Parent: gt-d0jqp


Nudge newly spawned polecats

Nudge newly spawned polecats that are ready for input.

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

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

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

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol cycle 7: All agents healthy


Digest: mol-deacon-patrol

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


Digest: mol-deacon-patrol

Patrol #15: Stable


Digest: mol-deacon-patrol

Patrol 9: Refineries healthy


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 681/1023)


Critical packages lack test coverage

Several packages have no test files:
- internal/lock/ - Core identity locking (212 lines UNTESTED)
- internal/witness/ - Worker monitoring
- internal/mrqueue/ - MR queue management
- internal/claude/ - Claude integration
- internal/style/ - Terminal styling
- internal/constants/ - Constants

Priority for testing:
1. lock/ - prevents duplicate agents, critical for correctness
2. witness/ - agent lifecycle management
3. mrqueue/ - merge request processing

Overall: 37 test files for 160 Go files (23% by file count)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 359/1023)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 283/1023)


Define mol-gastown-boot proto structure

Create the proto molecule definition with all steps.

## Proto Definition

Each step has:
- Title (step name)
- Description with Action/Verify/OnStall/OnFail sections
- Dependencies (Needs: directive)

## Steps

1. ensure-daemon
   - Action: gt daemon status || gt daemon start
   - Verify: daemon PID exists and responding

2. ensure-deacon
   - Action: gt deacon start
   - Verify: session exists, not stalled, heartbeat fresh
   - OnStall: gt nudge deacon/ "Start patrol."

3. ensure-witnesses (parallel container)
   - ensure-gastown-witness
   - ensure-beads-witness
   - Verify each: session exists, not stalled

4. ensure-refineries (parallel container)
   - ensure-gastown-refinery
   - ensure-beads-refinery
   - Verify each: session exists, not stalled

5. verify-town-health
   - Action: gt status
   - Verify: all expected agents shown

## Output

Proto stored in beads as molecule type issue.


Test MR

branch: test-branch
target: main
source_issue: gt-test
rig: gastown


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 75/1023)


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 732/1023)


Digest: mol-deacon-patrol

Patrol 18: quick pass


Digest: mol-deacon-patrol

Patrol 10: all clear


gt doctor: Check and fix beads routing configuration

## Summary

`gt doctor` should check that all rigs with beads have proper routing entries
in `~/gt/.beads/routes.jsonl`, and offer to fix any missing entries.

## Checks to Add

### Check: routes.jsonl exists
- Verify `~/gt/.beads/routes.jsonl` exists
- If missing, create with entries for all known rigs

### Check: All rigs have routing entries
For each rig in town:
1. Find the rig's beads prefix (from config.yaml or sample issue)
2. Check if routes.jsonl has an entry for that prefix
3. If missing, report and offer to add

### Check: Routes point to valid locations
For each route in routes.jsonl:
1. Verify the path exists and has a .beads directory
2. Verify the .beads directory has a beads.db
3. If invalid, report and offer to remove

## Fix Actions

- `--fix` should automatically add missing routes
- `--fix` should remove invalid routes (or prompt)
- Should handle redirect files when validating paths

## Example Output

```
Checking beads routing...
  [!] Rig 'myproject' (prefix: mp-) has no routing entry
      Run: gt doctor --fix to add routing

Routes health:
  [OK] gt- -> gastown/mayor/rig
  [OK] bd- -> beads/mayor/rig
  [!]  mp- -> myproject/mayor/rig (MISSING)
```


Work on ga-xxp: Define mol-polecat-work standard molecule...

Work on ga-xxp: Define mol-polecat-work standard molecule. See bd show ga-xxp for full details.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Digest: mol-deacon-patrol

Patrol 20: final cycle complete, handoff time


Merge: furiosa-1767084006859

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


mol sling command: attach molecule to agent hook

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

## Behavior

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

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

## Difference from mol attach

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

## Output

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

## Implementation

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


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol 11: Quick cycle, all quiet


load-context

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

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


Add orphaned-attachments doctor check

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

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


Move disk 4: A → C

Move disk 4 from peg A to peg C. (Move 920/1023)


Merge: toast-mjw7062w

branch: polecat/toast-mjw7062w
target: main
source_issue: toast-mjw7062w
rig: gastown
agent_bead: gt-gastown-polecat-toast


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 194/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 263/1023)


Beads schema: Add overseer field for team scenarios

For future team support: overseer field identifies human owner when multiple humans share a workspace. For now, email in git commits serves this purpose. Low priority until teams needed.


Digest: mol-deacon-patrol

Patrol cycle 79: All healthy


Digest: mol-deacon-patrol

Patrol cycle 31: All healthy, no incidents


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 107/1023)


Remove 'spawn' terminology from molecular chemistry

Clean all docs and code to present ONLY current terminology. No migration paths, no "old vs new" tables, no deprecated flags. The codebase should read as if the current design was always the design.

**Terminology rules:**
- spawn = polecats/workers ONLY
- pour = create persistent mol
- wisp = create ephemeral wisp
- run = create and execute

**Scope:**
- Remove all "Old → New" migration tables
- Remove deprecated flag documentation (--persistent, etc.)
- Remove chemistry-design-changes.md entirely (it is a migration doc)
- Clean all docs to use current terminology only
- Rename spawn functions in code that deal with molecules


Digest: mol-deacon-patrol

Patrol 104: All agents healthy, no incidents


Errant redirect file in .beads/ causes chain warnings

A redirect file appeared in gastown/mayor/rig/.beads/ alongside the actual beads.db, causing 'redirect chains not allowed' warnings. The redirect pointed to ../../mayor/rig/.beads which is circular. Had to manually delete the redirect file.


Digest: mol-deacon-patrol

Patrol 13: Quick cycle, all quiet


Recovery: Detect orphaned merged polecats

Safety net for when Refinery misses sending lifecycle notification.

## Detection Points

**Witness polecat-scan**:
- For each polecat in `mr_submitted` state:
  - Check MR status: `gt mq status <mr-id>`
  - If MR is closed/merged but polecat state is still mr_submitted:
    - Update polecat state to `merged`
    - Log recovery action

**Deacon orphan-check**:
- Query all closed MRs
- Cross-reference with polecat states
- If merged MR but polecat not in merged/retired state:
  - Send correction to Witness
  - Log for metrics (indicates Refinery notification missed)

## Acceptance
- Orphaned polecats detected and corrected
- Recovery is logged for monitoring
- No work lost due to missed notifications


Digest: mol-deacon-patrol

Patrol cycle 60: All healthy, handoff threshold reached


Deacon patrol banners: visual feedback on atom transitions

Print large ASCII banners when transitioning between patrol atoms.

## Problem

When the deacon progresses through patrol atoms (steps), there is no visual feedback.
The operator cannot easily see what the deacon is doing without reading the full output.

## Desired Behavior

Print banners on step start and completion:

  INBOX-CHECK - Checking for lifecycle requests, escalations, timers
  INBOX-CHECK COMPLETE - Processed 3 messages, 0 lifecycle requests

## Benefits

1. Scanability: Operator can glance at tmux and see what is happening
2. Progress tracking: Easy to see where in the patrol loop we are
3. Debugging: Clear demarcation between steps for troubleshooting

## Implementation Options

1. In deacon CLAUDE.md: Instruct agent to print banners
2. gt patrol step start/end: Commands that print banners
3. bd mol step hooks: Automatically on step transitions

## Related

- gt-id36: Deacon Kernel
- gt-rana: Patrol System


Merge: capable-1767079826600

branch: polecat/capable-1767079826600
target: main
source_issue: capable-1767079826600
rig: gastown


Merge: furiosa-dogs

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


Test issue for spawn molecule


Bug: bd update --parent doesn't persist

The --parent flag on bd update reports success but doesn't persist the parent field.

**Confirmed behavior:**
```bash
bd update gt-9kp3t --parent=gt-d0jqp --no-daemon -v
# Output: ✓ Updated issue: gt-9kp3t

bd show gt-9kp3t --json | jq '.[0].parent'
# Returns: null

grep gt-9kp3t .beads/issues.jsonl | head -1 | jq '.parent'
# Returns: null (field not present)
```

**Root cause hypothesis:**
The update handler processes the --parent flag but either:
1. Doesn't write it to the Issue struct
2. Doesn't include it in the JSONL export
3. The field name doesn't match what export expects

**Files to check:**
- cmd/bd/show.go:638-640 (flag handling)
- cmd/bd/show.go:810-814 (reparenting logic)
- internal/rpc/server_issues_epics.go (RPC handler)
- internal/rpc/protocol.go (UpdateArgs.Parent field)

Related: bd-cj2e (the original feature implementation)


Digest: mol-deacon-patrol

Patrol 18: All healthy


Witness patrol: cleanup idle orphan polecats

Add patrol step to find and cleanup polecats that are idle with no assigned issue. These orphans occur when polecats crash before sending DONE or Witness misses the message. Patrol should verify git is clean before removing worktree. Part of gt-rana.


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 900/1023)


Generate handoff summary

Summarize this patrol cycle for digest.

Include:
- Workers inspected (count, names)
- Nudges sent (count, to whom)
- Sessions killed (count, names)
- Escalations (count, issues)
- Issues found (brief descriptions)
- Actions pending for next cycle

This becomes the digest when the patrol wisp is squashed.


Design org formula hierarchy pattern

Design how organizational formula hierarchies work.

## Pattern

    company-base.formula.yaml (org-wide policies)
      └── team-frontend.formula.yaml (extends company-base)
           └── project-dashboard.formula.yaml (extends team-frontend)

## Key Questions

1. How are org formulas discovered? (search path? explicit import?)
2. How do aspects merge across levels?
3. Can child override parent aspects?
4. How to handle aspect conflicts?

## Proposed Design

- Formulas use extends: just like today
- Aspect lists merge (child appends to parent)
- Child can exclude parent aspects via "exclude-aspects: [name]"
- Search path: local -> rig -> org (configurable)

## Deliverables

1. Document pattern in docs/formula-inheritance.md
2. Define conflict resolution rules
3. Identify implementation tasks


Witness patrol wisp with polecat leases

Witness should maintain a rolling patrol wisp that tracks active polecats:

```
wisp-witness-patrol
├── lease: furiosa (boot → working → done)
├── lease: nux (working)
└── lease: slit (done, closed)
```

When POLECAT_STARTED arrives:
- bd mol bond mol-polecat-lease wisp-patrol --var polecat=X

Patrol loop iterates leases:
- gt peek $polecat
- If idle: gt nudge
- If shutdown received: close lease

When all leases closed:
- bd mol squash wisp-xxx --summary='N polecats processed'

Requires mol-polecat-lease proto definition.


Agent-centric dashboard view (gt dashboard)

Charmbracelet TUI for gt feed with dashboard + stream layout.

## Layout (horizontal split)

**Top panel: Agent Tree (role/town view)**
- Shows EVERY agent organized by role
- Each agent shows their MOST RECENT activity inline
- At a glance: who is doing what RIGHT NOW
- Collapsible sections

**Bottom panel: Event Stream (chronological feed)**
- Full scrollable history of events
- Most recent at top
- More detail than the tree view
- This is what you scroll through

## Visual
```
+-------------------------------------------------------------+
| GT Feed                                    Filter: all      |
+-------------------------------------------------------------+
| gastown/                           <- AGENT TREE (top)      |
|   mayor      [10:30] Dispatched gt-xyz -> Toast             |
|   witness    [10:28] Nudged polecat-3 (idle 5m)             |
|   refinery   [10:25] Merged PR #123                         |
|   crew/                                                      |
|      joe        [10:22] Completed gt-95j13                  |
|      max        [10:18] Working on gt-s6r44                 |
|   polecats/                                                  |
|      Toast      [10:30] Received gt-xyz                     |
+-------------------------------------------------------------+
| [10:30] Toast: Received molecule gt-xyz                     |
| [10:28] witness: Nudged polecat-3 after 5m idle             |
| [10:25] refinery: Merged PR #123                            |
| ...                                        <- EVENT STREAM  |
+-------------------------------------------------------------+
| j/k: scroll  /: search  f: filter  q: quit  ?: help         |
+-------------------------------------------------------------+
```

## Why this layout?
- Top answers: what is everyone doing?
- Bottom answers: what just happened?
- Together: complete situational awareness

## Replaces
- gt feed (currently just wraps bd activity)
- gt dashboard task merges into this

## Tech
- bubbletea Model with two viewports
- Tab switches focus between tree/stream
- j/k scrolls focused panel


Digest: mol-deacon-patrol

Patrol 16: all quiet


Digest: mol-deacon-patrol

Patrol cycle 12


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 682/1023)


Move disk 2: C → B

Move disk 2 from peg C to peg B. (Move 366/1023)


Bug: MRs appearing in bd ready output

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

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

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

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

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


Tmux status line: rig color themes and worker identity display

## Summary

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

## Current Problem

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

## Proposed Design

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

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

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

## Configuration

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

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


Digest: mol-deacon-patrol

Patrol 20: Nominal - Handoff threshold reached


Digest: mol-deacon-patrol

Patrol 17: All healthy, 2 mayor handoffs observed


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 850/1023)


Digest: mol-deacon-patrol

Patrol #1: All witnesses running, wyvern refinery started, 3 convoys active (Hanoi/Boot+Polish/Messaging), no orphans, inbox clear


Digest: mol-deacon-patrol

Patrol 6: routine


Day 1.2: Add agent-specific fields to schema

Add fields for agent beads:
- hook_bead: reference to current work (0..1 cardinality)
- role_bead: reference to role definition (1)
- state: agent-reported state (idle|running|stuck|stopped)

Parent: gt-d0jqp

Re-opened: Close reason referenced non-existent commit b5c69507. Agent fields not yet implemented in bd CLI.


Remove polecat state derivation from issue status

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

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

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

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

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


Digest: mol-deacon-patrol

Patrol 255 complete: no incidents


Add bulk session stop command (gt session stop --all)

When decommissioning a rig, need to stop multiple sessions one at a time. A --all or --rig flag would allow: gt session stop --rig gastown


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


CRITICAL: Polecats not pushing before signaling done

Pipeline failure - work being lost:

1. Polecat does work locally
2. Polecat closes bead, goes idle
3. BUT doesn't push commits first
4. Witness sends MERGE_READY to refinery
5. Refinery sees 'no commits ahead of main' - skips
6. Witness nukes polecat
7. Work lost forever

Evidence: Refinery log shows 'MERGE_SKIPPED: furiosa (gt-ft5eb) - No commits ahead of main'

All formula convoy work was lost this way.

Fix: gt done MUST verify push succeeded before signaling completion.


Digest: mol-deacon-patrol

Patrol 14: Quiet


gt crew add should provision .claude/commands/

When adding a crew member with 'gt crew add', provision the .claude/commands/ directory with standard commands like handoff.md.

Currently only polecats get this via the spawning process. Crew members are added manually and miss out on slash commands like /handoff.

Also: gt doctor should detect missing .claude/commands/ in crew directories and offer to fix.


mol-deacon-patrol


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 123/1023)


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 108/1023)


Move disk 3: C → A

Move disk 3 from peg C to peg A. (Move 644/1023)


Move disk 1: B → A

Move disk 1 from peg B to peg A.


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 887/1023)


Glass Cockpit: See WTF is happening

Glass cockpit - see what's happening across the system.

Phase 1 got the engine running. Phase 2 makes it observable.

**Pillars:**
- Pillar 4: Swarm-in-Beads (gt-kc7yj - already exists)
- Pillar 5: MQ Observability
- Pillar 6: Witness Observability
- Pillar 7: Unified Dashboard

**Success criteria:**
1. gt status shows per-rig queue depth and agent health
2. gt feed shows MQ and swarm lifecycle events
3. gt dashboard provides live system visibility
4. No .runtime/*.json files for observable state
5. Swarms fully tracked in beads

Reference: ~/gt/docs/liftoff-plan.md


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 257/1023)


Digest: mol-deacon-patrol

Patrol 101-120 complete: Cleaned 42 stale wisps, health pings sent to all witnesses/refineries, all agents healthy, no orphans, 1 idle dog


gt polecat status shows idle when hook_bead is set in agent bead

gt polecat status gastown/furiosa shows State: idle, Issue: (none) but the agent bead gt-gastown-polecat-furiosa has hook_bead: gt-um6q and agent_state: running. The status command isn't reading hook_bead from the agent bead correctly.


Witness patrol formula should document 'dead' agent state

## Problem

The witness patrol formula survey-workers step documents these agent states:

  agent_state: running|idle|stuck|done

But the daemon lifecycle (daemon/lifecycle.go:647) can set agent_state to 'dead'
when an agent goes unresponsive. This state isn't mentioned in the formula.

## Found in commit

f3a6ef6 (feat: Witness reads polecat state from agent beads)

## Suggested fix

Update the formula survey-workers step to include 'dead' in the state table:

| agent_state | Meaning | Action |
|-------------|---------|--------|
| running | Actively working | Check progress (Step 3) |
| idle | No work assigned | Skip (no action needed) |
| stuck | Self-reported stuck | Handle stuck protocol |
| done | Work complete | Verify cleanup triggered |
| dead | Marked dead by daemon | Clean up or respawn |


Merge: cheedo-1767146245543

branch: polecat/cheedo-1767146245543
target: main
source_issue: cheedo-1767146245543
rig: gastown


Digest: mol-deacon-patrol

Cycle 295: All healthy, gastown refinery 1 pending


attached_args: Extract processExists function to reduce duplication

Extract duplicated processExists function to shared package.

## Files to modify
- internal/util/process.go (NEW)
- internal/witness/manager.go (remove local function, import util)
- internal/refinery/manager.go (remove local function, import util)

## Current duplication
Both files have identical implementations at:
- internal/witness/manager.go (lines 136-144)
- internal/refinery/manager.go (lines 646-654)

```go
func processExists(pid int) bool {
    proc, err := os.FindProcess(pid)
    if err != nil {
        return false
    }
    err = proc.Signal(nil)
    return err == nil
}
```

## Implementation
Create internal/util/process.go:
```go
package util

import "os"

// ProcessExists checks if a process with the given PID exists.
func ProcessExists(pid int) bool {
    proc, err := os.FindProcess(pid)
    if err != nil {
        return false
    }
    return proc.Signal(nil) == nil
}
```

## Acceptance criteria
- [ ] internal/util/process.go created with ProcessExists function
- [ ] internal/util/process_test.go with basic tests
- [ ] witness/manager.go imports util and uses util.ProcessExists
- [ ] refinery/manager.go imports util and uses util.ProcessExists
- [ ] Local processExists functions removed from both files
- [ ] go build ./... passes
- [ ] go test ./... passes


Digest: mol-deacon-patrol

Patrol cycle 15: All healthy


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 511/1023)


Digest: mol-deacon-patrol

Cycle 189: Nominal


Digest: mol-deacon-patrol

Patrol cycle 30: All healthy, no incidents


Move disk 1: A → C

Move disk 1 from peg A to peg C.


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Remove deprecated SessionBeacon function

## Context

The StartupNudge migration (gt-7pp3l) replaced all SessionBeacon usages with StartupNudge.

## Current State

`SessionBeacon()` in `internal/session/names.go` is now dead code:
- Function definition exists at line 52
- No callers remain in the codebase

## Action

Remove the deprecated function:
```go
// SessionBeacon generates an identity beacon message for Claude Code sessions.
// ...
func SessionBeacon(address, molID string) string {
    // ...
}
```

## Risk

Low - function is unused. Verify with:
```bash
grep -r 'SessionBeacon' --include='*.go' . | grep -v 'names.go'
```

## Related

- gt-7pp3l: Migrate startup paths from SessionBeacon to StartupNudge
- gt-85whr: Agent Startup Consolidation epic (closed)


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 805/1023)


Digest: mol-deacon-patrol

Patrol 20 - handoff threshold


gt-gastown-polecat-organic

gt-gastown-polecat-organic

role_type: polecat
rig: gastown
agent_state: spawning
hook_bead: null
role_bead: gt-polecat-role
cleanup_status: has_stash
active_mr: gt-scdyn
notification_level: null


Digest: mol-deacon-patrol

Patrol 156 complete


Digest: mol-deacon-patrol

Patrol cycle 42: All agents healthy, no incidents


Merge: gt-ay1r

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


Task D: Integration


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 657/1023)


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.


mol-deacon-patrol


Digest: mol-deacon-patrol

Patrol complete: gastown witness came online, town healthy


Merge: valkyrie-1767147773208

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


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 540/1023)


Move disk 1: B → C

Move disk 1 from peg B to peg C. (Move 195/1023)


Merge: gt-3x1

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


Move disk 2: B → A

Move disk 2 from peg B to peg A. (Move 238/1023)


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 1019/1023)


Move disk 4: B → A

Move disk 4 from peg B to peg A. (Move 88/1023)


Workspace cleanup: preflight and postflight

Workspace preflight and postflight commands for clean state management.

## Preflight
```
gt preflight [--rig <rig>] [--dry-run]
```

Run before starting batch work:
1. Clean stale mail in inboxes
2. Check for stuck workers (warn)
3. Check rig health (polecats, refinery)
4. Verify git state is clean
5. Run bd sync to ensure beads current

## Postflight
```
gt postflight [--rig <rig>] [--archive-mail] [--dry-run]
```

Run after batch work completes:
1. Archive old mail with --archive-mail
2. Clean up stale integration branches
3. Sync beads
4. Report on rig state

## Implementation
```go
func Preflight(rigName string, dryRun bool) (*PreflightReport, error)
func Postflight(rigName string, opts PostflightOptions) (*PostflightReport, error)
```

## Report Structures
```go
type PreflightReport struct {
    MailCleaned    int
    RigHealthy     bool
    StuckWorkers   []string
    Warnings       []string
}

type PostflightReport struct {
    MailArchived   int
    BranchesCleaned int
    Warnings       []string
}
```

## Note

These are workspace maintenance commands, not tied to "swarm" lifecycle. Run them anytime to keep the rig clean.

## Acceptance Criteria
- [ ] Preflight cleans stale state
- [ ] Postflight archives old mail
- [ ] Both have --dry-run mode
- [ ] Clear reports of actions taken


Testing: End-to-end rebase workflow validation

Comprehensive testing of the new rebase-as-work workflow.

## Test Scenarios

### Happy Path
1. Single MR, clean rebase → refinery merges
2. Multiple MRs, no conflicts → priority ordering works

### Conflict Handling
3. MR conflicts → conflict task created
4. Conflict task dispatched → polecat resolves
5. Resolved MR re-enters queue with priority boost
6. Multiple conflict cycles → retry_count tracked

### Priority Scoring
7. Older convoy MRs prioritized over newer
8. P1 epic MRs prioritized over P3
9. High retry_count gets appropriate adjustment

### Edge Cases
10. MR conflicts again after resolution
11. Polecat recycled before merge
12. Convoy completed with pending MRs

## Implementation
- Unit tests for ScoreMR function
- Integration tests for refinery flow
- Scenario tests with actual polecats (manual/semi-auto)


Digest: mol-refinery-patrol

Patrol: queue empty, no merges, 0 messages processed


bd update --claim for work queue semantics

Atomic claim operation for work queue messages.

## Deliverables

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

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

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

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


Update swarm terminology to streams

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

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


mol-deacon-patrol

Mayor's daemon patrol loop.

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

## Second-Order Monitoring

Witnesses send WITNESS_PING messages to verify the Deacon is alive. This
prevents the "who watches the watchers" problem - if the Deacon dies,
Witnesses detect it and escalate to the Mayor.

The Deacon's agent bead last_activity timestamp is updated during each patrol
cycle. Witnesses check this timestamp to verify health.


Move disk 1: C → A

Move disk 1 from peg C to peg A. (Move 299/1023)


Digest: mol-deacon-patrol

Patrol 10: All healthy, halfway mark


Phase 3.1: Summary generation protocol

Define how agents generate summaries for squash.

## The Problem

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

## Summary Template

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

## Example

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

## Command

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


Digest: mol-deacon-patrol

Patrol 98: All healthy


Digest: mol-deacon-patrol

Patrol 9: All clear


Refinery Engineer: Role prompting and CLAUDE.md

Create refinery/CLAUDE.md with Chief Merge Engineer role context. Include:
- Role identity and responsibilities
- Decision authority (merge order, test frequency, binary rebuilds)
- Communication patterns (Witness, Deacon)
- Session lifecycle (handoff bead protocol)
- Key commands reference


Merge: slit-mjtj9dc8

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


gt mail send: support reading message body from stdin

Currently gt mail send -m requires the message as a command-line argument, which causes shell escaping issues with backticks, quotes, and special characters.

Add support for reading message body from stdin:
- gt mail send addr -s 'Subject' --stdin  # Read body from stdin
- echo 'body' | gt mail send addr -s 'Subject' -m -  # Convention: -m - means stdin

This would allow:
cat <<'EOF' | gt mail send addr -s 'Subject' --stdin
Message with \`backticks\` and 'quotes' safely
EOF

Without this, agents struggle to send handoff messages containing code snippets.

## Moved from beads
Originally bd-3bsz. gt mail is in gastown, not beads.


Move disk 3: B → C

Move disk 3 from peg B to peg C. (Move 972/1023)


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

Patrol 19: All healthy


mol-deacon-patrol


Move disk 2: A → C

Move disk 2 from peg A to peg C. (Move 566/1023)


Digest: mol-deacon-patrol

Patrol 121: All agents healthy, no incidents


Daemon sending heartbeat to Mayor - should not

Daemon appears to be sending heartbeat messages to Mayor, but Mayor should not receive heartbeats. Observed at least once or twice - needs investigation to confirm and fix.


Digest: mol-deacon-patrol

Cycle 15


Day 3.1: Wire witness patrol formula to daemon cron

Witness patrol molecule runs on schedule:
- Daemon pokes witness on cron interval
- Witness runs mol-witness-patrol steps
- Results in wisp (ephemeral), squashed later

Parent: gt-hwka3


Refinery background daemon mode

Refinery currently only works in foreground mode. Background daemon is stubbed.

## Current State
manager.go line 128-129:
```go
// Background mode: spawn a new process
// For MVP, we just mark as running - actual daemon implementation in gt-ov2
return nil
```

## Requirements

### 1. Background Process Spawning
```go
func (m *Manager) Start(foreground bool) error {
    if !foreground {
        // Spawn gt refinery start --foreground as subprocess
        cmd := exec.Command(os.Args[0], "refinery", "start", m.rig.Name, "--foreground")
        cmd.Start()  // Don't wait
        // Record PID
    }
}
```

### 2. PID File Management
- Write PID to .gastown/refinery.pid
- Check PID validity on status
- Clean up stale PID files

### 3. Log Output
- Redirect stdout/stderr to .gastown/refinery.log
- Log rotation (optional for MVP)

### 4. Graceful Shutdown
- Handle SIGTERM/SIGINT
- Complete current merge before exit
- Update state to stopped

### 5. Health Check
- Process existence check via kill -0
- Optional: heartbeat file with timestamp

## Files to Modify
- internal/refinery/manager.go: Start(), Status(), process spawning

## Acceptance Criteria
- [ ] gt refinery start <rig> spawns background process
- [ ] gt refinery status shows running with PID
- [ ] gt refinery stop sends SIGTERM and waits
- [ ] Logs written to .gastown/refinery.log
- [ ] Survives terminal close


Digest: mol-deacon-patrol

Patrol 14: All clear


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 859/1023)


Hook ergonomics: auto-replace completed pins

## Problem

When pinning a new bead, if the old pinned bead is complete, the new pin should automatically replace it. Currently this fails and requires manual unpinning (which doesn't exist as a command).

Observed friction:
1. Old patrol wisp 100% complete, still pinned
2. Created new patrol wisp
3. `gt mol attach` failed: 'not pinned'
4. Tried to close old wisp: 'cannot close pinned issue'
5. Tried `gt hook unpin`: command doesn't exist
6. Stuck in limbo

## Proposed fix

- `gt hook <new-bead>` auto-replaces if old pin is complete
- Require `--force` if old pin is incomplete
- `gt mol attach` should auto-pin if bead isn't pinned

## Orphan detection

Unpinned incomplete molecules aren't stale orphans until they create graph pressure (blocking other work). Orphan detection should focus on dependency blocking, not just 'unpinned' status.


Delete molecules_*.go files

Remove legacy Go-defined molecules:
- internal/beads/builtin_molecules.go
- internal/beads/molecules_patrol.go
- internal/beads/molecules_session.go
- internal/beads/molecules_work.go

Update install.go to cook formulas instead of seeding Go structs.
Update catalog.go if needed.


Deacon health checks too frequent - disturbs idle agents


Move disk 1: A → B

Move disk 1 from peg A to peg B. (Move 643/1023)


Config package: Config, State types and JSON serialization

Config and state types with JSON serialization.

## Town Config (config/town.json)

```go
type TownConfig struct {
    Type      string    `json:"type"`       // "town"
    Version   int       `json:"version"`    // schema version
    Name      string    `json:"name"`       // town identifier
    CreatedAt time.Time `json:"created_at"`
}
```

## Rigs Registry (config/rigs.json)

```go
type RigsConfig struct {
    Version int                `json:"version"`
    Rigs    map[string]RigEntry `json:"rigs"`
}

type RigEntry struct {
    GitURL   string    `json:"git_url"`
    AddedAt  time.Time `json:"added_at"`
    BeadsConfig *BeadsConfig `json:"beads,omitempty"`
}

type BeadsConfig struct {
    Repo   string `json:"repo"`   // "local" | path | git-url
    Prefix string `json:"prefix"` // issue prefix
}
```

## Agent State (*/state.json)

```go
type AgentState struct {
    Role       string    `json:"role"`       // "mayor", "witness", etc.
    LastActive time.Time `json:"last_active"`
    Session    string    `json:"session,omitempty"`
    Extra      map[string]any `json:"extra,omitempty"`
}
```

## Interface

```go
func LoadTownConfig(path string) (*TownConfig, error)
func SaveTownConfig(path string, config *TownConfig) error

func LoadRigsConfig(path string) (*RigsConfig, error)
func SaveRigsConfig(path string, config *RigsConfig) error

func LoadAgentState(path string) (*AgentState, error)
func SaveAgentState(path string, state *AgentState) error
```

## Validation

- Version compatibility checks
- Required field validation
- Path existence verification