Digest: mol-deacon-patrol

Cycle 4: quiet patrol


BUG: Convoys don't auto-close when all tracked issues complete

Multiple convoys found with 100% completion (1/1, 10/10) but still status=open. According to convoy docs: 'Auto-closes when all tracked issues complete'. Either the auto-close logic isn't running or it's failing silently.

Fixed: Added gt convoy check command for cross-rig auto-close


Digest: mol-deacon-patrol

P17: stable


Session ended: gt-gastown-crew-joe


Autonomous agents idle at welcome screen after start

dispatched_by: mayor

After refinery/witness is killed and respawned by Deacon, the new session sits idle at Claude welcome screen. Root cause: Deacon's respawn logic starts the session but doesn't send the GUPP propulsion nudge. Compare to ensureRefinerySession() in start.go which sends StartupNudge + PropulsionNudgeForRole. The Deacon respawn needs the same treatment. Check deacon patrol code that handles LIFECYCLE/respawn events.

Added StartupNudge and PropulsionNudgeForRole to restartSession in lifecycle.go


Implement queue:name address type for claim-based mail delivery

Add support for queue:name addresses in the mail router.

SEMANTICS:
- Messages to queue:name create ONE copy in a shared location
- Workers eligible for the queue (per messaging.json) can claim messages
- Claimed message is removed from queue, moved to claimer inbox
- If claimer fails to process, message can be released back to queue

USE CASE:
Polecat completion notifications - Witness OR Deacon should handle, not both.

IMPLEMENTATION:
1. Add isQueueAddress() / parseQueueName() helpers
2. Add sendToQueue() - creates message in queue location
3. Add gt mail claim <queue> - claims oldest unclaimed message
4. Add gt mail release <msg-id> - releases back to queue
5. Track claim state in message metadata

CONFIG (already in messaging.json schema):
queues.cleanup/gastown.workers = [gastown/witness, deacon/]
queues.cleanup/gastown.max_claims = 0


Digest: mol-deacon-patrol

Patrol 2: routine, all healthy


Merge: warboy-mjz94u1q

branch: polecat/warboy-mjz94u1q
target: main
source_issue: warboy-mjz94u1q
rig: gastown
agent_bead: gt-gastown-polecat-warboy
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Merge: capable-1767081117001

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


gt channel publish command

New CLI command for ephemeral broadcast to channels.

## Deliverables

1. New command: gt channel publish <channel> <message>
   - Example: gt channel publish #witnesses "Swarm incoming"
2. Resolve channel to running sessions
3. Nudge each session with message
4. Report delivery status

## Usage
```bash
gt channel publish #town "Handoff in 5 minutes"
gt channel publish #rig/gastown "Merge queue paused"
```

## Dependencies
- #channel resolution (gt-???)

## Acceptance
- Command works with #channel syntax
- Message delivered to running sessions
- Clear output showing delivery status


Review PR #95: fix daemon init recommendation


Digest: mol-deacon-patrol

Patrol 10: 3 rigs healthy


Digest: mol-deacon-patrol

Patrol 8: healthy


Digest: mol-deacon-patrol

Patrol 15: healthy


Digest: mol-deacon-patrol

Patrol cycle 17: All agents healthy


Digest: mol-deacon-patrol

Patrol 113: All healthy


Digest: mol-deacon-patrol

Patrol 119: All healthy


Digest: mol-deacon-patrol

Patrol 20: final cycle complete, handoff time


Digest: mol-deacon-patrol

Patrol cycle 46: All healthy


Merge: toast-1767088545235

branch: polecat/toast-1767088545235
target: main
source_issue: toast-1767088545235
rig: gastown


Digest: mol-deacon-patrol

Patrol 18: All clear


Session ended: gt-gastown-crew-joe

Bulk cleanup of stale session-ended events (gt-8tc1v)


Merge: furiosa-1767087671424

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


Add gt hook command (wrapper for bd hook)

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

## Usage

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

## Implementation

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

## Why gt wrapper?

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

## Related

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


Review: Refinery patrol template changes (gt-qz2l)

Polecat dementus implemented refinery template changes: banners, wisp-based execution, propulsion protocol. Review for correctness and consistency with witness/deacon patterns.


Merge: dementus-mjw46vz4

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


[Refactor] Consolidate duplicate clone-with-reference-fallback pattern

The pattern of 'try CloneWithReference, warn, fallback to Clone' appears in 3+ locations:

1. rig/manager.go:274-285: CloneBare with reference
2. rig/manager.go:314-326: Clone for mayor
3. crew/manager.go:74-85: Clone for crew

Should extract to a helper like:
  func (g *Git) CloneWithReferenceFallback(url, dest, ref string, bare bool) error

This would reduce duplication and ensure consistent error messaging.


Digest: mol-deacon-patrol

Patrol 5: All healthy


Digest: mol-deacon-patrol

Patrol complete: all agents healthy


Digest: mol-deacon-patrol

Patrol 251 complete: no incidents


Digest: mol-deacon-patrol

Patrol 14: healthy


Digest: mol-deacon-patrol

Patrol 86: All healthy


gt done fails in worktree: missing remote.origin.fetch config

Added ls-remote fallback when tracking ref unavailable due to missing fetch refspec


Digest: mol-deacon-patrol

Patrol cycle 53: All healthy


Merge: furiosa-1767084006859

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


Session ended: gt-gastown-crew-joe


Session ended: gt-gastown-crew-gus


Digest: mol-deacon-patrol

Patrol cycle 12: All agents healthy


Digest: mol-deacon-patrol

Patrol cycle 3: all healthy


Merge: gt-3x1.3

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


Digest: mol-deacon-patrol

Cycle 8


Digest: mol-deacon-patrol

Patrol complete: no work, gastown refinery came online, town healthy


Digest: mol-deacon-patrol

Patrol cycle 25: quick check, all healthy


Digest: mol-deacon-patrol

Patrol 149: All healthy


Merge: gt-s7t1h

branch: polecat/dag-mjxm10sv
target: main
source_issue: gt-s7t1h
rig: gastown
agent_bead: gt-mayor

Merged to main at a15f4bb7 (dag-mjxm10sv restart feature)


Agent state lifecycle incomplete for polecats

## Problem

The witness patrol formula (mol-witness-patrol.formula.toml) expects polecats to self-report states:
- running
- idle
- stuck
- done

But looking at the code, the only state transitions that actually happen are:

1. **spawning** - Set when polecat is created (polecat/manager.go:170)
2. **running** - Set when agent runs `gt prime` (prime.go:112)
3. **dead** - Set by daemon when agent goes unresponsive (daemon/lifecycle.go:647)

**Missing transitions:**
- `stuck` - No code path exists for agents to report this
- `done` - No code path exists for agents to report this
- `idle` - Only set for infrastructure agents, never for polecats

## Impact

The witness cannot rely on agent_state to detect stuck or done polecats, contradicting the ZFC principle stated in the formula.

## Found in commit

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

## Suggested fix

Add code paths for polecats to self-report:
1. `gt done` should update agent_state to "done"
2. When stuck (detected how?), agent should update to "stuck"
3. Consider if "idle" makes sense for polecats (no current work)


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

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

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

Fixed: Added mayor detection for <rig>/mayor/ paths in detectRole(). Now gt prime detects Mayor from ~/gt/gastown/mayor/rig and similar paths.


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy, handoff threshold reached


Update prompts.md: Engineer role and templates

Update docs/prompts.md with Engineer role:

1. Role Prompts table: Change Refinery to Engineer
2. Add Engineer-specific prompts:
   - Session restart request template
   - Subtask filing template
   - Handoff mail template
3. Update refinery.md template name to engineer.md
4. Ensure consistency with architecture.md


Remove all hardcoded gastown dependencies from gt codebase

The Go codebase should not have hardcoded dependencies on gastown (the rig name).

Found in prime.go outputDeaconPatrolContext() - FIXED in this session.

Other potential issues to audit:
- Check all patrol context functions (Witness, Refinery) for similar patterns
- Ensure rig-specific paths are derived from context, not hardcoded
- Test with a different rig name to verify

The principle: Gas Town should work with any rig name, not just gastown.


Add isQueueAddress() and parseQueueName() helpers to router.go

Add queue address detection to internal/mail/router.go.

PATTERN TO FOLLOW:
Look at isListAddress() and parseListName() at lines 53-60 as the template.

IMPLEMENTATION:
1. Add isQueueAddress(address string) bool - returns true if address starts with 'queue:'
2. Add parseQueueName(address string) string - extracts queue name after 'queue:'

FILE: internal/mail/router.go
TESTS: Add tests in internal/mail/router_test.go following the pattern of TestIsListAddress/TestParseListName

This is a small, focused task. Do not implement sendToQueue or claiming - just the address detection.

Added isQueueAddress() and parseQueueName() helpers with tests


Digest: mol-deacon-patrol

Patrol 16: All healthy


Session ended: gt-gastown-crew-joe


Merge: capable-1767079826600

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


Merge: gastown-mk0voe9u

branch: polecat/gastown-mk0voe9u
target: main
source_issue: gastown-mk0voe9u
rig: gastown
agent_bead: gt-gastown-polecat-gus
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Add unit tests for internal/mrqueue package

attached_args: mrqueue package tests

Add comprehensive tests for the merge request queue package.

## Files to create
- internal/mrqueue/mrqueue_test.go

## Test cases to cover
1. NewQueue creates queue directory
2. Add() persists MR to queue
3. Get() retrieves MR by ID
4. List() returns all MRs
5. Remove() deletes MR
6. MR serialization/deserialization
7. Queue handles concurrent access

## Acceptance criteria
- [ ] internal/mrqueue/mrqueue_test.go created
- [ ] At least 6 test functions
- [ ] Tests pass: go test ./internal/mrqueue/...
- [ ] Coverage > 70%


[Go Idiom] Remove panic in MustGetTownName

workspace/find.go:155-158 uses panic in MustGetTownName(). Panics in library code are an anti-pattern - they make error handling impossible for callers. Either:
1. Remove the Must* variant entirely (callers use GetTownName with proper error handling)
2. If convenience function needed, return empty string on error with logging

Current usage should be audited to ensure callers can handle errors gracefully.


Digest: mol-deacon-patrol

Patrol 19


Digest: mol-deacon-patrol

Patrol 17: all healthy


Session ended: gt-gastown-crew-gus


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)


gt dog add/remove/list/call/status CLI

Dog management commands:
- gt dog add <name> - Create dog in kennel with multi-rig worktrees
- gt dog remove <name> - Retire dog, cleanup worktrees
- gt dog list - Show the pack (all dogs with status)
- gt dog call [name] - Wake idle dog(s)
- gt dog status [name] - Show detailed dog state

