docs: reorganize documentation into concepts, design, and examples

Move documentation files into a clearer structure:
- concepts/: core ideas (convoy, identity, molecules, polecat-lifecycle, propulsion)
- design/: architecture and protocols (architecture, escalation, federation, mail, etc.)
- examples/: demos and tutorials (hanoi-demo)
- overview.md: renamed from understanding-gas-town.md

Remove outdated/superseded docs and update reference.md.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gastown/crew/gus
2026-01-11 21:21:25 -08:00
committed by Steve Yegge
parent 8ed31e9634
commit 88f784a9aa
22 changed files with 195 additions and 1356 deletions

View File

@@ -223,4 +223,4 @@ Use rig status for "what's everyone in this rig working on?"
## See Also
- [Propulsion Principle](propulsion-principle.md) - Worker execution model
- [Mail Protocol](mail-protocol.md) - Notification delivery
- [Mail Protocol](../design/mail-protocol.md) - Notification delivery

View File

@@ -154,6 +154,50 @@ gt mol squash # Squash attached molecule
gt mol step done <step> # Complete a molecule step
```
## Polecat Workflow
Polecats receive work via their hook - a pinned molecule attached to an issue.
They execute molecule steps sequentially, closing each step as they complete it.
### Molecule Types for Polecats
| Type | Storage | Use Case |
|------|---------|----------|
| **Regular Molecule** | `.beads/` (synced) | Discrete deliverables, audit trail |
| **Wisp** | `.beads/` (ephemeral) | Patrol cycles, operational loops |
Polecats typically use **regular molecules** because each assignment has audit value.
Patrol agents (Witness, Refinery, Deacon) use **wisps** to prevent accumulation.
### Hook Management
```bash
gt hook # What's on MY hook?
gt mol attach-from-mail <id> # Attach work from mail message
gt done # Signal completion (syncs, submits to MQ, notifies Witness)
```
### Polecat Workflow Summary
```
1. Spawn with work on hook
2. gt hook # What's hooked?
3. bd mol current # Where am I?
4. Execute current step
5. bd close <step> --continue
6. If more steps: GOTO 3
7. gt done # Signal completion
```
### Wisp vs Molecule Decision
| Question | Molecule | Wisp |
|----------|----------|------|
| Does it need audit trail? | Yes | No |
| Will it repeat continuously? | No | Yes |
| Is it discrete deliverable? | Yes | No |
| Is it operational routine? | No | Yes |
## Best Practices
1. **Use `--continue` for propulsion** - Keep momentum by auto-advancing

View File

@@ -278,6 +278,6 @@ This distinction matters for:
## Related Documentation
- [Understanding Gas Town](understanding-gas-town.md) - Role taxonomy and architecture
- [Polecat Wisp Architecture](polecat-wisp-architecture.md) - Molecule execution
- [Overview](../overview.md) - Role taxonomy and architecture
- [Molecules](molecules.md) - Molecule execution and polecat workflow
- [Propulsion Principle](propulsion-principle.md) - Why work triggers immediate execution

View File

@@ -125,6 +125,6 @@ bd show gt-xyz # Routes to gastown/mayor/rig/.beads
## See Also
- [reference.md](reference.md) - Command reference
- [molecules.md](molecules.md) - Workflow molecules
- [identity.md](identity.md) - Agent identity and BD_ACTOR
- [reference.md](../reference.md) - Command reference
- [molecules.md](../concepts/molecules.md) - Workflow molecules
- [identity.md](../concepts/identity.md) - Agent identity and BD_ACTOR

View File

@@ -1,5 +1,7 @@
# Federation Architecture
> **Status: Design spec - not yet implemented**
> Multi-workspace coordination for Gas Town and Beads
## Overview
@@ -100,7 +102,7 @@ Distribute work across workspaces:
## Agent Provenance
Every agent operation is attributed. See [identity.md](identity.md) for the
Every agent operation is attributed. See [identity.md](../concepts/identity.md) for the
complete BD_ACTOR format convention.
### Git Commits

View File

@@ -0,0 +1,136 @@
# Operational State in Gas Town
> Managing runtime state through events and labels.
## Overview
Gas Town tracks operational state changes as structured data. This document covers:
- **Events**: State transitions as beads (immutable audit trail)
- **Labels-as-state**: Fast queries via role bead labels (current state cache)
For Boot triage and degraded mode details, see [Watchdog Chain](watchdog-chain.md).
## Events: State Transitions as Data
Operational state changes are recorded as event beads. Each event captures:
- **What** changed (`event_type`)
- **Who** caused it (`actor`)
- **What** was affected (`target`)
- **Context** (`payload`)
- **When** (`created_at`)
### Event Types
| Event Type | Description | Payload |
|------------|-------------|---------|
| `patrol.muted` | Patrol cycle disabled | `{reason, until?}` |
| `patrol.unmuted` | Patrol cycle re-enabled | `{reason?}` |
| `agent.started` | Agent session began | `{session_id?}` |
| `agent.stopped` | Agent session ended | `{reason, outcome?}` |
| `mode.degraded` | System entered degraded mode | `{reason}` |
| `mode.normal` | System returned to normal | `{}` |
### Creating Events
```bash
# Mute deacon patrol
bd create --type=event --event-type=patrol.muted \
--actor=human:overseer --target=agent:deacon \
--payload='{"reason":"fixing convoy deadlock","until":"gt-abc1"}'
# System entered degraded mode
bd create --type=event --event-type=mode.degraded \
--actor=system:daemon --target=rig:greenplace \
--payload='{"reason":"tmux unavailable"}'
```
### Querying Events
```bash
# Recent events for an agent
bd list --type=event --target=agent:deacon --limit=10
# All patrol state changes
bd list --type=event --event-type=patrol.muted
bd list --type=event --event-type=patrol.unmuted
# Events in the activity feed
bd activity --follow --type=event
```
## Labels-as-State Pattern
Events capture the full history. Labels cache the current state for fast queries.
### Convention
Labels use `<dimension>:<value>` format:
- `patrol:muted` / `patrol:active`
- `mode:degraded` / `mode:normal`
- `status:idle` / `status:working`
### State Change Flow
1. Create event bead (full context, immutable)
2. Update role bead labels (current state cache)
```bash
# Mute patrol
bd create --type=event --event-type=patrol.muted ...
bd update role-deacon --add-label=patrol:muted --remove-label=patrol:active
# Unmute patrol
bd create --type=event --event-type=patrol.unmuted ...
bd update role-deacon --add-label=patrol:active --remove-label=patrol:muted
```
### Querying Current State
```bash
# Is deacon patrol muted?
bd show role-deacon | grep patrol:
# All agents with muted patrol
bd list --type=role --label=patrol:muted
# All agents in degraded mode
bd list --type=role --label=mode:degraded
```
## Configuration vs State
| Type | Storage | Example |
|------|---------|---------|
| **Static config** | TOML files | Daemon tick interval |
| **Operational state** | Beads (events + labels) | Patrol muted |
| **Runtime flags** | Marker files | `.deacon-disabled` |
Static config rarely changes and doesn't need history.
Operational state changes at runtime and benefits from audit trail.
Marker files are fast checks that can trigger deeper beads queries.
## Commands Summary
```bash
# Create operational event
bd create --type=event --event-type=<type> \
--actor=<entity> --target=<entity> --payload='<json>'
# Update state label
bd update <role-bead> --add-label=<dim>:<val> --remove-label=<dim>:<old>
# Query current state
bd list --type=role --label=<dim>:<val>
# Query state history
bd list --type=event --target=<entity>
# Boot management
gt dog status boot
gt dog call boot
gt dog prime boot
```
---
*Events are the source of truth. Labels are the cache.*

View File

@@ -1,73 +0,0 @@
# Decision 009: Session Events Architecture
**Status:** Accepted
**Date:** 2025-12-31
**Context:** Where should session events live? Beads, separate repo, or events.jsonl?
## Decision
Session events are **orchestration infrastructure**, not work items. They stay in
`events.jsonl` (outside beads). Work attribution happens by capturing `session_id`
on beads mutations (issue close, MR merge).
## Context
The seance feature needs to discover and resume Claude Code sessions. This requires:
1. **Pointer** to session (session_id) - for `claude --resume`
2. **Attribution** (which work happened in this session) - for entity CV
Claude Code already stores full session transcripts indefinitely. Gas Town doesn't
need to duplicate them - just point at them.
## The Separation
| Layer | Storage | Content | Retention |
|-------|---------|---------|-----------|
| **Orchestration** | `~/.events.jsonl` | session_start, nudges, mail routing | Ephemeral (auto-prune) |
| **Work** | Beads (rig-level) | Issues, MRs, convoys | Permanent (ledger) |
| **Entity activity** | Beads (entity chain) | Session digests | Permanent (CV) |
| **Transcript** | Claude Code | Full session content | Claude Code's retention |
## Why Not Beads for Events?
1. **Volume**: Orchestration events are high volume, would overwhelm work signal
2. **Ephemerality**: Most orchestration events don't need CV/ledger permanence
3. **Different audiences**: Work items are cross-agent; orchestration is internal
4. **Claude Code has it**: Transcripts already live there; we just need pointers
## Implementation
### Phase 1: Attribution (Now)
- `gt done` captures `CLAUDE_SESSION_ID` in issue close
- Beads supports `closed_by_session` field on issue mutations
- Events.jsonl continues to capture `session_start` for seance
### Phase 2: Session Digests (Future)
- Sessions as wisps: `session_start` creates ephemeral wisp
- Session work adds steps (issues closed, commits made)
- `session_end` squashes to digest
- Digest lives on entity chain (agent CV)
### Phase 3: Pruning (Future)
- Events.jsonl auto-prunes after N days
- Session digests provide permanent summary
- Full transcripts remain in Claude Code
## Consequences
**Positive:**
- Clean separation of concerns
- Work ledger stays focused on work
- CV attribution via session_id on beads mutations
- Seance works via events.jsonl discovery
**Negative:**
- Two systems to understand (events vs beads)
- Need to ensure session_id flows through commands
## Related
- `gt seance` - Session discovery and resume
- `gt-3zsml` - SessionStart hook passes session_id to gt prime
- PRIMING.md - "The Feed Is the Signal" section
- CONTEXT.md - Entity chains and CV model

View File

@@ -1,278 +0,0 @@
# Operational State in Gas Town
> Managing runtime state, degraded modes, and the Boot triage system.
## Overview
Gas Town needs to track operational state: Is the Deacon's patrol muted? Is the
system in degraded mode? When did state change, and why?
This document covers:
- **Events**: State transitions as beads
- **Labels-as-state**: Fast queries via role bead labels
- **Boot**: The dog that triages the Deacon
- **Degraded mode**: Operating without tmux
## Events: State Transitions as Data
Operational state changes are recorded as event beads. Each event captures:
- **What** changed (`event_type`)
- **Who** caused it (`actor`)
- **What** was affected (`target`)
- **Context** (`payload`)
- **When** (`created_at`)
### Event Types
| Event Type | Description | Payload |
|------------|-------------|---------|
| `patrol.muted` | Patrol cycle disabled | `{reason, until?}` |
| `patrol.unmuted` | Patrol cycle re-enabled | `{reason?}` |
| `agent.started` | Agent session began | `{session_id?}` |
| `agent.stopped` | Agent session ended | `{reason, outcome?}` |
| `mode.degraded` | System entered degraded mode | `{reason}` |
| `mode.normal` | System returned to normal | `{}` |
### Creating Events
```bash
# Mute deacon patrol
bd create --type=event --event-type=patrol.muted \
--actor=human:overseer --target=agent:deacon \
--payload='{"reason":"fixing convoy deadlock","until":"gt-abc1"}'
# System entered degraded mode
bd create --type=event --event-type=mode.degraded \
--actor=system:daemon --target=rig:greenplace \
--payload='{"reason":"tmux unavailable"}'
```
### Querying Events
```bash
# Recent events for an agent
bd list --type=event --target=agent:deacon --limit=10
# All patrol state changes
bd list --type=event --event-type=patrol.muted
bd list --type=event --event-type=patrol.unmuted
# Events in the activity feed
bd activity --follow --type=event
```
## Labels-as-State Pattern
Events capture the full history. Labels cache the current state for fast queries.
### Convention
Labels use `<dimension>:<value>` format:
- `patrol:muted` / `patrol:active`
- `mode:degraded` / `mode:normal`
- `status:idle` / `status:working`
### State Change Flow
1. Create event bead (full context, immutable)
2. Update role bead labels (current state cache)
```bash
# Mute patrol
bd create --type=event --event-type=patrol.muted ...
bd update role-deacon --add-label=patrol:muted --remove-label=patrol:active
# Unmute patrol
bd create --type=event --event-type=patrol.unmuted ...
bd update role-deacon --add-label=patrol:active --remove-label=patrol:muted
```
### Querying Current State
```bash
# Is deacon patrol muted?
bd show role-deacon | grep patrol:
# All agents with muted patrol
bd list --type=role --label=patrol:muted
# All agents in degraded mode
bd list --type=role --label=mode:degraded
```
## Boot: The Deacon's Watchdog
> See [Watchdog Chain](watchdog-chain.md) for the complete Daemon/Boot/Deacon
> architecture and design rationale.
Boot is a dog (Deacon helper) that triages the Deacon's health. The daemon pokes
Boot instead of the Deacon directly, centralizing the "when to wake" decision in
an agent that can reason about it.
### Why Boot?
The daemon is dumb transport (ZFC principle). It can't decide:
- Is the Deacon stuck or just thinking?
- Should we interrupt or let it continue?
- Is the system in a state where nudging would help?
Boot is an agent that can observe and decide.
### Boot's Lifecycle
```
Daemon tick
├── Check: Is Boot already running? (marker file)
│ └── Yes + recent: Skip this tick
└── Spawn Boot (fresh session each time)
└── Boot runs triage molecule
├── Observe (wisps, mail, git state, tmux panes)
├── Decide (start/wake/nudge/interrupt/nothing)
├── Act
├── Clean inbox (discard stale handoffs)
└── Handoff (or exit in degraded mode)
```
### Boot is Always Fresh
Boot restarts on each daemon tick. This is intentional:
- Narrow scope makes restarts cheap
- Fresh context avoids accumulated confusion
- Handoff mail provides continuity without session persistence
- No keepalive needed
### Boot's Decision Guidance
Agents may take several minutes on legitimate work - composing artifacts, running
tools, deep analysis. Ten minutes or more in edge cases.
To assess whether an agent is stuck:
1. Check the agent's last reported activity (recent wisps, mail sent, git commits)
2. Observe the tmux pane output over a 30-second window
3. Look for signs of progress vs. signs of hanging (tool prompt, error loop, silence)
Agents work in small steps with feedback. Most tasks complete in 2-3 minutes, but
task nature matters.
**Boot's options (increasing disruption):**
- Let them continue (if progress is evident)
- `gt nudge <agent>` (gentle wake signal)
- Escape + chat (interrupt and ask what's happening)
- Request process restart (last resort, for true hangs)
**Common false positives:**
- Tool waiting for user confirmation
- Long-running test suite
- Large file read/write operations
### Boot's Location
```
~/gt/deacon/dogs/boot/
```
Session name: `gt-boot`
Created/maintained by `bd doctor`.
### Boot Commands
```bash
# Check Boot status
gt dog status boot
# Manual Boot run (debugging)
gt dog call boot
# Prime Boot with context
gt dog prime boot
```
## Degraded Mode
Gas Town can operate without tmux, with reduced capabilities.
### Detection
The daemon detects degraded mode mechanically and passes it to agents:
```bash
GT_DEGRADED=true # Set by daemon when tmux unavailable
```
Boot and other agents check this environment variable.
### What Changes in Degraded Mode
| Capability | Normal | Degraded |
|------------|--------|----------|
| Observe tmux panes | Yes | No |
| Interactive interrupt | Yes | No |
| Session management | Full | Limited |
| Agent spawn | tmux sessions | Direct spawn |
| Boot lifecycle | Handoff | Exit |
### Agents in Degraded Mode
In degraded mode, agents:
- Cannot observe other agents' pane output
- Cannot interactively interrupt stuck agents
- Focus on beads/git state observation only
- Report anomalies but can't fix interactively
Boot specifically:
- Runs to completion and exits (no handoff)
- Limited to: start deacon, file beads, mail overseer
- Cannot: observe panes, nudge, interrupt
### Recording Degraded Mode
```bash
# System entered degraded mode
bd create --type=event --event-type=mode.degraded \
--actor=system:daemon --target=rig:greenplace \
--payload='{"reason":"tmux unavailable"}'
bd update role-greenplace --add-label=mode:degraded --remove-label=mode:normal
```
## Configuration vs State
| Type | Storage | Example |
|------|---------|---------|
| **Static config** | TOML files | Daemon tick interval |
| **Operational state** | Beads (events + labels) | Patrol muted |
| **Runtime flags** | Marker files | `.deacon-disabled` |
Static config rarely changes and doesn't need history.
Operational state changes at runtime and benefits from audit trail.
Marker files are fast checks that can trigger deeper beads queries.
## Commands Summary
```bash
# Create operational event
bd create --type=event --event-type=<type> \
--actor=<entity> --target=<entity> --payload='<json>'
# Update state label
bd update <role-bead> --add-label=<dim>:<val> --remove-label=<dim>:<old>
# Query current state
bd list --type=role --label=<dim>:<val>
# Query state history
bd list --type=event --target=<entity>
# Boot management
gt dog status boot
gt dog call boot
gt dog prime boot
```
---
*Events are the source of truth. Labels are the cache.*

View File

@@ -27,7 +27,7 @@ These roles manage the Gas Town system itself:
| Role | Description | Lifecycle |
|------|-------------|-----------|
| **Mayor** | Global coordinator at mayor/ | Singleton, persistent |
| **Deacon** | Background supervisor daemon ([watchdog chain](watchdog-chain.md)) | Singleton, persistent |
| **Deacon** | Background supervisor daemon ([watchdog chain](design/watchdog-chain.md)) | Singleton, persistent |
| **Witness** | Per-rig polecat lifecycle manager | One per rig, persistent |
| **Refinery** | Per-rig merge queue processor | One per rig, persistent |
@@ -37,7 +37,7 @@ These roles do actual project work:
| Role | Description | Lifecycle |
|------|-------------|-----------|
| **Polecat** | Ephemeral worker with own worktree | Transient, Witness-managed ([details](polecat-lifecycle.md)) |
| **Polecat** | Ephemeral worker with own worktree | Transient, Witness-managed ([details](concepts/polecat-lifecycle.md)) |
| **Crew** | Persistent worker with own clone | Long-lived, user-managed |
| **Dog** | Deacon helper for infrastructure tasks | Ephemeral, Deacon-managed |
@@ -64,7 +64,7 @@ gt convoy list
- Historical record of completed work (`gt convoy list --all`)
The "swarm" is ephemeral - just the workers currently assigned to a convoy's issues.
When issues close, the convoy lands. See [Convoys](convoy.md) for details.
When issues close, the convoy lands. See [Convoys](concepts/convoy.md) for details.
## Crew vs Polecats

View File

@@ -1,172 +0,0 @@
# Polecat Wisp Architecture
How polecats use molecules and wisps to execute work in Gas Town.
## Overview
Polecats receive work via their hook - a pinned molecule attached to an issue.
They execute molecule steps sequentially, closing each step as they complete it.
## Molecule Types for Polecats
| Type | Storage | Use Case |
|------|---------|----------|
| **Regular Molecule** | `.beads/` (synced) | Discrete deliverables, audit trail |
| **Wisp** | `.beads/` (ephemeral, type=wisp) | Patrol cycles, operational loops |
Polecats typically use **regular molecules** because each assignment has audit value.
Patrol agents (Witness, Refinery, Deacon) use **wisps** to prevent accumulation.
## Step Execution
### The Traditional Approach
```bash
# 1. Check current status
gt hook
# 2. Find next step
bd ready --parent=gt-abc
# 3. Claim the step
bd update gt-abc.4 --status=in_progress
# 4. Do the work...
# 5. Close the step
bd close gt-abc.4
# 6. Repeat from step 2
```
### The Propulsion Approach
```bash
# 1. Check where you are
bd mol current
# 2. Do the work on current step...
# 3. Close and advance in one command
bd close gt-abc.4 --continue
# 4. Repeat from step 1
```
The `--continue` flag:
- Closes the current step
- Finds the next ready step in the same molecule
- Auto-marks it `in_progress`
- Outputs the transition
### Example Session
```bash
$ bd mol current
You're working on molecule gt-abc (Implement user auth)
✓ gt-abc.1: Design schema
✓ gt-abc.2: Create models
→ gt-abc.3: Add endpoints [in_progress] <- YOU ARE HERE
○ gt-abc.4: Write tests
○ gt-abc.5: Update docs
Progress: 2/5 steps complete
$ # ... implement the endpoints ...
$ bd close gt-abc.3 --continue
✓ Closed gt-abc.3: Add endpoints
Next ready in molecule:
gt-abc.4: Write tests
→ Marked in_progress (use --no-auto to skip)
$ bd mol current
You're working on molecule gt-abc (Implement user auth)
✓ gt-abc.1: Design schema
✓ gt-abc.2: Create models
✓ gt-abc.3: Add endpoints
→ gt-abc.4: Write tests [in_progress] <- YOU ARE HERE
○ gt-abc.5: Update docs
Progress: 3/5 steps complete
```
## Molecule Completion
When closing the last step:
```bash
$ bd close gt-abc.5 --continue
✓ Closed gt-abc.5: Update docs
Molecule gt-abc complete! All steps closed.
Consider: bd mol squash gt-abc --summary '...'
```
After all steps are closed:
```bash
# Squash to digest for audit trail
bd mol squash gt-abc --summary "Implemented user authentication with JWT"
# Or if it's routine work
bd mol burn gt-abc
```
## Hook Management
### Checking Your Hook
```bash
gt hook
```
Shows what molecule is pinned to your current agent and the associated bead.
### Attaching Work from Mail
```bash
gt mail inbox
gt mol attach-from-mail <mail-id>
```
### Completing Work
```bash
# After all molecule steps closed
gt done
# This:
# 1. Syncs beads
# 2. Submits to merge queue
# 3. Notifies Witness
```
## Polecat Workflow Summary
```
1. Spawn with work on hook
2. gt hook # What's hooked?
3. bd mol current # Where am I?
4. Execute current step
5. bd close <step> --continue
6. If more steps: GOTO 3
7. gt done # Signal completion
8. Wait for Witness cleanup
```
## Wisp vs Molecule Decision
| Question | Molecule | Wisp |
|----------|----------|------|
| Does it need audit trail? | Yes | No |
| Will it repeat continuously? | No | Yes |
| Is it discrete deliverable? | Yes | No |
| Is it operational routine? | No | Yes |
Polecats: **Use molecules** (deliverables have audit value)
Patrol agents: **Use wisps** (routine loops don't accumulate)

View File

@@ -471,7 +471,7 @@ gt convoy list --all # Include landed convoys
gt convoy list --status=closed # Only landed convoys
```
Note: "Swarm" is ephemeral (workers on a convoy's issues). See [Convoys](convoy.md).
Note: "Swarm" is ephemeral (workers on a convoy's issues). See [Convoys](concepts/convoy.md).
### Work Assignment
@@ -510,7 +510,7 @@ gt escalate -s HIGH "msg" # Important blocker
gt escalate -s MEDIUM "msg" -m "Details..."
```
See [escalation.md](escalation.md) for full protocol.
See [escalation.md](design/escalation.md) for full protocol.
### Sessions
@@ -611,4 +611,4 @@ bd mol bond mol-security-scan $PATROL_ID --var scope="$SCOPE"
**Nondeterministic idempotence**: Any worker can continue any molecule. Steps are atomic checkpoints in beads.
**Convoy tracking**: Convoys track batched work across rigs. A "swarm" is ephemeral - just the workers currently on a convoy's issues. See [Convoys](convoy.md) for details.
**Convoy tracking**: Convoys track batched work across rigs. A "swarm" is ephemeral - just the workers currently on a convoy's issues. See [Convoys](concepts/convoy.md) for details.

View File

@@ -1,220 +0,0 @@
# Infrastructure & Utilities Code Review
**Review ID**: gt-a02fj.8
**Date**: 2026-01-04
**Reviewer**: gastown/polecats/interceptor (polecat gus)
## Executive Summary
Reviewed 14 infrastructure packages for dead code, missing abstractions, performance concerns, and error handling consistency. Found significant cleanup opportunities totaling ~44% dead code in constants package and an entire unused package (keepalive).
---
## 1. Dead Code Inventory
### Critical: Entire Package Unused
| Package | Status | Recommendation |
|---------|--------|----------------|
| `internal/keepalive/` | 100% unused | **DELETE ENTIRE PACKAGE** |
The keepalive package (5 functions) was removed from the codebase on Dec 30, 2025 as part of the shift to feed-based activation. No imports exist anywhere.
### High Priority: Functions to Remove
| Package | Function | Location | Notes |
|---------|----------|----------|-------|
| `config` | `NewExampleAgentRegistry()` | agents.go:361-381 | Zero usage in codebase |
| `constants` | `DirMayor`, `DirPolecats`, `DirCrew`, etc. | constants.go:32-59 | 9 unused directory constants |
| `constants` | `FileRigsJSON`, `FileTownJSON`, etc. | constants.go:62-74 | 4 unused file constants |
| `constants` | `BranchMain`, `BranchBeadsSync`, etc. | constants.go:77-89 | 4 unused branch constants |
| `constants` | `RigBeadsPath()`, `RigPolecatsPath()`, etc. | constants.go | 5 unused path helper functions |
| `doctor` | `itoa()` | daemon_check.go:93-111 | Duplicate of `strconv.Itoa()` |
| `lock` | `DetectCollisions()` | lock.go:367-402 | Superseded by doctor checks |
| `events` | `BootPayload()` | events.go:186-191 | Never called |
| `events` | `TypePatrolStarted`, `TypeSessionEnd` | events.go:50,54 | Never emitted |
| `events` | `VisibilityBoth` | events.go:32 | Never set |
| `boot` | `DeaconDir()` | boot.go:235-237 | Exported but never called |
| `dog` | `IdleCount()`, `WorkingCount()` | manager.go:532-562 | Inlined in callers |
### Medium Priority: Duplicate Definitions
| Package | Item | Duplicate Location | Action |
|---------|------|-------------------|--------|
| `constants` | `RigSettingsPath()` | Also in config/loader.go:673 | Remove from constants |
| `util` | Atomic write pattern | Also in mrqueue/, wisp/ | Consolidate to util |
| `doctor` | `findRigs()` | 3 identical implementations | Extract shared helper |
---
## 2. Utility Consolidation Plan
### Pattern: Atomic Write (Priority: HIGH)
**Current state**: Duplicated in 3+ locations
- `util/atomic.go` (canonical)
- `mrqueue/mrqueue.go` (duplicate)
- `wisp/io.go` (duplicate)
- `polecat/pending.go` (NON-ATOMIC - bug!)
**Action**:
1. Fix `polecat/pending.go:SavePending()` to use `util.AtomicWriteJSON`
2. Replace inline atomic writes in mrqueue and wisp with util calls
### Pattern: Rig Discovery (Priority: HIGH)
**Current state**: 7+ implementations scattered across doctor package
- `BranchCheck.findPersistentRoleDirs()`
- `OrphanSessionCheck.getValidRigs()`
- `PatrolMoleculesExistCheck.discoverRigs()`
- `config_check.go.findAllRigs()`
- Multiple `findCrewDirs()` implementations
**Action**: Create `internal/workspace/discovery.go`:
```go
type RigDiscovery struct { ... }
func (d *RigDiscovery) FindAllRigs() []string
func (d *RigDiscovery) FindCrewDirs(rig string) []string
func (d *RigDiscovery) FindPolecatDirs(rig string) []string
```
### Pattern: Clone Validation (Priority: MEDIUM)
**Current state**: Duplicate logic in doctor checks
- `rig_check.go`: Validates .git, runs git status
- `branch_check.go`: Similar traversal logic
**Action**: Create `internal/workspace/clone.go`:
```go
type CloneValidator struct { ... }
func (v *CloneValidator) ValidateClone(path string) error
func (v *CloneValidator) GetCloneInfo(path string) (*CloneInfo, error)
```
### Pattern: Tmux Session Handling (Priority: MEDIUM)
**Current state**: Fragmented across lock, doctor, daemon
- `lock/lock.go`: `getActiveTmuxSessions()`
- `doctor/identity_check.go`: Similar logic
- `cmd/agents.go`: Uses `tmux.NewTmux()`
**Action**: Consolidate into `internal/tmux/sessions.go`
### Pattern: Load/Validate Config Files (Priority: LOW)
**Current state**: 8 near-identical Load* functions in config/loader.go
- `LoadTownConfig`, `LoadRigsConfig`, `LoadRigConfig`, etc.
**Action**: Create generic loader using Go generics:
```go
func loadConfigFile[T Validator](path string) (*T, error)
```
### Pattern: Math Utilities (Priority: LOW)
**Current state**: `min()`, `max()`, `min3()`, `abs()` in suggest/suggest.go
**Action**: If needed elsewhere, move to `internal/util/math.go`
---
## 3. Performance Concerns
### Critical: File I/O Per-Event
| Package | Issue | Impact | Recommendation |
|---------|-------|--------|----------------|
| `events` | Opens/closes file for every event | High on busy systems | Batch writes or buffered logger |
| `townlog` | Opens/closes file per log entry | Medium | Same as events |
| `events` | `workspace.FindFromCwd()` on every Log() | Low-medium | Cache town root |
### Critical: Process Tree Walking
| Package | Issue | Impact | Recommendation |
|---------|-------|--------|----------------|
| `doctor/orphan_check` | `hasCrewAncestor()` calls `ps` in loop | O(n) subprocess calls | Batch gather process info |
### High: Directory Traversal Inefficiencies
| Package | Issue | Impact | Recommendation |
|---------|-------|--------|----------------|
| `doctor/hook_check` | Uses `exec.Command("find")` | Subprocess overhead | Use `filepath.Walk` |
| `lock` | `FindAllLocks()` - unbounded Walk | Scales poorly | Add depth limits |
| `townlog` | `TailEvents()` reads entire file | Memory for large logs | Implement true tail |
### Medium: Redundant Operations
| Package | Issue | Recommendation |
|---------|-------|----------------|
| `dog` | `List()` + iterate = double work | Provide `CountByState()` |
| `dog` | Creates new git.Git per worktree | Cache or batch |
| `doctor/rig_check` | Runs git status twice per polecat | Combine operations |
| `checkpoint/Capture` | 3 separate git commands | Use combined flags |
### Low: JSON Formatting Overhead
| Package | Issue | Recommendation |
|---------|-------|----------------|
| `lock` | `MarshalIndent()` for lock files | Use `Marshal()` (no indentation needed) |
| `townlog` | No compression for old logs | Consider gzip rotation |
---
## 4. Error Handling Issues
### Pattern: Silent Failures
| Package | Location | Issue | Fix |
|---------|----------|-------|-----|
| `events` | All callers | 19 instances of `_ = events.LogFeed()` | Standardize: always ignore or always check |
| `townlog` | `ParseLogLines()` | Silently skips malformed lines | Log warnings |
| `lock` | Lines 91, 180, 194-195 | Silent `_ =` without comments | Document intent |
| `checkpoint` | `Capture()` | Returns nil error but git commands fail | Return actual errors |
| `deps` | `BeadsUnknown` case | Silently passes | Log warning or fail |
### Pattern: Inconsistent State Handling
| Package | Issue | Recommendation |
|---------|-------|----------------|
| `dog/Get()` | Returns minimal Dog if state missing | Document or error |
| `config/GetAccount()` | Returns pointer to loop variable (bug!) | Return by value |
| `boot` | `LoadStatus()` returns empty struct if missing | Document behavior |
### Bug: Missing Role Mapping
| Package | Issue | Impact |
|---------|-------|--------|
| `claude` | `RoleTypeFor()` missing `deacon`, `crew` | Wrong settings applied |
---
## 5. Testing Gaps
| Package | Gap | Priority |
|---------|-----|----------|
| `checkpoint` | No unit tests | HIGH (crash recovery) |
| `dog` | 4 tests, major paths untested | HIGH |
| `deps` | Minimal failure path testing | MEDIUM |
| `claude` | No tests | LOW |
---
## Summary Statistics
| Category | Count | Packages Affected |
|----------|-------|-------------------|
| **Dead Code Items** | 25+ | config, constants, doctor, lock, events, boot, dog, keepalive |
| **Duplicate Patterns** | 6 | util, doctor, config, lock |
| **Performance Issues** | 12 | events, townlog, doctor, dog, lock, checkpoint |
| **Error Handling Issues** | 15 | events, townlog, lock, checkpoint, deps, claude |
| **Testing Gaps** | 4 packages | checkpoint, dog, deps, claude |
## Recommended Priority
1. **Delete keepalive package** (entire package unused)
2. **Fix claude/RoleTypeFor()** (incorrect behavior)
3. **Fix config/GetAccount()** (pointer to stack bug)
4. **Fix polecat/pending.go** (non-atomic writes)
5. **Delete 21 unused constants** (maintenance burden)
6. **Consolidate atomic write pattern** (DRY)
7. **Add checkpoint tests** (crash recovery critical)

View File

@@ -1,74 +0,0 @@
# Swarm (Ephemeral Worker View)
> **Note**: "Swarm" is an ephemeral concept, not a persistent entity.
> For tracking work, see [Convoys](convoy.md).
## What is a Swarm?
A **swarm** is simply "the workers currently assigned to a convoy's issues."
It has no separate ID and no persistent state - it's just a view of active workers.
| Concept | Persistent? | ID | Description |
|---------|-------------|-----|-------------|
| **Convoy** | Yes | hq-* | The tracking unit. What you create and track. |
| **Swarm** | No | None | The workers. Ephemeral view of who's working. |
## The Relationship
```
Convoy hq-abc ─────────tracks───────────► Issues
│ assigned to
Polecats
────────┴────────
"the swarm"
(ephemeral)
```
When you say "kick off a swarm," you're really:
1. Creating a convoy (persistent tracking)
2. Assigning polecats to the convoy's issues
3. The swarm = those polecats while they work
When the work completes, the convoy lands and the swarm dissolves.
## Viewing the Swarm
The swarm appears in convoy status:
```bash
gt convoy status hq-abc
```
```
Convoy: hq-abc (Deploy v2.0)
════════════════════════════
Progress: 2/3 complete
Issues
✓ gt-xyz: Update API closed
→ bd-ghi: Update docs in_progress @beads/amber
○ gt-jkl: Final review open
Workers (the swarm) ← this is the swarm
beads/amber bd-ghi running 12m
```
## Historical Note
Earlier Gas Town development used "swarm" as if it were a persistent entity
with its own lifecycle. The `gt swarm` commands were built on this model.
The correct model is:
- **Convoy** = the persistent tracking unit (what `gt swarm` was trying to be)
- **Swarm** = ephemeral workers (no separate tracking needed)
The `gt swarm` command is being deprecated in favor of `gt convoy`.
## See Also
- [Convoys](convoy.md) - The persistent tracking unit
- [Propulsion Principle](propulsion-principle.md) - Worker execution model

View File

@@ -1,154 +0,0 @@
# Test Coverage and Quality Review
**Reviewed by**: polecat/gus
**Date**: 2026-01-04
**Issue**: gt-a02fj.9
## Executive Summary
- **80 test files** covering **32 out of 42 packages** (76% package coverage)
- **631 test functions** with 192 subtests (30% use table-driven pattern)
- **10 packages** with **0 test coverage** (2,452 lines)
- **1 confirmed flaky test** candidate
- Test quality is generally good with moderate mocking
---
## Coverage Gap Inventory
### Packages Without Tests (Priority Order)
| Priority | Package | Lines | Risk | Notes |
|----------|---------|-------|------|-------|
| **P0** | `internal/lock` | 402 | **CRITICAL** | Multi-agent lock management. Bugs cause worker collisions. Already has `execCommand` mockable for testing. |
| **P1** | `internal/events` | 295 | HIGH | Event bus for audit trail. Mutex-protected writes. Core observability. |
| **P1** | `internal/boot` | 242 | HIGH | Boot watchdog lifecycle. Spawns tmux sessions. |
| **P1** | `internal/checkpoint` | 216 | HIGH | Session crash recovery. Critical for polecat continuity. |
| **P2** | `internal/tui/convoy` | 601 | MEDIUM | TUI component. Harder to test but user-facing. |
| **P2** | `internal/constants` | 221 | LOW | Mostly configuration constants. Low behavioral risk. |
| **P3** | `internal/style` | 331 | LOW | Output formatting. Visual only. |
| **P3** | `internal/claude` | 80 | LOW | Claude settings parsing. |
| **P3** | `internal/wisp` | 52 | LOW | Ephemeral molecule I/O. Small surface. |
| **P4** | `cmd/gt` | 12 | TRIVIAL | Main entry point. Minimal code. |
**Total untested lines**: 2,452
---
## Flaky Test Candidates
### Confirmed: `internal/feed/curator_test.go`
**Issue**: Uses `time.Sleep()` for synchronization (lines 59, 71, 119, 138)
```go
// Give curator time to start
time.Sleep(50 * time.Millisecond)
...
// Wait for processing
time.Sleep(300 * time.Millisecond)
```
**Risk**: Flaky under load, CI delays, or slow machines.
**Fix**: Replace with channel-based synchronization or polling with timeout:
```go
// Wait for condition with timeout
deadline := time.Now().Add(time.Second)
for time.Now().Before(deadline) {
if conditionMet() {
break
}
time.Sleep(10 * time.Millisecond)
}
```
---
## Test Quality Analysis
### Strengths
1. **Table-driven tests**: 30% of tests use `t.Run()` (192/631)
2. **Good isolation**: Only 2 package-level test variables
3. **Dedicated integration tests**: 15 files with explicit integration/e2e naming
4. **Error handling**: 316 uses of `if err != nil` in tests
5. **No random data**: No `rand.` usage in tests (deterministic)
6. **Environment safety**: Uses `t.Setenv()` for clean env var handling
### Areas for Improvement
1. **`testing.Short()`**: Only 1 usage. Long-running tests should check this.
2. **External dependencies**: 26 tests skip when `bd` or `tmux` unavailable - consider mocking more.
3. **time.Sleep usage**: Found in `curator_test.go` - should be eliminated.
---
## Test Smells (Minor)
| Smell | Location | Severity | Notes |
|-------|----------|----------|-------|
| Sleep-based sync | `feed/curator_test.go` | HIGH | See flaky section |
| External dep skips | Multiple files | LOW | Reasonable for integration tests |
| Skip-heavy file | `tmux/tmux_test.go` | LOW | Acceptable - tmux not always available |
---
## Priority List for New Tests
### Immediate (P0)
1. **`internal/lock`** - Critical path
- Test `Acquire()` with stale lock cleanup
- Test `Check()` with live/dead PIDs
- Test `CleanStaleLocks()` with mock tmux sessions
- Test `DetectCollisions()`
- Test concurrent lock acquisition (race detection)
### High Priority (P1)
2. **`internal/events`**
- Test `Log()` file creation and append
- Test `write()` mutex behavior
- Test payload helpers
- Test graceful handling when not in workspace
3. **`internal/boot`**
- Test `IsRunning()` with stale markers
- Test `AcquireLock()` / `ReleaseLock()` cycle
- Test `SaveStatus()` / `LoadStatus()` round-trip
- Test degraded mode path
4. **`internal/checkpoint`**
- Test `Read()` / `Write()` round-trip
- Test `Capture()` git state extraction
- Test `IsStale()` with various durations
- Test `Summary()` output
### Medium Priority (P2)
5. **`internal/tui/convoy`** - Consider golden file tests for view output
6. **`internal/constants`** - Test any validation logic
---
## Missing Test Types
| Type | Current State | Recommendation |
|------|--------------|----------------|
| Unit tests | Good coverage where present | Add for P0-P1 packages |
| Integration tests | 15 dedicated files | Adequate |
| E2E tests | `browser_e2e_test.go` | Consider more CLI E2E |
| Fuzz tests | None | Consider for parsers (`formula/parser.go`) |
| Benchmark tests | None visible | Add for hot paths (`lock`, `events`) |
---
## Actionable Next Steps
1. **Fix flaky test**: Refactor `feed/curator_test.go` to use channels/polling
2. **Add lock tests**: Highest priority - bugs here break multi-agent
3. **Add events tests**: Core observability must be tested
4. **Add checkpoint tests**: Session recovery is critical path
5. **Run with race detector**: `go test -race ./...` to catch data races
6. **Consider `-short` flag**: Add `testing.Short()` checks to slow tests

View File

@@ -1,372 +0,0 @@
# Wisp Squash Design: Cadences, Rules, Templates
Design specification for how wisps squash to digests in Gas Town.
## Problem Statement
Wisps are ephemeral molecules that need to be condensed into digests for:
- **Audit trail**: What happened, when, by whom
- **Activity feed**: Observable progress in the capability ledger
- **Space efficiency**: Ephemeral data doesn't accumulate indefinitely
Currently under-designed:
- **Cadences**: When should squash happen?
- **Templates**: What should digests contain?
- **Retention**: How long to keep, when to aggregate?
## Squash Cadences
### Patrol Wisps (Deacon, Witness, Refinery)
**Trigger**: End of each patrol cycle
```
patrol-start → steps → loop-or-exit step → squash → new wisp
```
| Decision Point | Action |
|----------------|--------|
| `loop-or-exit` with low context | Squash current wisp, create new wisp |
| `loop-or-exit` with high context | Squash current wisp, handoff |
| Extraordinary action | Squash immediately, handoff |
**Rationale**: Each patrol cycle is a logical unit. Squashing per-cycle keeps
digests meaningful and prevents context-filling sessions from losing history.
### Work Wisps (Polecats)
**Trigger**: Before `gt done` or molecule completion
```
work-assigned → steps → all-complete → squash → gt done → merge queue
```
Polecats typically use regular molecules (not wisps), but when wisps are used
for exploratory work:
| Scenario | Action |
|----------|--------|
| Molecule completes | Squash to digest |
| Molecule abandoned | Burn (no digest) |
| Molecule handed off | Squash, include handoff context |
### Time-Based Cadences (Future)
For long-running molecules that span multiple sessions:
| Duration | Action |
|----------|--------|
| Session ends | Auto-squash if molecule in progress |
| > 24 hours | Create checkpoint digest |
| > 7 days | Warning: stale molecule |
**Not implemented initially** - simplicity first.
## Summary Templates
### Template Structure
Digests have three sections:
1. **Header**: Standard metadata (who, what, when)
2. **Body**: Context-specific content (from template)
3. **Footer**: System metrics (steps, duration, commit refs)
### Patrol Digest Template
```markdown
## Patrol Digest: {{.Agent}}
**Cycle**: {{.CycleNumber}} | **Duration**: {{.Duration}}
### Actions Taken
{{range .Actions}}
- {{.Icon}} {{.Description}}
{{end}}
### Issues Filed
{{range .IssuesFiled}}
- {{.ID}}: {{.Title}}
{{end}}
### Metrics
- Inbox: {{.InboxCount}} messages processed
- Health checks: {{.HealthChecks}}
- Alerts: {{.AlertCount}}
```
### Work Digest Template
```markdown
## Work Digest: {{.IssueTitle}}
**Issue**: {{.IssueID}} | **Agent**: {{.Agent}} | **Duration**: {{.Duration}}
### Summary
{{.Summary}}
### Steps Completed
{{range .Steps}}
- [{{.Status}}] {{.Title}}
{{end}}
### Artifacts
- Commits: {{range .Commits}}{{.Short}}, {{end}}
- Files changed: {{.FilesChanged}}
- Lines: +{{.LinesAdded}} -{{.LinesRemoved}}
```
### Formula-Defined Templates
Formulas can define custom squash templates in `[squash]` section:
```toml
formula = "mol-my-workflow"
version = 1
[squash]
template = """
## {{.Title}} Complete
Duration: {{.Duration}}
Key metrics:
{{range .Steps}}
- {{.ID}}: {{.CustomField}}
{{end}}
"""
# Template variables from step outputs
[squash.vars]
include_metrics = true
summary_length = "short" # short | medium | detailed
```
**Resolution order**:
1. Formula-defined template (if present)
2. Type-specific default (patrol vs work)
3. Minimal fallback (current behavior)
## Retention Rules
### Digest Lifecycle
```
Wisp → Squash → Digest (active) → Digest (archived) → Rollup
```
| Phase | Duration | Storage |
|-------|----------|---------|
| Active | 30 days | `.beads/issues.jsonl` |
| Archived | 1 year | `.beads/archive/` (compressed) |
| Rollup | Permanent | Weekly/monthly summaries |
### Rollup Strategy
After retention period, digests aggregate into rollups:
**Weekly Patrol Rollup**:
```markdown
## Week of {{.WeekStart}}
| Agent | Cycles | Issues Filed | Merges | Incidents |
|-------|--------|--------------|--------|-----------|
| Deacon | 140 | 3 | - | 0 |
| Witness | 168 | 12 | - | 2 |
| Refinery | 84 | 0 | 47 | 1 |
```
**Monthly Work Rollup**:
```markdown
## {{.Month}} Work Summary
Issues completed: {{.TotalIssues}}
Total duration: {{.TotalDuration}}
Contributors: {{range .Contributors}}{{.Name}}, {{end}}
Top categories:
{{range .Categories}}
- {{.Name}}: {{.Count}} issues
{{end}}
```
### Retention Configuration
Per-rig settings in `config.json`:
```json
{
"retention": {
"digest_active_days": 30,
"digest_archive_days": 365,
"rollup_weekly": true,
"rollup_monthly": true,
"auto_archive": true
}
}
```
## Implementation Plan
### Phase 1: Template System (MVP)
1. Add `[squash]` section parsing to formula loader
2. Create default templates for patrol and work digests
3. Enhance `bd mol squash` to use templates
4. Add `--template` flag for override
### Phase 2: Cadence Automation
1. Hook squash into `gt done` flow
2. Add patrol cycle completion detection
3. Emit squash events for activity feed
### Phase 3: Retention & Archival
1. Implement digest aging (active → archived)
2. Add `bd archive` command for manual archival
3. Create rollup generator for weekly/monthly summaries
4. Background daemon task for auto-archival
## Commands
### Squash with Template
```bash
# Use formula-defined template
bd mol squash <id>
# Use explicit template
bd mol squash <id> --template=detailed
# Add custom summary
bd mol squash <id> --summary="Patrol complete: 3 issues filed"
```
### View Digests
```bash
# List recent digests
bd list --label=digest
# View rollups
bd rollup list
bd rollup show weekly-2025-01
```
### Archive Management
```bash
# Archive old digests
bd archive --older-than=30d
# Generate rollup
bd rollup generate --week=2025-01
# Restore from archive
bd archive restore <digest-id>
```
## Activity Feed Integration
Digests feed into the activity feed for observability:
```json
{
"type": "digest",
"agent": "greenplace/witness",
"timestamp": "2025-12-30T10:00:00Z",
"summary": "Patrol cycle 47 complete",
"metrics": {
"issues_filed": 2,
"polecats_nudged": 1,
"duration_minutes": 12
}
}
```
The feed curator (daemon) can aggregate these for dashboards.
## Formula Example
Complete formula with squash configuration:
```toml
formula = "mol-witness-patrol"
version = 1
type = "workflow"
description = "Witness patrol cycle"
[squash]
trigger = "on_complete"
template_type = "patrol"
include_metrics = true
[[steps]]
id = "inbox-check"
title = "Check inbox"
description = "Process messages and escalations"
[[steps]]
id = "health-scan"
title = "Scan polecat health"
description = "Check all polecats for stuck/idle"
[[steps]]
id = "nudge-stuck"
title = "Nudge stuck workers"
description = "Send nudges to idle polecats"
[[steps]]
id = "loop-or-exit"
title = "Loop or exit decision"
description = "Decide whether to continue or handoff"
```
## Migration
### Existing Digests
Current minimal digests remain valid. New template system is additive:
- Old digests: Title, basic description
- New digests: Structured content, metrics
### Backward Compatibility
- `bd mol squash` without template uses current behavior
- Formulas without `[squash]` section use type defaults
- No breaking changes to existing workflows
## Design Decisions
### Why Squash Per-Cycle?
**Alternative**: Squash on session end only
**Rejected because**:
- Sessions can crash mid-cycle (lost audit trail)
- High-context sessions may span multiple cycles
- Per-cycle gives finer granularity
### Why Formula-Defined Templates?
**Alternative**: Hard-coded templates per role
**Rejected because**:
- Different workflows have different metrics
- Extensibility for custom formulas
- Separation of concerns (workflow defines its own output)
### Why Retain Forever (as Rollups)?
**Alternative**: Delete after N days
**Rejected because**:
- Capability ledger needs long-term history
- Rollups are small (aggregate stats)
- Audit requirements vary by use case
## Future Considerations
- **Search**: Full-text search over archived digests
- **Analytics**: Metrics aggregation dashboard
- **Export**: Export digests to external systems
- **Compliance**: Configurable retention for regulatory needs