diff --git a/docs/convoy.md b/docs/concepts/convoy.md similarity index 98% rename from docs/convoy.md rename to docs/concepts/convoy.md index 47c37533..f096e71f 100644 --- a/docs/convoy.md +++ b/docs/concepts/convoy.md @@ -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 diff --git a/docs/identity.md b/docs/concepts/identity.md similarity index 100% rename from docs/identity.md rename to docs/concepts/identity.md diff --git a/docs/molecules.md b/docs/concepts/molecules.md similarity index 76% rename from docs/molecules.md rename to docs/concepts/molecules.md index 2a800879..a421d6b3 100644 --- a/docs/molecules.md +++ b/docs/concepts/molecules.md @@ -154,6 +154,50 @@ gt mol squash # Squash attached molecule gt mol step done # 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 # 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 --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 diff --git a/docs/polecat-lifecycle.md b/docs/concepts/polecat-lifecycle.md similarity index 98% rename from docs/polecat-lifecycle.md rename to docs/concepts/polecat-lifecycle.md index faeb925a..ddcdf158 100644 --- a/docs/polecat-lifecycle.md +++ b/docs/concepts/polecat-lifecycle.md @@ -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 diff --git a/docs/propulsion-principle.md b/docs/concepts/propulsion-principle.md similarity index 100% rename from docs/propulsion-principle.md rename to docs/concepts/propulsion-principle.md diff --git a/docs/architecture.md b/docs/design/architecture.md similarity index 96% rename from docs/architecture.md rename to docs/design/architecture.md index 5d9980ea..8a53e688 100644 --- a/docs/architecture.md +++ b/docs/design/architecture.md @@ -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 diff --git a/docs/escalation.md b/docs/design/escalation.md similarity index 100% rename from docs/escalation.md rename to docs/design/escalation.md diff --git a/docs/federation.md b/docs/design/federation.md similarity index 97% rename from docs/federation.md rename to docs/design/federation.md index 7b8983be..edb84a5d 100644 --- a/docs/federation.md +++ b/docs/design/federation.md @@ -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 diff --git a/docs/mail-protocol.md b/docs/design/mail-protocol.md similarity index 100% rename from docs/mail-protocol.md rename to docs/design/mail-protocol.md diff --git a/docs/design/operational-state.md b/docs/design/operational-state.md new file mode 100644 index 00000000..c0f602ef --- /dev/null +++ b/docs/design/operational-state.md @@ -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 `:` 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= \ + --actor= --target= --payload='' + +# Update state label +bd update --add-label=: --remove-label=: + +# Query current state +bd list --type=role --label=: + +# Query state history +bd list --type=event --target= + +# Boot management +gt dog status boot +gt dog call boot +gt dog prime boot +``` + +--- + +*Events are the source of truth. Labels are the cache.* diff --git a/docs/property-layers.md b/docs/design/property-layers.md similarity index 100% rename from docs/property-layers.md rename to docs/design/property-layers.md diff --git a/docs/watchdog-chain.md b/docs/design/watchdog-chain.md similarity index 100% rename from docs/watchdog-chain.md rename to docs/design/watchdog-chain.md diff --git a/docs/hanoi-demo.md b/docs/examples/hanoi-demo.md similarity index 100% rename from docs/hanoi-demo.md rename to docs/examples/hanoi-demo.md diff --git a/docs/hop/decisions/009-session-events-architecture.md b/docs/hop/decisions/009-session-events-architecture.md deleted file mode 100644 index 88943f83..00000000 --- a/docs/hop/decisions/009-session-events-architecture.md +++ /dev/null @@ -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 diff --git a/docs/operational-state.md b/docs/operational-state.md deleted file mode 100644 index dd9cdef3..00000000 --- a/docs/operational-state.md +++ /dev/null @@ -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 `:` 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 ` (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= \ - --actor= --target= --payload='' - -# Update state label -bd update --add-label=: --remove-label=: - -# Query current state -bd list --type=role --label=: - -# Query state history -bd list --type=event --target= - -# Boot management -gt dog status boot -gt dog call boot -gt dog prime boot -``` - ---- - -*Events are the source of truth. Labels are the cache.* diff --git a/docs/understanding-gas-town.md b/docs/overview.md similarity index 96% rename from docs/understanding-gas-town.md rename to docs/overview.md index 353fc924..637243b9 100644 --- a/docs/understanding-gas-town.md +++ b/docs/overview.md @@ -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 diff --git a/docs/polecat-wisp-architecture.md b/docs/polecat-wisp-architecture.md deleted file mode 100644 index cdb5cddb..00000000 --- a/docs/polecat-wisp-architecture.md +++ /dev/null @@ -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 -``` - -### 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 --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) diff --git a/docs/reference.md b/docs/reference.md index 3c027d94..bbe0f8dd 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -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. diff --git a/docs/reviews/infrastructure-review.md b/docs/reviews/infrastructure-review.md deleted file mode 100644 index 38f5ebfb..00000000 --- a/docs/reviews/infrastructure-review.md +++ /dev/null @@ -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) diff --git a/docs/swarm.md b/docs/swarm.md deleted file mode 100644 index a8268cc4..00000000 --- a/docs/swarm.md +++ /dev/null @@ -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 diff --git a/docs/test-coverage-review.md b/docs/test-coverage-review.md deleted file mode 100644 index a59ef6cf..00000000 --- a/docs/test-coverage-review.md +++ /dev/null @@ -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 diff --git a/docs/wisp-squash-design.md b/docs/wisp-squash-design.md deleted file mode 100644 index 74dc5c2a..00000000 --- a/docs/wisp-squash-design.md +++ /dev/null @@ -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 - -# Use explicit template -bd mol squash --template=detailed - -# Add custom summary -bd mol squash --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 -``` - -## 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