Implemented all gt dog CLI commands: add, remove, list, call, status


Kennel directory structure and multi-rig worktrees

Create kennel infrastructure:
- ~/gt/deacon/dogs/<name>/ directory
- Worktrees into each rig (gastown, beads, etc.)
- .dog.json state file (idle/working, last-active, assigned-work)
- Worktree refresh/cleanup logic

Implemented internal/dog package with Manager, Dog struct, .dog.json schema, multi-rig worktrees, and refresh/cleanup logic


gt sling support for deacon/dogs target

Extend gt sling to support dog targets:
- gt sling <work> deacon/dogs - Auto-dispatch to idle dog
- gt sling <work> deacon/dogs/alpha - Specific dog
- Dog pool management (spawn if needed, up to max)
- Completion mail handling

Implemented: gt sling deacon/dogs and deacon/dogs/<name> targets with pool management


Deacon patrol refactor: detect → dispatch

Refactor Deacon patrol to delegate heavy work to dogs:
- check-conditions → sling to dog (not inline execution)
- Pool maintenance step (spawn/retire/refresh)
- Completion mail handling from dogs
- Keep patrol lightweight (detection only)

Refactored patrol: added DOG_DONE handling, dog-pool-maintenance, detect-only orphan-check and session-gc


Infrastructure formulas for dog tasks

Create formulas for dog-executed tasks:
- mol-convoy-cleanup: Archive convoy, notify overseer
- mol-dep-propagate: Cross-rig dependency resolution
- mol-digest-generate: Daily digest for overseer
- mol-orphan-scan: Find and reassign orphaned work
- mol-session-gc: Clean stale sessions

Created 5 infrastructure formulas for dog tasks: convoy-cleanup, dep-propagate, digest-generate, orphan-scan, session-gc


mol-sync-workspace: Add explicit gt prime / bd prime in assess-state

Added gt prime / bd prime commands as Step 0 in assess-state, with explanatory comment about when priming is critical


Digest: mol-deacon-patrol

P10: stable


Standardize error handling and warning output patterns

Inconsistent patterns across codebase:

Error wrapping:
- Some: fmt.Errorf("context: %w", err) (good)
- Some: return err (loses context)
- Some: fmt.Errorf("message", rigName) without wrapping original

Exit handling in Cobra commands:
- Some use os.Exit(1) inside RunE (bad - loses error chain)
- Some properly return errors

Warning output styles:
- fmt.Printf("%s Warning: ...", style.Dim.Render("⚠"))
- fmt.Printf("Warning: %s", ...)
- fmt.Fprintf(os.Stderr, "warning: ...")

Suggestion:
1. Always wrap errors with %w
2. Never call os.Exit() in RunE handlers
3. Standardize on style.Warning.Render("Warning:") pattern


Digest: mol-deacon-patrol

Patrol 85: All healthy


Day 4.5: Test multi-step molecule lifecycle

Integration test (UPDATED for self-managed handoffs):
1. Sling work with molecule to polecat
2. Polecat works through all steps (self-handoffs as context fills)
3. Polecat calls gt done when work complete
4. Witness verifies clean state and sends MERGE_READY to refinery
5. Refinery merges branch
6. Refinery sends MERGED to witness
7. Witness calls gt polecat nuke for full cleanup
8. Verify clean state (no worktree, no branch, agent bead closed)

**VALIDATED**: rictus lifecycle worked end-to-end: gt done → witness → refinery → merged

Parent: gt-4a2qt


Session ended: gt-gastown-crew-max


gt mail clear --all: Add flag for agent ergonomics

## Task

Add `--all` flag to `gt mail clear` as an affordance.

The command already clears all messages by default, but agents naturally try `--all` when they want to clear everything. Adding it as a no-op flag improves ergonomics.

## Implementation

In `internal/cmd/mail_clear.go` (or similar):

```go
var clearAll bool

func init() {
    clearCmd.Flags().BoolVar(&clearAll, "all", false, "Clear all messages (default behavior)")
}
```

The flag doesn't change behavior - it's just for discoverability and natural agent usage patterns.

Added --all flag to gt mail clear as no-op for agent ergonomics


Merge: warboy-mjwjbptd

branch: polecat/warboy-mjwjbptd
target: main
source_issue: warboy-mjwjbptd
rig: gastown
agent_bead: gt-gastown-polecat-warboy

Branch reset to main - work superseded by existing code


gt rig start <rig>... - start witness + refinery on patrol

Start one or more rigs by launching their witness and refinery workers on patrol. Should support multiple rigs: gt rig start gastown beads

Implemented gt rig start command with multi-rig support


Digest: mol-deacon-patrol

Cycle 3: quiet patrol


Session ended: gt-gastown-dinki


Phase 4: Handle conflict resolution edge case

Address edge case: conflict detected AFTER polecat worktree is nuked.

Problem: If polecat is cleaned up before MR merges, local branch is gone.

Options:
1. **Delay cleanup** (recommended): Witness doesn't nuke polecats with pending MRs
2. Copy branch to holding namespace before cleanup
3. Push branch only when conflict detected

Recommendation: Option 1 - polecat isn't truly 'done' until work is merged.

Files:
- Witness cleanup logic
- internal/formula/formulas/mol-polecat-conflict-resolve.formula.toml:149-152

Implemented Phase 4: Witness now defers polecat cleanup for pending MRs, preserving local branches for conflict resolution


Digest: mol-deacon-patrol

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


Add timeouts to convoy panel subprocess calls

convoy.go spawns bd and sqlite3 without timeouts. If these hang, the TUI freezes. Add 5-second context timeouts.

Added 5-second context timeouts to convoy panel subprocess calls


Session ended: gt-gastown-crew-jack


Add prefix mismatch detection to gt doctor

## Context

When investigating PR #183 (rig agent beads prefix fix), we discovered that rigs.json
had `"prefix": "ga"` for gastown, but the actual beads database uses `gt-` prefix.

This happened because:
1. `deriveBeadsPrefix("gastown")` returns "ga" (first 2 chars of single word)
2. But beads were initialized with "gt" (perhaps before auto-derive existed)
3. rigs.json stored the wrong derived prefix

## Problem

There's no validation that the prefix in rigs.json matches what's actually in the
beads database. This can cause agent lifecycle management to fail silently (looking
for `ga-gastown-witness` when `gt-gastown-witness` exists).

## Suggested Fix

Add a check to `gt doctor` that:
1. For each rig in rigs.json, get the configured prefix
2. Query the rig's beads database for its actual prefix (from config or existing beads)
3. Warn if they don't match

Example output:
```
⚠ Prefix mismatch for rig 'gastown':
  rigs.json says: ga
  beads db uses:  gt
  Run: gt rig set-prefix gastown gt
```

## Related

- Commit e8d27e7: fix rig agent beads prefix
- PR #183: original partial fix by Johann Taberlet

Implemented prefix mismatch detection check for gt doctor


Document Boot vs Deacon lifecycle and fix design confusion

## Problem

The Boot/Deacon relationship is confusing and possibly over-engineered:

### Current Design
```
Daemon (Go process, 3-min heartbeat)
    │
    └─► Boot (ephemeral triage dog)
            │
            └─► Decides: start/wake/nudge/interrupt Deacon?
                    │
                    └─► Deacon (persistent patrol agent)
                            │
                            └─► health-scan: restart witness/refinery
```

### Questions

1. **Why two agents?** Boot exists to avoid waking Deacon unnecessarily in idle towns. But is this complexity worth it?

2. **Session ownership**: Boot should run in `gt-deacon-boot`, Deacon in `gt-deacon`. But current behavior is confused.

3. **Handoff**: When Boot starts Deacon, what happens to Boot? Does it exit? Hand off?

4. **Fallback**: Daemon has `checkDeaconHeartbeat()` as belt-and-suspenders. When does this fire vs Boot?

## Options

### Option A: Keep Boot/Deacon separation (fix implementation)
- Boot is ephemeral, spawns fresh each heartbeat
- Boot runs in `gt-deacon-boot`, exits after triage
- Deacon runs in `gt-deacon`, persistent patrol
- Clear session boundaries, clear lifecycle

### Option B: Merge Boot into Deacon
- Single `gt-deacon` session
- Deacon handles its own 'should I be awake?' logic
- Simpler, fewer moving parts
- Trade-off: Deacon consumes context even when idle

### Option C: Replace with simpler watchdog
- Daemon directly monitors witness/refinery
- No Boot, no Deacon AI agents for health checks
- Just Go code: if session dead, restart it
- AI agents only for complex decisions (escalations)

## Recommendation

Option A with clear documentation. The separation has merit for cost control in idle towns. But the implementation needs fixing.

Documentation complete: created docs/watchdog-chain.md with full lifecycle explanation, design decision (keep separation), and cross-references


Session ended: gt-gastown-citadel

Bulk cleanup of stale session-ended events (gt-8tc1v)


Digest: mol-deacon-patrol

Patrol 54: All healthy


Digest: mol-deacon-patrol

Patrol 12: Quiet


gt sling fails for terminated polecats even with --naked flag

## Problem
When a polecat terminates after completing work (submits MR, session ends), the polecat directory still exists but the tmux session is gone. Attempting to sling new work to that polecat fails:

```
gt sling bd-fa1q beads/Toast --naked
Error: resolving target: getting pane for gt-beads-toast: exit status 1
```

The `--naked` flag should bypass tmux pane requirements, but the error occurs during target resolution before the flag is checked.

## Expected Behavior
`gt sling <bead> <polecat> --naked` should:
1. Attach work to the polecat hook
2. Skip session creation (manual start later)
3. NOT require an existing tmux pane

## Workaround
Use crew workers instead (they have persistent sessions).

## Fix
Target resolution should check `--naked` flag before attempting pane lookup, or provide a way to respawn terminated polecats.

Fixed: resolveTargetAgent now skips tmux pane lookup when --naked flag is set


Polecat auto-start: Claude doesn't process initial nudge

After gt sling spawns a polecat, the 'Work slung' message is sent to tmux but Claude sits idle at the prompt. The SessionStart hook doesn't fire because no user input was received.

Observed:
- gt sling successfully spawns polecat, creates worktree, starts Claude
- Sends 'Work slung: gt-xxx. Start working on it now...' to the pane
- Claude shows idle prompt 'Try refactor...' and doesn't process the message

Expected:
- Polecat should auto-start working on the slung issue

Root cause hypothesis:
- The nudge is sent as tmux send-keys which goes to the input line
- Claude needs Enter to be pressed to submit the prompt
- SessionStart hook only fires after first user message

Workaround:
- Send extra Enter after the nudge message
- Or use daemon's triggerPendingSpawns to send Enter after Claude is ready


Merge: toast-mjw7062w

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


Code review: handoff.go changes (gt-yt6g, gt-tocb)

Review ~80 lines of Go changes to internal/cmd/handoff.go:

## Commits to review
- 1414081: Standardize session end with gt handoff (gt-yt6g)
  - Detect polecats via GT_POLECAT env var
  - Call gt done instead of respawning for polecats
  - +31/-11 lines

- 9c85b83: Support full session paths in gt handoff (gt-tocb)
  - resolveRoleToSession accepts <rig>/crew/<name>, <rig>/witness, <rig>/refinery
  - +46/-3 lines

## Review focus
- Error handling in path resolution
- Edge cases in polecat detection
- Test coverage needed?


Merge: keeper-mjwcc4ik

branch: polecat/keeper-mjwcc4ik
target: main
source_issue: keeper-mjwcc4ik
rig: gastown
agent_bead: gt-gastown-polecat-keeper


Session ended: gt-gastown-coma


Digest: mol-deacon-patrol

Patrol 18: all healthy


Session ended: gt-gastown-refinery


Digest: mol-deacon-patrol

Patrol 15: quick pass


Digest: mol-deacon-patrol

Cycle 8: quiet


Digest: mol-deacon-patrol

Patrol 11: All healthy


Session ended: gt-mayor


Add tests for gt crew restart --all

Add integration tests for the crew restart flow:

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

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

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


Merge: slit-mjxof5ku

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


CLI: workspace commands (init, add, list)

GGT needs workspace management commands beyond install.

## Commands (beyond gt-f9x.3 install)

### gt workspace list
List all rigs in current workspace.
```
gt workspace list [--json]
```
Essentially `gt rig list` but framed as workspace view.

### gt workspace add
Add existing rig to workspace (alternative to gt rig add).
```
gt workspace add <git-url> [--name NAME]
```

### gt onboard
Interactive first-time setup wizard.
```
gt onboard
```
- Prompts for workspace location
- Creates structure via gt install
- Offers to add first rig

## Note
May be redundant with gt-f9x.3 (install) and gt-u1j.16 (rig commands).
Consider if this is needed or should be closed as covered by those.

## PGT Reference
gastown-py/src/gastown/cli/workspace_cmd.py


town handoff command (optional)

CLI commands for session handoff workflow (optional convenience).

## Commands

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

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

## Implementation

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

## Priority

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

## Notes

Part of session cycling workflow designed in [deleted:gt-u82].

Added --collect flag to gt handoff and --handoff flag to gt resume


Digest: mol-deacon-patrol

Patrol cycle 15: All healthy


Digest: mol-deacon-patrol

Patrol #7: Quick cycle, no pending spawns.


Digest: mol-deacon-patrol

Patrol 11


Digest: mol-deacon-patrol

Cycle 6


Digest: mol-deacon-patrol

Patrol 17: healthy


README: Add beads (bd) as prerequisite

CRITICAL: gt calls bd via exec.Command for sling, cook, gate, etc. but beads is not listed in Prerequisites. Users following Quick Start will fail.

Fix:
1. Add 'beads (bd)' to Prerequisites with install link
2. Move Prerequisites section BEFORE Quick Start
3. Add version requirements for each dep

Added beads (bd) to Prerequisites with install link, moved section before Quick Start, added version requirements


Session ended: gt-gastown-crew-jack


Add unit tests for internal/mail router and mailbox

attached_args: Add unit tests for mail router and mailbox

Add tests for mail routing and mailbox functionality.

## Files to create
- internal/mail/router_test.go
- internal/mail/mailbox_test.go

## Test cases for router
1. Route() resolves addresses correctly
2. Route() handles rig/role format
3. Route() handles rig/crew/name format
4. Invalid addresses return error

## Test cases for mailbox
1. Send() writes message to mailbox
2. Inbox() lists messages
3. Read() retrieves message by ID
4. Delete() removes message
5. Messages persist correctly

## Acceptance criteria
- [ ] router_test.go with 4+ tests
- [ ] mailbox_test.go with 5+ tests
- [ ] Tests pass: go test ./internal/mail/...
- [ ] Coverage > 60%


Merge: dinki-mk0ap14g

branch: polecat/dinki-mk0ap14g
target: main
source_issue: dinki-mk0ap14g
rig: gastown
agent_bead: gt-gastown-polecat-dinki
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Digest: mol-deacon-patrol

Patrol 17: All healthy


Swarm status doesn't update after task completions

During swarm bd-784c, the swarm status remained at '9% (1/11 tasks merged)' even after 5 tasks were completed and closed.

**Expected:**
Swarm status should reflect actual completion count, either by:
1. Polling issue status from beads
2. Updating when polecats close issues
3. Updating when commits are pushed to integration branch

**Impact:**
Coordinator had to manually check bd list to know actual progress.

Fixed: Swarm status now reads from BeadsPath() which points to the mayor/rig clone with proper beads sync config. This ensures status reflects git-synced beads data instead of stale local daemon data.


Digest: mol-deacon-patrol

Patrol 153: All healthy, nux respawned


Digest: mol-deacon-patrol

Cycle 6: healthy


Digest: mol-refinery-patrol

Patrol cycle: queue empty, 0 branches merged, no issues


Session ended: gt-gastown-chumbucket


E2E Swarm Test Epic

E2E Test: All tasks complete, swarm landed


Task A: Setup foundation


Task B: First feature


Task C: Second feature


Task D: Integration


Digest: mol-deacon-patrol

Patrol 15


Interactive prompts for destructive operations

Add interactive confirmations for destructive operations.

## Operations Needing Confirmation
- `gt swarm cancel` - Cancels active swarm
- `gt swarm land --force` - Force landing
- `gt polecat decommission` - Removes polecat
- `gt rig remove` - Removes rig
- `gt stop --all` - Stops all sessions
- `gt mail purge` - Permanently deletes mail

## Implementation Options

### Option 1: promptui library
```go
import "github.com/manifoldco/promptui"

prompt := promptui.Prompt{
    Label:     "Delete polecat Toast",
    IsConfirm: true,
}
result, err := prompt.Run()
```

### Option 2: Simple stdin
```go
func confirm(prompt string) bool {
    fmt.Printf("%s [y/N]: ", prompt)
    var response string
    fmt.Scanln(&response)
    return strings.ToLower(response) == "y"
}
```

## Bypass Flags
All confirmations skippable with --force or --yes:
```go
if !force && !confirm("Really cancel swarm?") {
    return nil
}
```

## Acceptance Criteria
- [ ] Destructive ops prompt by default
- [ ] --force or --yes bypasses
- [ ] Clear prompt text explaining action
- [ ] Non-interactive mode (piped input) auto-fails


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


Digest: mol-refinery-patrol

Patrol cycle: checked mail (empty), scanned MR queue (0 open), no branches to merge. All MRs already processed.


Session ended: gt-gastown-dinki


Session ended: gt-gastown-crew-gus


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

## Context

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

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

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

## Background

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

## Investigation Steps

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

## Key Question

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

## Commands

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


Show actor on pinned/status change events

Pinned events currently show no actor:

  [10:22:25] → gt-95j13 → pinned · Add tmux hotkey...

Should show who pinned it:

  [10:22:25] → gt-95j13 → pinned · Add tmux hotkey... @gastown/crew/joe

Part of epic gt-u7dxq

Fixed: Actor now shows on status/pinned events in bd activity. Fix implemented in beads repo branch fix/actor-on-status-events (https://github.com/steveyegge/beads/pull/new/fix/actor-on-status-events). Changes: Added SetActor method to RPC client and called it during daemon connection to pass actor in RPC requests.


Digest: mol-deacon-patrol

Patrol cycle 17: All 6 agents healthy


Human escalation path design

Flesh out the human escalation mechanism for Gas Town errors. Currently: errors mail Mayor, Mayor startup prompts about escalations. Need: structured escalation channel, escalation severity levels, and clear documentation. All edge cases in molecular algebra can write warnings to this channel.

Implemented: gt escalate command with CRITICAL/HIGH/MEDIUM severity, Mayor startup check, escalation beads with audit trail, documentation


gt swarm is implemented but undocumented

internal/swarm/ package is fully implemented with:
- gt swarm create
- gt swarm status
- gt swarm list
- gt swarm land
- gt swarm cancel
- gt swarm start

But no documentation exists for it:
- Not in README
- Not in architecture.md (uses different terminology)
- Not in any role prompts

Either:
1. Document gt swarm as the canonical mechanism
2. Or deprecate it in favor of gt sling

Related to gt-6n13 (competing molecule mechanisms)

Added docs/swarm.md with full swarm documentation and updated reference.md with CLI commands


Session ended: gt-gastown-crew-max


Digest: mol-deacon-patrol

Patrol 92: All healthy


Session ended: gt-gastown-rictus


Session ended: gt-gastown-crew-george


Merge: dementus-mjxofwf6

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


Digest: mol-deacon-patrol

Patrol complete: healthy


Merge: warboy-1767106060799

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


Digest: mol-refinery-patrol

Patrol: queue empty, no merges, 0 messages processed


Create activity aggregator

Component that connects to multiple rig beads daemons and merges their activity into a unified view. Polls GetMutations and GetWorkerStatus from each rig, groups by rig/worker. Handles connection failures gracefully.

BLOCKED BY (Beads rig):
- bd-gqxd: Enrich MutationEvent with title and assignee
- bd-l13p: Add GetWorkerStatus RPC endpoint
- bd-0oqz: Add GetMoleculeProgress RPC endpoint


Digest: mol-deacon-patrol

Patrol cycle 1: All agents healthy. Processed 14 inbox messages, archived status updates. Witness and Refinery running. No orphans, no cleanup needed.


Digest: mol-deacon-patrol

Patrol 208: All nominal


Digest: mol-deacon-patrol

Patrol cycle 15: All agents healthy


Digest: mol-deacon-patrol

Patrol 147: All healthy, 2 polecats working


Session ended: gt-gastown-refinery


Digest: mol-deacon-patrol

Patrol #13: Dog pool healthy, 1 idle.


Day 3.6: Polecat closes steps for activity feed

**REVISED**: Step completion is for visibility, not session control.

Polecats close molecule steps as they complete them:
```bash
# After completing implement step:
bd close <step-bead-id>  # Or: mol step done implement
```

This provides:
1. **Activity feed visibility** - Observers see progress in real-time
2. **Audit trail** - Step completion timestamps in beads
3. **Stuck detection** - Witness can see 'long time on same step'

What this does NOT do:
- Trigger session recycle (polecat self-manages)
- Block next step (polecat continues immediately)
- Require Witness intervention

Implementation options:
- Option A: Polecat runs `bd close <step-id>` manually
- Option B: Formula `on_complete` hook auto-closes step bead
- Option C: `mol step done <step>` convenience command

Priority lowered: Nice-to-have for visibility, not launch-blocking.

**Dependency removed**: No longer depends on gt-zb0io (recycle between steps).


Add gt mail announces command to list and read bulletin boards

Add announces subcommand to internal/cmd/mail.go.

COMMANDS:
1. gt mail announces - list available announce channels
2. gt mail announces <channel> - read messages from channel

BEHAVIOR for 'gt mail announces':
- Load messaging.json
- List all announce channel names
- Show reader count for each

BEHAVIOR for 'gt mail announces <channel>':
- Validate channel exists
- Query beads for messages with announce_channel=<channel>
- Display in reverse chronological order
- Do NOT mark as read or remove

FILE: internal/cmd/mail.go
ADD: announcesCmd as subcommand of mailCmd

TESTS: Add TestMailAnnounces

Implemented gt mail announces command with list and read channel functionality


Digest: mol-deacon-patrol

Patrol cycle 11: all healthy


Digest: mol-deacon-patrol

Patrol cycle 20: All 3 rigs healthy. No incidents. Handoff threshold reached.


Digest: mol-deacon-patrol

Patrol cycle 62: All healthy, no issues


Digest: mol-deacon-patrol

Patrol 15: Routine


Merge: capable-mjtltnm5

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


Merge: valkyrie-mjw71b7u

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


Session ended: gt-gastown-corpus


Digest: mol-deacon-patrol

Patrol cycle 1: All 3 rigs healthy, 6 agents pinged, no incidents, inbox clean


Merge: dementus-1767087772272

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


Fix template syntax in code-review.formula.toml (Handlebars vs Go)

code-review.formula.toml uses Handlebars syntax ({{#if}}, {{#each}}) but Go text/template uses {{if}}, {{range}}. Either switch to Go template syntax or implement a Handlebars-compatible template engine.

Converted Handlebars syntax to Go text/template syntax in code-review.formula.toml


Digest: mol-deacon-patrol

Patrol cycle 57: All healthy


Session ended: gt-refinery


gt status: check daemon health first, attempt restart

If daemon not running, attempt to start it. If start fails, show warning but don't block status display. Currently falls back to slow direct mode silently.

Implemented bd daemon health check in gt status


Digest: mol-deacon-patrol

Patrol cycle 12: All healthy


Remove dead code: splitLines first loop, unused methods.

## Dead code locations

### 1. internal/cmd/polecat.go (lines 1093-1106)
splitLines function has unreachable first loop:
```go
func splitLines(s string) []string {
    var lines []string
    for _, line := range filepath.SplitList(s) {  // DEAD: wrong function
        ...
    }
    lines = nil  // Discards above
    for _, line := range strings.Split(s, "\n") {  // This is what runs
        lines = append(lines, line)
    }
    return lines
}
```
**Fix:** Remove first loop and reset.

### 2. internal/townlog/logger.go (lines 277-279)
```go
func (e Event) JSON() ([]byte, error) {
    return json.Marshal(e)
}
```
**Fix:** Remove unused method.

### 3. internal/lock/lock.go (line 27)
```go
ErrStaleLock = errors.New("stale lock detected")
```
**Fix:** Remove unused error variable.

### 4. internal/witness/types.go (line 19)
```go
StatePaused State = "paused"
```
**Fix:** Remove unused state constant.

### 5. internal/refinery/manager.go (lines 527-538)
```go
func (m *Manager) getTestCommand() string { ... }
```
**Fix:** Remove unused method.

## Acceptance criteria
- [ ] polecat.go: Dead loop removed from splitLines
- [ ] townlog/logger.go: Event.JSON() method removed
- [ ] lock/lock.go: ErrStaleLock removed
- [ ] witness/types.go: StatePaused removed
- [ ] refinery/manager.go: getTestCommand removed
- [ ] go build ./... passes
- [ ] go test ./... passes


Merge: capable-1767084028536

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

Conflicts with main - mrqueue package was removed. Notified capable to rebase.


Digest: mol-deacon-patrol

Patrol 69: Routine


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.

Fixed in cf03343 - added push verification to gt mq submit


Day 2.4: Add timeout fallback for dead agents

For truly dead agents that can't report their own death:
- Daemon tracks last_seen timestamp from heartbeats
- If no heartbeat for N minutes AND state=running, mark state=dead
- This is fallback only, not primary state source

Parent: gt-d0jqp


Merge: chumbucket-mk0ao4ek

branch: polecat/chumbucket-mk0ao4ek
target: main
source_issue: chumbucket-mk0ao4ek
rig: gastown
agent_bead: gt-gastown-polecat-chumbucket
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Session ended: gt-gastown-crew-gus


Add missing hq-dog-role to initTownAgentBeads

The initTownAgentBeads() function in install.go creates role beads for Mayor, Deacon, Witness, Refinery, Polecat, Crew but is missing Dog role bead (hq-dog-role).

Add DogRoleBeadIDTown() to the roleDefs slice.

Already implemented and merged in b7d82c72


Session ended: gt-gastown-crew-joe


CLI: cleanup commands for stale state

Cleanup commands for recovering from stale state.

## Commands

### gt cleanup <polecat>
Clean stale state for specific polecat.
```
gt cleanup <rig>/<polecat> [--dry-run]
```

Actions:
- Remove orphaned state.json if clone missing
- Clear stale session references
- Reset stuck state (working → idle after timeout)

### gt cleanup --all
Clean all polecats in workspace.
```
gt cleanup --all [--dry-run]
```

## Implementation
```go
func CleanupPolecat(rigName, polecatName string, dryRun bool) (*CleanupResult, error)

type CleanupResult struct {
    OrphanedStateRemoved bool
    SessionsCleared      int
    StateReset           bool
    Warnings             []string
}
```

## Overlap with Doctor
- Doctor diagnoses and offers --fix
- Cleanup is more aggressive state recovery
- Consider merging into doctor --fix

## New File
internal/cmd/cleanup.go

## Acceptance Criteria
- [ ] Removes orphaned state files
- [ ] Clears stale session refs
- [ ] --dry-run shows what would happen
- [ ] Reports all actions taken


Change session naming from gt-{town}-{role} to gt-{role}-{town}

REVISED: Revert PR #70 entirely.

After discussion, multi-town on one machine isn't a real use case:
- Rigs provide project isolation within a town
- True isolation should use containers/VMs
- The complexity tax isn't worth it for edge cases

Solution: Revert to simple gt-mayor and gt-deacon (no town qualifier).
If someone tries to run a second town's mayor, they get a collision error.
This is honest about the architecture: one town per machine.

Already completed in commit 4bcf50bf (Revert to simple gt-mayor/gt-deacon session names) which is on main


Digest: mol-deacon-patrol

Patrol 3: quiet, health OK


Merge: rictus-mjxofiub

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


Digest: mol-deacon-patrol

Patrol cycle 3: All infrastructure healthy. 3 Witnesses running, 3 Refineries running. Town idle.


Code review swarm: recent merges


Merge: nux-mk0uimp8

branch: polecat/nux-mk0uimp8
target: main
source_issue: nux-mk0uimp8
rig: gastown
agent_bead: gt-gastown-polecat-gus
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Merge: rictus-mjxc967h

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


Session test no rig


list: static mailing list lookup

Static mailing list support via config file.

## Deliverables

1. Load lists from ~/gt/config/lists.json
2. Parse list:name syntax in router
3. Fan-out at send time (same as @group)
4. Error handling for unknown list names

## Example
```bash
gt mail send list:oncall -s "Alert" -m "System down"
# Expands to: mayor/, gastown/witness, beads/witness
# Creates 3 message copies
```

## Dependencies
- Config directory (gt-i6jvc)

## Acceptance
- list:oncall resolves to configured members
- Each member gets own message copy
- Unknown list returns clear error

Implemented static mailing list support with list:name syntax


Digest: mol-deacon-patrol

Patrol cycle 6: all healthy


Session ended: gt-gastown-blackfinger

Bulk cleanup of stale session-ended events (gt-8tc1v)


Session ended: gt-gastown/crew/joe


Plugin surface for daemon lifecycle hooks

Allow rigs to customize daemon behavior via hooks/plugins.

## Hook Points

- on_heartbeat: Called during daemon heartbeat cycle
- on_worker_idle: Called when worker goes idle
- on_worker_stuck: Called when stuck detection triggers
- on_lifecycle_request: Called before processing lifecycle

## Configuration

```
<rig>/config/daemon-hooks.json
{
  "on_heartbeat": "./hooks/check-ci-status.sh",
  "on_worker_idle": "./hooks/maybe-assign-work.sh",
  "idle_threshold": "5m",
  "custom_signals": [
    {"name": "ci_status", "command": "./hooks/get-ci.sh"}
  ]
}
```

## Signal Contribution

Hooks can return signals that feed into decision engine:
- SKIP_POKE: Don't poke this agent
- FORCE_POKE: Override backoff, poke now
- CUSTOM_DATA: Extra context for logging

## Use Cases

- Check CI status before interrupting test runs
- Auto-assign work when worker becomes idle
- Custom stuck detection for specific workflows


Digest: mol-deacon-patrol

Patrol 11: quiet


Digest: mol-deacon-patrol

Patrol 147 complete


Merge: furiosa-dogs

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


Digest: mol-deacon-patrol

Patrol 18: quick pass


Digest: mol-deacon-patrol

Patrol 7: Quiet


Digest: mol-deacon-patrol

Patrol cycle 14: All healthy.


Merge: cheedo-mjw70xce

branch: polecat/cheedo-mjw70xce
target: main
source_issue: cheedo-mjw70xce
rig: gastown
agent_bead: gt-gastown-polecat-cheedo


Digest: mol-deacon-patrol

Patrol 4: all clear


Polecat hook not cleared after work completion

## Problem

When a polecat completes work (bead closed, branch merged), the hook is not cleared. This prevents automatic cleanup because `gt polecat nuke` sees work still hooked and refuses to nuke without --force.

## Evidence

After work merged:
```
$ gt polecat nuke gastown/chumbucket
Error: Cannot nuke:
  - has work on hook (gt-bc6gm)
```

But gt-bc6gm is closed:
```
$ bd show gt-bc6gm
Status: closed
```

## Expected Behavior

When `gt done` or merge completion occurs:
1. Close the bead ✓
2. Clear the hook ✗ (missing)
3. Update polecat state ✓

## Fix

In the completion flow (gt done / witness merge handler):
- Call hook clear after bead close
- Or: nuke should check bead status, not just hook presence

Fixed: bd slot commands now use rig path instead of town root


Digest: mol-deacon-patrol

Patrol cycle 11: All 6 agents healthy


Merge: furiosa-1767081103575

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


Digest: mol-deacon-patrol

Patrol 4: Routine


GAP: Deacon patrol needs stale hooked bead cleanup

The deacon patrol mol-deacon-patrol does not have a step to clean up stale hooked beads.

During shutdown cleanup, found:
- Handoff beads stuck in hooked status after processing
- Template beads (hq-1lit, hq-5vu, etc.) perpetually hooked

Proposed addition to patrol:
1. Query for beads with status=hooked older than X hours
2. For handoffs: Close them (they were processed)
3. For templates: Reset to appropriate status
4. Log cleanup actions

This should be a backstop - the primary fix is ensuring hooked status is cleared after processing.

Implemented gt deacon stale-hooks command and added step to patrol formula


Session ended: gt-gastown-prime


Digest: mol-deacon-patrol

Patrol 32: all quiet


Digest: mol-deacon-patrol

Patrol 10


Digest: mol-deacon-patrol

Patrol 13


Digest: mol-deacon-patrol

Patrol 220: All nominal - handing off after 20 cycles


Digest: mol-deacon-patrol

Patrol cycle 9: all healthy


Merge: nux-mjxn8p5t

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


Error handling improvements: retry logic and recovery hints

Improve error handling across GGT codebase.

## Issues Found

### 1. Silent Failures in Refinery
manager.go ProcessMR():
- git pull errors ignored
- Continues processing even on partial failures

### 2. Missing Beads CLI
Many operations silently continue if `bd` not found:
```go
// Current
tasks, err := m.loadTasksFromBeads(epicID)
if err != nil {
    // Non-fatal - swarm can start without tasks
}

// Better
if err != nil {
    return nil, fmt.Errorf("beads required: %w", err)
}
```

### 3. No Retry Logic
Network/lock errors should retry:
```go
func withRetry(attempts int, delay time.Duration, fn func() error) error {
    for i := 0; i < attempts; i++ {
        if err := fn(); err == nil {
            return nil
        }
        time.Sleep(delay)
    }
    return fmt.Errorf("failed after %d attempts", attempts)
}
```

### 4. Recovery Hints
Error messages should include fix suggestions:
```go
// Current
return fmt.Errorf("polecat not found")

// Better
return fmt.Errorf("polecat '%s' not found. Use 'gt polecat list' to see available polecats", name)
```

## Domain Error Types
```go
type SessionError struct {
    Op      string
    Polecat string
    Err     error
}

func (e *SessionError) Error() string {
    return fmt.Sprintf("session %s for %s: %v", e.Op, e.Polecat, e.Err)
}
```

## Files to Review
- internal/refinery/manager.go
- internal/swarm/manager.go
- internal/session/manager.go
- All cmd/*.go files

## Acceptance Criteria
- [ ] No silent error swallowing
- [ ] Retry logic for transient failures
- [ ] Helpful error messages with hints
- [ ] Consistent error types per domain


Digest: mol-deacon-patrol

Patrol 3: all healthy


Digest: mol-deacon-patrol

Patrol cycle 79: All healthy


Digest: mol-deacon-patrol

Patrol 124: All healthy


Remove gt polecat done/reset/finish commands (idle producers)

## Problem

Commands exist that transition polecats to idle state, violating the transient model.

From PRIMING.md: "Polecats exist only while working. One task, then nuked."

## Heretical Commands

1. gt polecat done - "Mark polecat as done with work and return to idle"
2. gt polecat reset - "Force reset polecat to idle state"
3. gt polecat finish - alias for done
4. gt polecat sleep - deprecated but still exists

## Confusion with gt done

Two commands with similar names but different semantics:
- gt done (correct): Push branch, create MR, signal Witness for nuke
- gt polecat done (heresy): Transition to idle, sandbox stays

## Correct Model

Polecats should only use gt done (or gt handoff which calls gt done).
The Witness handles sandbox destruction. There is no "return to idle" - only death.

## Changes Required

1. Remove gt polecat done command
2. Remove gt polecat reset command
3. Remove gt polecat finish alias
4. Remove gt polecat sleep (already deprecated)
5. Remove manager.Finish() and manager.Reset() methods
6. Update any callers to use proper lifecycle (gt done -> Witness nuke)


Digest: mol-deacon-patrol

Patrol cycle 19: all healthy


Session ended: gt-gastown-crew-max


Digest: mol-deacon-patrol

Patrol 1: inbox clear, witness/refinery healthy, no orphans, no plugins


Wire polecat-CLAUDE.md template into polecat spawn

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

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

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


Merge: fury-mk0vskad

branch: polecat/fury-mk0vskad
target: main
source_issue: fury-mk0vskad
rig: gastown
agent_bead: gt-gastown-polecat-gus
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Plugin: plan-oracle (work decomposition)

Plugin that helps decompose epics/issues into sub-tasks. Analyzes scope, identifies dependencies, estimates complexity for parallelization, creates beads for sub-tasks with dependency links.


Digest: mol-deacon-patrol

Patrol cycle 4: All 6 agents healthy


Digest: mol-deacon-patrol

Patrol 143: 2 polecats (nux, rictus) working on formula tasks, all healthy


Digest: mol-deacon-patrol

Patrol 128: All healthy


Digest: mol-deacon-patrol

Patrol 3: all healthy, mayor running, witnesses running


Session ended: gt-gastown-prime


Digest: mol-deacon-patrol

Cycle 198: Nominal


Feed daemon: curate raw events into user-facing feed

Goroutine in gt daemon that transforms raw events into curated activity feed.

## Input
- Tails ~/gt/.events.jsonl (raw events from gt, bd, agents)

## Output
- Writes ~/gt/.feed.jsonl (curated, user-facing)

## Processing
1. Filter by visibility tag (drop audit-only events)
2. Dedupe repeated updates (5 molecule updates → "agent active")
3. Aggregate related events (3 issues closed → "batch complete")
4. Future: AI summarization via haiku for complex activity

## Integration
- Runs as goroutine in existing gt daemon
- Starts when daemon starts
- Graceful shutdown on daemon stop

Part of epic gt-u7dxq

Implemented feed curator goroutine in gt daemon that tails .events.jsonl, filters by visibility, deduplicates repeated events, aggregates related events, and writes curated feed to .feed.jsonl


Merge: gt-xqh3y

branch: polecat/eli-mjufuh2g
target: main
source_issue: gt-xqh3y
rig: gastown


Session ended: gt-gastown-crew-george


Day 2.1: Daemon reads agent bead state field

Daemon queries agent beads for state instead of inferring from PID/tmux.

Change getAgentState() to:
1. Look up agent bead by ID (gt-mayor, gt-witness, etc.)
2. Read state field (idle|running|stuck|stopped)
3. Trust the value

Parent: gt-d0jqp


Session ended: gt-refinery


Merge: rictus-mjw3nj1a

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


Session ended: gt-gastown-nux


Digest: mol-deacon-patrol

Cycle 15


Overhaul autonomous-mode guidance with ledger/capability framing

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

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

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

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

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

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

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

Implemented ledger/capability framing in all role templates and prime.go. Also fixed hooked/pinned terminology confusion. Filed gt-d9smb for gt mol status output fix.


Digest: mol-deacon-patrol

Patrol 14: routine


Digest: mol-deacon-patrol

Cycle 9


Review PR #44: docs: Fix Quick Start to use gt mayor attach

Review and approve/request changes for PR #44. Check docs accuracy. If good, approve with gh pr review --approve.


Test Patrol for Bonding

Parent issue for mol bond CLI test


Default polecat names: Mad Max theme instead of AdjectiveNoun

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

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

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

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


Merge: furiosa-1767059690595

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

Stale merge requests - branches no longer exist


Digest: mol-deacon-patrol

Cycle 12


Digest: mol-deacon-patrol

Patrol #15: All healthy


Merge: capable-1767074169502

attached_args: Code review this merge request

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

STALE: Branch polecat/capable-1767074169502 no longer exists. The underlying work (gt-594a4 BeadsPath fix) was already merged to main via commit e362be3c at 23:43. This merge request was orphaned.


Merge: vuvalini-mk0frc7r

branch: polecat/vuvalini-mk0frc7r
target: main
source_issue: vuvalini-mk0frc7r
rig: gastown
agent_bead: gt-gastown-polecat-vuvalini
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Overseer inbox for strategic notifications

New address overseer/ for strategic notifications.

Receives:
- Convoy completions
- Cross-rig dependency resolutions
- Escalations from Deacon
- Daily digests (optional)

Separate from operational mail - this is the executive dashboard.

Related: hq-7h8jx (Convoy System epic in town beads)


Session ended: gt-gastown-crew-george


Digest: mol-deacon-patrol

Patrol cycle 7: All 3 rigs healthy. No incidents.


Mail orchestrator daemon

Background mail orchestrator daemon.

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

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

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

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

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

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

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

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


Session ended: gt-gastown-crew-max


Merge: rockryder-mk0frt3g

branch: polecat/rockryder-mk0frt3g
target: main
source_issue: rockryder-mk0frt3g
rig: gastown
agent_bead: gt-gastown-polecat-rockryder
retry_count: 0
last_conflict_sha: null
conflict_task_id: null


Merge: toast-1767081120579

branch: polecat/toast-1767081120579
target: main
source_issue: toast-1767081120579
rig: gastown


Session ended: gt-gastown-refinery


Digest: mol-deacon-patrol

Patrol 2: all healthy, no callbacks


Session ended: gt-gastown-ace


Digest: mol-deacon-patrol

Patrol 207: All nominal


Session ended: gt-gastown-vuvalini


Consider TownBeadsPrefix constant for hq- prefix

The 'hq' prefix string is used in multiple places in agent_ids.go. Consider adding a constant:

const TownBeadsPrefix = "hq"

This would make prefix changes easier and reduce string duplication.

Already completed: TownBeadsPrefix constant exists at agent_ids.go:8 and is used throughout the file. Commit 948986b4 implemented this.


Witness Patrol

Per-rig worker monitor patrol loop with progressive nudging.

Duplicate patrol molecule beads - keeping gt-t5i07, gt-8ynws, gt-kt9qq


Digest: mol-deacon-patrol

Patrol 8: quick pass


Digest: mol-deacon-patrol

Patrol 20 complete


Close PR #145 - superseded by heresy correction

PR #145 (polecat completion protocol with push step) is a workaround for the push requirement.

Once heresy correction is complete, PR #145 becomes obsolete - close it with explanation that local-only branches eliminate the need for explicit push instructions.


Digest: mol-deacon-patrol

Patrol 137: All healthy


Digest: mol-deacon-patrol

Patrol cycle 17: All healthy.


Digest: mol-deacon-patrol

Patrol 63: Routine, all healthy


Session ended: gt-gastown-buzzard


Digest: mol-deacon-patrol

Patrol complete: all agents healthy, cycling at 20 patrols


Merge: furiosa-mjw17xzd

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

Stale MR - branch has no new commits or doesn't exist


Digest: mol-deacon-patrol

Cycle 293: All healthy, no incidents


Digest: mol-deacon-patrol

Patrol cycle 5: All 3 rigs healthy. No incidents.


Digest: mol-deacon-patrol

Patrol 34: all quiet


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

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


Implement gt watch command scaffold

Basic bubbletea TUI scaffold for 'gt watch' command. Discovers rigs, connects to daemons, renders placeholder view. Foundation for the full activity feed TUI.


gt feed: Activity feed command with tmux-aware modes

## Context

`bd activity` exists and works well for streaming beads mutation events. However:
- It's not discoverable via `gt` (the agent coordination CLI)
- No tmux-aware behavior for when Gas Town is running in tmux
- The planned TUI (gt-rivr) was tombstoned - need a simpler approach

## Requirements

### Without tmux (standalone mode)
- `gt feed` streams activity to stdout (like `bd activity --follow`)
- Supports filtering by rig, time window, event type
- Works in any terminal

### With tmux (integrated mode)
- Could open/attach to a dedicated activity pane
- Or provide a way to send feed to a specific pane
- Integrate with existing gt tmux session management

## Design Questions

1. **Command name**: `gt feed` vs `gt activity` vs `gt watch`?
2. **Tmux integration**: Dedicated pane? Split? Popup?
3. **Cross-rig aggregation**: Merge events from multiple rig daemons?
4. **Filtering UX**: By rig, by molecule, by event type?

## Implementation Options

**Phase 1: Simple wrapper**
- `gt feed` shells out to `bd activity --follow`
- Add `--rig` flag for filtering
- Works identically with/without tmux

**Phase 2: Tmux-aware**
- Detect if running in gt tmux session
- Offer to open in dedicated pane
- `gt feed --pane` to force pane mode

**Phase 3: Cross-rig** (if needed)
- Aggregate from multiple rig daemons
- Unified activity stream across town

## Related

- gt-rivr (tombstoned) - Original TUI epic
- gt-22ng - Activity aggregator (blocked)
- bd activity command - The underlying implementation


Digest: mol-deacon-patrol

Cycle 188: Nominal


Dead Code: Unused parameter in mail/router.go resolveBeadsDir

The resolveBeadsDir function (router.go:187) has an unused parameter:

```go
func (r *Router) resolveBeadsDir(_ string) string { // address unused: all mail uses town-level beads
```

The comment explains that the address parameter was previously used for routing but is now unused since all mail uses town-level beads.

Options:
1. Remove the parameter entirely
2. If backward compatibility is needed, mark as deprecated

Files:
- internal/mail/router.go:187

Severity: low


Digest: mol-deacon-patrol

Patrol cycle 10: all healthy


Day 3.0: Document mail protocol contracts

Document the formal mail protocol for Gas Town agent coordination.

Mail Types:

**POLECAT_DONE** (polecat → witness)
```
Subject: POLECAT_DONE: <name>
Body: {"issue": "gt-xyz", "status": "complete|failed", "notes": "..."}
```

**MERGE_READY** (witness → refinery)
```
Subject: MERGE_READY: <branch>
Body: {"worker": "nux", "issue": "gt-xyz", "branch": "polecat/nux/gt-xyz"}
```

**MERGED** (refinery → witness)
```
Subject: MERGED: <branch>
Body: {"issue": "gt-xyz", "sha": "abc123", "worker": "nux"}
```

**LIFECYCLE:Shutdown/Cycle/Restart** (agent → deacon/)
```
Subject: LIFECYCLE:Shutdown
Body: {"action": "shutdown"}
```

**HELP** (polecat → witness → mayor)
```
Subject: HELP: <brief>
Body: {"issue": "gt-xyz", "problem": "...", "context": "..."}
```

Create: docs/mail-protocol.md


Merge: immortan-mjwlaw9o

branch: polecat/immortan-mjwlaw9o
target: main
source_issue: immortan-mjwlaw9o
rig: gastown
agent_bead: gt-gastown-polecat-immortan


Digest: mol-deacon-patrol

Patrol cycle 13: All healthy


Add nudge_channels to MessagingConfig schema

Extend MessagingConfig in internal/config/types.go.

ADD TO MessagingConfig STRUCT:
    // NudgeChannels are named groups for real-time nudge fan-out.
    // Like mailing lists but for tmux send-keys instead of durable mail.
    NudgeChannels map[string][]string `json:"nudge_channels,omitempty"`

UPDATE NewMessagingConfig():
    Add: NudgeChannels: make(map[string][]string)

UPDATE ValidateMessagingConfig() in loader.go:
    Validate that nudge channel names are non-empty
    Validate that each channel has at least one recipient

FILE: internal/config/types.go, internal/config/loader.go
TESTS: Add to loader_test.go following existing patterns

Example config:
{
  "nudge_channels": {
    "workers": ["gastown/polecats/*", "gastown/crew/*"],
    "witnesses": ["*/witness"]
  }
}

Added NudgeChannels field to MessagingConfig with validation and tests


Merge: gt-bpiph

branch: polecat/toast-mjtm1hg8
target: main
source_issue: gt-bpiph
rig: gastown


Merge: slit-mjtj9dc8

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


Session ended: gt-gastown-bullet


Digest: mol-deacon-patrol

Patrol 8: All healthy


Add nudge channels for real-time fan-out messaging

Add channel support to gt nudge for real-time fan-out.

## Semantics
- Ephemeral, real-time (tmux send-keys)
- Fan-out to all channel members
- Parallel to list:name but for nudge instead of mail

## Use Case
"Everyone send yourself gt handoff now" - real-time coordination.

## Syntax
gt nudge channel:workers "gt handoff"
gt nudge channel:witnesses "Swarm incoming"

## Implementation
1. Add nudge_channels to MessagingConfig schema
2. Extend gt nudge to recognize channel:name syntax
3. Expand channel to member list, nudge each

## Config Addition to messaging.json
```json
"nudge_channels": {
  "workers": ["gastown/polecats/*", "gastown/crew/*"],
  "witnesses": ["*/witness"],
  "all": ["@town", "@rig/*"]
}
```

## Relation to gt broadcast
gt broadcast is a one-off "everyone" nudge.
Nudge channels are named, configured subsets.

Could potentially deprecate gt broadcast in favor of:
gt nudge channel:all "message"


Session ended: gt-gastown-imperator


Digest: mol-deacon-patrol

Patrol 2: all healthy, beads swarm active


Digest: mol-deacon-patrol

Patrol complete: 17 Claude procs, 3 witnesses, 2 refineries healthy. 2 convoys open. No orphans, no cleanup needed. Inbox empty.


Merge: slit-1767080431456

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


Wisp config storage layer

dispatched_by: mayor

Implement wisp-based config storage for transient/local settings.

Storage: .beads-wisp/config/<rig>.json
Format:
{
  "rig": "gastown",
  "values": { "status": "parked", ... },
  "blocked": ["auto_restart", ...]
}

API:
- wispConfig.Get(key) - returns value or nil
- wispConfig.Set(key, value)
- wispConfig.Block(key) - NullValue equivalent
- wispConfig.Unset(key)
- wispConfig.IsBlocked(key)

Never synced via git - local to this town only.

Implemented wisp config storage layer with Get, Set, Block, Unset, IsBlocked API


Remove vestigial state.json files from agent directories

Agent directories (witness/, refinery/, etc.) contain state.json files with last_active timestamps that are never updated. These are stale/vestigial and misleading.

Example: ~/gt/gastown/witness/state.json shows last_active Dec 19th while witness has been running daily.

Task:
1. Remove state.json files from agent directories
2. Remove any code that creates/reads these files
3. Verify no dependencies on this state

Removed vestigial state.json files from agent directories and related dead code


Phase 4.2: Witness/Refinery patrol molecules

Extend ephemeral patrol pattern to Witness and Refinery.

## Witness Patrol Cycle

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

## Refinery Patrol Cycle

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

## Quiescent Mode

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


Phase 5.2: Ephemeral error handling and recovery

Handle edge cases in ephemeral molecule lifecycle.

## Scenarios

### Agent dies mid-molecule
- Ephemeral state persists
- Witness detects stall (no heartbeat)
- Options:
  a. Nudge agent to resume
  b. Reassign to new agent
  c. Escalate to Mayor

### Squash fails
- Retry with exponential backoff
- If persistent failure, escalate
- Don't lose the ephemeral state until squash succeeds

### Orphaned molecules
- Molecule started, never completed
- gt doctor detects (>24h old with no activity)
- Options:
  a. Manual review
  b. Auto-abandon with 'abandoned' digest
  c. Reassign

### Ephemeral repo corruption
- Re-init from scratch
- Active molecules are lost
- Main beads is source of truth for assigned work

## Implementation

Add error handling to:
- bd mol bond (handle init failures)
- bd squash (retry logic)
- gt doctor (recovery suggestions)


Agent monitoring and status inference

Agent monitoring with status inference from activity, like PGT.

## Agent Status Enum
```go
type AgentStatus string
const (
    StatusAvailable AgentStatus = "available"
    StatusWorking   AgentStatus = "working"
    StatusThinking  AgentStatus = "thinking"
    StatusBlocked   AgentStatus = "blocked"
    StatusWaiting   AgentStatus = "waiting"
    StatusReviewing AgentStatus = "reviewing"
    StatusIdle      AgentStatus = "idle"
    StatusPaused    AgentStatus = "paused"
    StatusError     AgentStatus = "error"
    StatusOffline   AgentStatus = "offline"
)
```

## Status Sources (priority order)
```go
type StatusSource string
const (
    SourceBossOverride StatusSource = "boss"      // Witness/Mayor sets
    SourceSelfReported StatusSource = "self"      // Agent reports own status
    SourceInferred     StatusSource = "inferred"  // Detected from activity
)
```

## Activity Detection

### Pattern Registry
```go
var activityPatterns = []struct {
    Pattern string
    Status  AgentStatus
}{
    {"Thinking...", StatusThinking},
    {"BLOCKED:", StatusBlocked},
    {"Error:", StatusError},
    // etc
}
```

### Idle Detection
No pane output for N seconds → StatusIdle

### Resource Monitoring (optional)
CPU/memory via os.Process

## New Package
internal/monitoring/
├── types.go      # AgentStatus, StatusReport
├── detector.go   # PatternRegistry, detect from output
├── tracker.go    # Per-agent status tracking
└── idle.go       # Idle timeout detection

## Integration
- Session capture output → monitoring detector
- Status shown in gt status, gt session list

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

## Acceptance Criteria
- [ ] Status enum with 10 states
- [ ] Pattern-based detection from pane output
- [ ] Idle detection with configurable timeout
- [ ] Status visible in CLI output


Digest: mol-deacon-patrol

Patrol 57: All healthy


Digest: mol-deacon-patrol

Patrol 146: All healthy, new furiosa spawn


Digest: mol-deacon-patrol

Patrol 6: All healthy


Add pre-flight test check to mol-polecat-work

Add a step early in mol-polecat-work (after branch-setup, before implement) to check if tests pass on main.

## Problem
If main is broken when polecat starts, they could:
- Waste context trying to fix unrelated issues
- Not know if their changes broke things or it was pre-existing
- Get blamed for failures they didn't cause

## Proposed Step: preflight-tests

After branch-setup, before implement:

1. Checkout main temporarily
2. Run test suite
3. If tests PASS: Continue to implement
4. If tests FAIL:
   - Quick fix (<15 min): Fix it, commit to main, then continue
   - Big fix: File bead, mail Witness, proceed with own work
   - Use ZFC judgment - you're there, you decide

## Handoff Consideration
If fixing pre-existing failures consumes significant context:
- Commit the fix
- gt handoff with note: 'Fixed pre-existing test failures, continuing with assigned work'
- Fresh session picks up from implement step

## Key Principle
Scotty Test: Don't walk past a broken warp core. But also don't let someone else's mess derail your mission entirely.


SessionStart hook should pass session_id to gt prime

## Context

The seance discovery system relies on session_start events emitted by gt prime.
Currently, gt prime falls back to actor-PID when CLAUDE_SESSION_ID is not set.

## Enhancement

The SessionStart hook receives session_id in its stdin JSON:
```json
{
  "session_id": "abc123",
  "transcript_path": "...",
  "source": "startup|resume|clear|compact"
}
```

The hook should parse this and pass it to gt prime via environment variable:
```bash
SESSION_ID=$(cat /dev/stdin | jq -r ".session_id")
CLAUDE_SESSION_ID=$SESSION_ID gt prime
```

## Benefits

- Accurate session tracking for seances
- Can resume exact sessions via `claude --resume <id>`
- Events correlate with Claude Code session history

## Implementation

1. Update SessionStart hook in CLAUDE.md templates
2. Have gt prime read CLAUDE_SESSION_ID env var (already done)
3. Emit proper session_id in session_start events

Related: gt-7qvd7 (seance implementation)

Created ~/.claude/hooks/session-start.sh to parse session_id from stdin JSON and pass it to gt prime via CLAUDE_SESSION_ID. Updated SessionStart hooks in all settings.json files across town.


Session ended: gt-gastown-crew-jack


Digest: mol-deacon-patrol

Patrol 255 complete: no incidents


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.

Fixed in commit 275f3026: loadFromBeads now checks agent bead hook_bead field


Add -m flag to gt nudge command

Currently gt nudge requires positional args: gt nudge <target> <message>

Add -m flag support for consistency with other commands:
  gt nudge beads/crew/emma -m "Please do a handoff"

The message should still work as positional arg for backwards compatibility.


Merge: cheedo-mjxpd9go

branch: polecat/cheedo-mjxpd9go
target: main
source_issue: cheedo-mjxpd9go
rig: gastown
agent_bead: gt-gastown-polecat-cheedo


Digest: mol-deacon-patrol

Patrol 12


Digest: mol-deacon-patrol

Patrol 249 complete: no incidents


Digest: mol-deacon-patrol

Patrol 7: Routine


Polecat session checkpoint for crash recovery

When polecat session dies, all context is lost.

## Problem
- Session dies (context limit, crash, timeout)
- No record of what files were modified
- No checkpoint of molecule step progress
- Next session has to rediscover state

## Fix
Periodic checkpoint during work:
1. Every N minutes, or on molecule step completion
2. Write checkpoint file: `.polecat-checkpoint.json`
   - Current molecule step
   - Modified files list
   - Last commit SHA
   - Timestamp
3. On session restart, read checkpoint
4. Resume from checkpoint state

## Checkpoint Format
```json
{
  "molecule_id": "mol-xxx",
  "current_step": "gt-abc.2",
  "modified_files": ["internal/foo/bar.go"],
  "last_commit": "abc123",
  "timestamp": "2025-12-30T18:00:00Z"
}
```

Implemented checkpoint system for crash recovery. Added internal/checkpoint package and gt checkpoint command (write/read/clear). Checkpoint context is shown during gt prime startup.


Digest: mol-deacon-patrol

Patrol 30: all quiet


Digest: mol-deacon-patrol

Patrol 11: All clear


Digest: mol-deacon-patrol

Patrol 121: All agents healthy, no incidents


Session ended: gt-gastown-crew-gus


Session ended: gt-gastown-bullet-farmer


Pillar 3: Polecat Lifecycle

Session-per-step model with automated recycle/nuke.

Key deliverables:
- gt polecat recycle <name> - kill session, preserve sandbox
- gt polecat nuke <name> - kill everything
- Witness calls recycle between molecule steps
- Refinery calls nuke after merge

Subsumes existing work:
- gt-budeb: Witness auto-nuke polecats after merge
- gt-1dbcp: Polecat auto-start nudge fix

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

Parent: gt-oki8p


Digest: mol-deacon-patrol

Patrol 40: all quiet


Merge: slit-1767138831931

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


Session ended: gt-gastown-crew-jack


Digest: mol-deacon-patrol

P18: stable


Merge: toast-mjxpchjl

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


Digest: mol-deacon-patrol

Patrol complete: checked inbox (0 msgs), health check passed (all rigs healthy), cleaned 3 stale locks


Digest: mol-deacon-patrol

Patrol 151: All healthy


Digest: mol-deacon-patrol

Patrol #1: All witnesses/refineries running (beads, gastown, wyvern). 1 dog idle. No convoys, no gates, no pending spawns. Clean cycle.


Improve looksLikeFormulaName heuristic in mol_bond

The looksLikeFormulaName() function in mol_bond.go uses simple heuristics that could have edge cases:

Current checks:
- starts with 'mol-'
- contains '.formula'
- contains path separators

Potential improvements:
- Check if operand matches issue ID format (prefix-hash pattern)
- Consider formula search paths when determining if something could be a formula
- Add --formula flag to explicitly mark an operand as a formula name

Low priority since edge cases are rare in practice.


Digest: mol-deacon-patrol

Patrol 19: healthy


Session ended: gt-refinery


Digest: mol-deacon-patrol

Patrol 11: Quiet


Session ended: gt-gastown-corpus


Session ended: gt-gastown-crew-joe


Digest: mol-deacon-patrol

Cycle 19


Digest: mol-deacon-patrol

Patrol cycle 13


Session ended: gt-gastown-crew-gus


Review PR #149: fix(sling) cross-rig beads routing


Session ended: gt-gastown-rictus


Digest: mol-deacon-patrol

Patrol 20


Digest: mol-deacon-patrol

Cycle 301: All healthy, refinery queue 8


Digest: mol-deacon-patrol

Patrol 7: healthy


Merge: furiosa-mjtnoooj

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


Digest: mol-deacon-patrol

Patrol cycle 18: all healthy


Review PR #183: rig agent beads prefix

dispatched_by: gastown/crew/joe

Reviewed PR #183 - requested changes due to incomplete fix (creation fixed but lookups still use hardcoded gt- prefix)


Session ended: gt-gastown-warboy


Merge: gt-x4ad3

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


Merge: capable-1767140263101

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


Pipeline Reliability: Fix work loss in polecat→refinery flow

Post-mortem from 12 swarms that produced 74 orphan commits and lost work.

## Root Cause
No transactional boundaries between pipeline stages. Work moves polecat→witness→refinery→main with fire-and-forget handoffs.

## Key Failures
1. Polecat session death before pipeline entry (commit but no push, or push but no gt done)
2. No push verification in gt done
3. Cleanup wisp and MR bead are unlinked tracking mechanisms
4. Premature nuke before merge confirmed
5. Refinery bottleneck causing stale branches
6. No polecat session persistence/checkpoint

## Success Criteria
- Zero work loss from session death
- All merged work traceable end-to-end
- Recovery path for every failure mode


Digest: mol-deacon-patrol

Patrol cycle 18: All agents healthy


Digest: mol-deacon-patrol

Patrol 15 complete


Session ended: gt-gastown-crew-max

Bulk cleanup of stale session-ended events (gt-8tc1v)


Digest: mol-deacon-patrol

Patrol 145: All healthy


Merge: nux-1767141948667

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


Digest: mol-deacon-patrol

Cycle 16


Align agent/role beads with two-level architecture

## Problem

Agent and role beads are stored inconsistently with the documented two-level beads architecture.

### Current State (Incorrect)

All agent beads use `gt-*` prefix and route to gastown rig beads:
- `gt-mayor`, `gt-deacon` → stored in `gastown/mayor/rig/.beads/`
- `gt-gastown-witness`, `gt-gastown-refinery` → same location
- `gt-mayor-role`, `gt-witness-role` → same location

### Design Docs Say (from PRIMING.md)

```
ORGANIZATION CHAIN (town beads, ~/gt/.beads/)
    Prefix: hq-*
    Contains: Convoys, Mayor mail, strategic coordination

PROJECT CHAIN (gastown, ~/gt/gastown/**/.beads/)
    Prefix: gt-*
    Contains: Implementation work, MRs, code issues
```

Role taxonomy:
```
TOWN LEVEL (cross-rig)          RIG LEVEL (per-project)
├── Mayor (agent)               ├── Witness (patrol)
├── Deacon (patrol)             ├── Refinery (merge)
└── Dogs (workers)              └── Polecats (ephemeral workers)
```

**Town-level agents are stored at project level.** This violates the two-level architecture.

## Correct Architecture

| Agent Type | Scope | Bead Location | Prefix |
|------------|-------|---------------|--------|
| Mayor | Town | `~/gt/.beads/` | `hq-mayor` |
| Deacon | Town | `~/gt/.beads/` | `hq-deacon` |
| Dogs | Town | `~/gt/.beads/` | `hq-dog-<name>` |
| Witness | Rig | `<rig>/.beads/` | `<prefix>-<rig>-witness` |
| Refinery | Rig | `<rig>/.beads/` | `<prefix>-<rig>-refinery` |
| Polecats | Rig | `<rig>/.beads/` | `<prefix>-<rig>-polecat-<name>` |

**Role beads** are global templates → town beads with `hq-` prefix:
- `hq-mayor-role`, `hq-deacon-role`, `hq-witness-role`, etc.

## Why This Matters (HOP Context)

From CONTEXT.md: "Each polecat should have a chain" for CV/reputation tracking.

Agent beads are **identity beads** (CV chains), not work beads. For HOP compatibility:
- Agent identity should be cross-project
- Town-level agents → organization chain (town beads)
- Rig-level agents → project chain (rig beads)

## Impact

- **PR #50** tries to fix prefix mismatch by changing town beads to `gt` prefix - WRONG direction
- **PR #32** (ca487a8) added broken code trying to store agents in town beads with `gt-` prefix
- Routes already support `hq-` → town beads, no routing changes needed

## Implementation Plan

See child issues for phased implementation.


Digest: mol-deacon-patrol

Patrol cycle 15: all healthy


Merge: furiosa-1767075024945

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

Branch no longer exists on remote - already merged or cleaned up


Digest: mol-deacon-patrol

Patrol 20: healthy


Session ended: gt-gastown-nux


Digest: mol-deacon-patrol

Cycle 11


Serialized conflict resolution via merge-slot gate

## Problem: Monkey Knife Fight

Multiple conflict-resolution polecats racing to land creates cascading conflicts:
- Polecat A rebases on main@v1, resolving...
- Polecat B rebases on main@v1, resolving...
- Polecat A pushes → main@v2
- Polecat B pushes → CONFLICT (main moved) → needs re-resolve

This wastes cycles and creates thrashing.

## Solution: Merge-Slot Gate

A single merge slot per rig, implemented via gates:

```
┌─────────────────────────────────────────────────────┐
│              MERGE SLOT (gt-merge-slot)             │
│            Only one holder at a time                │
└─────────────────────────────────────────────────────┘
                         │
         ┌───────────────┼───────────────┐
         ▼               ▼               ▼
    [High-prio MR]  [Med-prio MR]   [Low-prio MR]
     acquires slot   waits on gate   waits on gate
```

## Design

### Merge Slot Bead
Each rig has a persistent slot bead: `gt-merge-slot` (type=slot)
- Status: open (slot available) or in_progress (slot held)
- Holder field: which polecat/MR currently holds it

### Acquiring the Slot
1. Conflict polecat checks `bd show gt-merge-slot`
2. If status=open:
   - `bd update gt-merge-slot --status=in_progress --holder=<mr-id>`
   - Proceed with conflict resolution
3. If status=in_progress:
   - Create bead-gate waiting for slot to become open
   - Block until gate closes

### Priority Ordering
Convoy graph provides priority:
- Convoy age (older = higher priority)
- Epic priority (P0 > P4)
- Retry count (high retries = penalty)

Witness dispatches conflict resolution in priority order.
Only highest-priority waiting work acquires slot when released.

### Releasing the Slot
After merge to main:
1. `bd update gt-merge-slot --status=open --holder=""`
2. All waiting gates check slot
3. Highest-priority waiter acquires

### Direct-to-Main Flow
Conflict polecat with slot:
1. Rebase on main, resolve conflicts
2. Run tests
3. Push directly to main (not back to MR queue)
4. Close original MR bead
5. Release merge slot

## Benefits
- No monkey knife fight (serialized)
- Priority respected (convoy back-pressure)
- No queue re-entry (direct to main)
- Uses existing gates infrastructure

## Implementation Tasks
1. Create merge-slot bead type
2. Slot acquire/release in gt done
3. Witness priority-ordered dispatch
4. Gate-based waiting for slot

## Related
- gt-si8rq.5: Conflict resolution workflow (update to use slot)
- gt-si8rq.6: Priority-ordered MQ (provides priority info)
- bd-quw1: Phase handoff (gate infrastructure)

Implemented merge-slot gate for serialized conflict resolution


Extract SupportedShells constant to constants package

Extract repeated shell list to a single constant.

## Files to modify
- internal/constants/constants.go (add constant)
- internal/cmd/start.go (use constant at lines 729, 773, 907)
- internal/cmd/crew_helpers.go (use constant)

## Implementation
Add to constants.go:
```go
var SupportedShells = []string{"bash", "zsh", "sh", "fish", "tcsh", "ksh"}
```

Replace all inline []string{"bash", "zsh"...} with constants.SupportedShells.

## Acceptance criteria
- [ ] SupportedShells added to internal/constants/constants.go
- [ ] All 4 occurrences in start.go and crew_helpers.go replaced
- [ ] grep -r '"bash", "zsh"' returns no matches in internal/cmd/
- [ ] go build ./... passes
- [ ] go test ./... passes


Merge: nux-1767059693217

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


Digest: mol-deacon-patrol

Patrol 14: all clear


Session ended: gt-gastown/crew/jack


Merge: furiosa-mjtny0lc

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


Session ended: gt-gastown-crew-max


Session ended: gt-gastown-crew-joe


Digest: mol-deacon-patrol

Cycle 7


Session ended: gt-gastown-crew-george


Digest: mol-deacon-patrol

Patrol 7


Digest: mol-deacon-patrol

Patrol 19: all clear


Session ended: gt-gastown-crew-jack


Digest: mol-deacon-patrol

Patrol 17: quick pass


Add Windows-compatible file locking for daemon

PR #108 added syscall.Flock() for daemon orphan prevention, but Flock is Unix-only.

For Windows support, need to implement platform-specific locking:
- Unix: syscall.Flock (current implementation)
- Windows: LockFileEx via golang.org/x/sys/windows or similar

Options:
1. Build tags with platform-specific implementations
2. Use a cross-platform library like github.com/gofrs/flock
3. Conditional compilation with fallback behavior on Windows

The gofrs/flock library is probably the cleanest solution - it handles both platforms transparently.

Related: PR #108 (fix daemon orphan race condition)

Implemented cross-platform file locking using gofrs/flock library


Session ended: gt-gastown-splendid


Epic: Fix swarm orchestration - witness/refinery/polecat lifecycle

## Problem Statement

The bd-9115 swarm execution required excessive manual intervention from Mayor. The witness, refinery, and polecat lifecycle components didn't coordinate automatically.

## What Should Have Happened

```
Mayor slings 6 beads to rig
    ↓
Polecats auto-spawn with synced beads, work pinned
    ↓
Polecats work autonomously
    ↓
Witness monitors progress, nudges stuck polecats
    ↓
Polecat completes → pushes branch → signals completion
    ↓
Refinery detects ready branch → rebases → merges → deletes branch
    ↓
Witness detects merge → nukes polecat worktree
    ↓
When all done → Witness notifies Mayor
```

## What Actually Happened

1. **gt sling failed to pin beads** - polecat worktrees had stale JSONL
2. **Manual intervention** - had to checkout latest JSONL, pin, nudge each polecat
3. **Witness was passive** - never nudged or checked on polecats
4. **Refinery waited for requests** - didn't detect completed branches
5. **Manual lifecycle** - Mayor had to close beads, nuke polecats
6. **Manual merge coordination** - had to mail refinery with merge order

## Root Cause: Branch Hysteresis

Polecat branches persist across runs and drift from main/beads-sync:
- `polecat/foo` created weeks ago from old main
- New work slung to `polecat/foo`
- JSONL in branch doesn't have new beads
- Pin fails

## Open Questions

### Q1: Fresh branches per run?
Should each polecat spawn create a NEW branch from latest main/beads-sync?
```
gt sling bd-xxx rig
  → creates polecat/foo-20251227-1630 from origin/main
  → ensures JSONL is current
  → after merge, branch deleted forever
```
Pros: No drift, always current
Cons: Branch proliferation, naming complexity

### Q2: Rebase existing branches?
Or should we rebase persistent polecat branches before work?
```
gt sling bd-xxx rig/foo
  → git fetch origin
  → git rebase origin/main
  → now JSONL is current
```
Pros: Keeps simple naming
Cons: Rebase can fail with conflicts

### Q3: Just cherry-pick JSONL?
Minimal fix - grab latest JSONL before pinning:
```
git checkout origin/beads-sync -- .beads/issues.jsonl
bd import  # refresh DB
bd pin bd-xxx
```
Pros: Simple, surgical
Cons: Doesn't fix code drift, just beads

### Q4: Shared beads DB?
Could polecats share a DB (via symlink or sqlite over network)?
Pros: Always consistent
Cons: Locking complexity, daemon conflicts

### Q5: Who owns polecat lifecycle?
- Witness? (current assumption)
- Refinery? (after merge)
- gt sling? (on spawn)
- New "foreman" role?

## Proposed Solutions

See child issues for implementation details. Need to resolve open questions first.


Digest: mol-deacon-patrol

Patrol 15: Quiet


Build activity stream component

Bubbletea component showing scrollable activity stream for a selected worker. Shows mutation events with timestamps, symbols, and issue titles. Displayed when user expands/selects a worker.


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 60: All healthy, handoff threshold reached


Digest: mol-deacon-patrol

Patrol 14: All healthy


Digest: mol-deacon-patrol

Patrol cycle 8: All healthy.


Formula execution: Spawn convoy from formula

Implement gt formula run <name>:
1. Load and parse formula
2. Create convoy bead (hq-cv-xxx)
3. For each leg, create child bead
4. Sling each leg to separate polecat with leg-specific prompt
5. Track leg completion via bead status
6. When all legs done, spawn synthesis polecat

Use existing gt sling and gt convoy infrastructure.


Digest: mol-deacon-patrol

Patrol cycle 17


Session ended: gt-gastown-crew-gus


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.

Fixed: Added Rig.BeadsPath() method and updated all swarm bd commands to use it. The issue was that bd commands were being run from the rig container directory which has gitignored .beads/, not from a valid git clone within the rig.


ZFC #10: Polecat reports cleanup status instead of Go checking git

**ZFC Violation:** internal/polecat/manager.go:192-215

Go examines git state to decide if polecat removal is safe:
```go
status, err := polecatGit.CheckUncommittedWork()
if status.StashCount > 0 || status.UnpushedCommits > 0 {
    return &UncommittedWorkError{...}
}
```

**ZFC-compliant solution:**
Polecat reports its own cleanup status via agent bead:
- state: stopped
- cleanup_status: clean | has_uncommitted | has_stash | has_unpushed
- Witness reads cleanup_status before calling nuke
- Polecat is authority on whether it's safe to remove

**Relates to:** Day 4.1/4.2 (recycle/nuke commands)

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


Add GitHub issue/PR templates

Add .github/ISSUE_TEMPLATE/ with bug and feature templates. Add .github/PULL_REQUEST_TEMPLATE.md. Reference beads repo for examples.

Added .github/ISSUE_TEMPLATE/ with bug and feature templates, plus PULL_REQUEST_TEMPLATE.md