Add infrastructure formulas for dog tasks (gt-0x5og.5)

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

Each formula follows the standard TOML structure with:
- Description and dog contract
- Step-by-step workflow with dependencies
- Variable definitions
- Squash configuration for digests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-30 10:35:53 -08:00
parent ddf5b5a9f4
commit c6a9201b5e
5 changed files with 1206 additions and 0 deletions

View File

@@ -0,0 +1,209 @@
description = """
Archive completed convoys and notify overseer.
Dogs execute this formula when convoys complete. The Deacon detects completed
convoys (all tracked issues closed) and slings this work to a dog for:
- Generating convoy summary
- Archiving convoy state
- Notifying the overseer (Mayor)
- Updating activity feed
## Dog Contract
This is infrastructure work. You:
1. Receive convoy ID via hook_bead
2. Generate summary of completed work
3. Archive to appropriate location
4. Notify stakeholders
5. Return to kennel
## Variables
| Variable | Source | Description |
|----------|--------|-------------|
| convoy | hook_bead | The convoy ID to archive |
## Failure Modes
| Situation | Action |
|-----------|--------|
| Convoy not found | Exit with error, notify Deacon |
| Archive location full | Create space, retry, or escalate |
| Mail send fails | Retry once, then proceed anyway |"""
formula = "mol-convoy-cleanup"
version = 1
[squash]
trigger = "on_complete"
template_type = "work"
include_metrics = true
[[steps]]
id = "load-convoy"
title = "Load convoy and verify completion"
description = """
Load the convoy bead and verify it's ready for archival.
**1. Check your assignment:**
```bash
gt mol status # Shows hook_bead = convoy ID
bd show {{convoy}} # Full convoy details
```
**2. Verify convoy is complete:**
- Status should be 'closed' or all tracked issues closed
- If convoy is still open, exit - Deacon dispatched too early
```bash
bd show {{convoy}}
# Check 'tracks' or 'dependencies' field
# All tracked issues should be closed
```
**3. Gather convoy metadata:**
- Start date (created_at)
- End date (last closure timestamp)
- Total issues tracked
- Contributing polecats
**Exit criteria:** Convoy loaded, verified complete, metadata gathered."""
[[steps]]
id = "generate-summary"
title = "Generate convoy summary"
needs = ["load-convoy"]
description = """
Create a summary of the convoy's completed work.
**1. Collect tracked issue details:**
```bash
# For each tracked issue
bd show <tracked-id>
# Extract: title, type, assignee, duration
```
**2. Calculate statistics:**
- Total duration (convoy start to finish)
- Issues by type (task, bug, feature)
- Contributors (unique assignees)
- Commits generated (if tracked)
**3. Create summary text:**
```markdown
## Convoy Summary: {{convoy.title}}
**Duration**: X days/hours
**Issues completed**: N
### Work Breakdown
- Tasks: N
- Bugs: N
- Features: N
### Contributors
- polecat-1: N issues
- polecat-2: N issues
### Key Outcomes
- <notable achievement 1>
- <notable achievement 2>
```
**Exit criteria:** Summary text generated and ready for notification."""
[[steps]]
id = "archive-convoy"
title = "Archive convoy to cold storage"
needs = ["generate-summary"]
description = """
Move convoy from active to archived state.
**1. Update convoy status:**
```bash
bd update {{convoy}} --status=archived
# Or close if not already closed
bd close {{convoy}} --reason="Convoy complete, archived"
```
**2. Generate archive record:**
The convoy bead with all metadata is the archive record. Beads retention
handles moving it to `.beads/archive/` after the retention period.
**3. Verify archive:**
```bash
bd show {{convoy}}
# Status should reflect archived state
```
**4. Sync to persist:**
```bash
bd sync
```
**Exit criteria:** Convoy archived, changes synced."""
[[steps]]
id = "notify-overseer"
title = "Send completion notification to overseer"
needs = ["archive-convoy"]
description = """
Notify the Mayor (overseer) of convoy completion.
**1. Send completion mail:**
```bash
gt mail send mayor/ -s "Convoy complete: {{convoy.title}}" -m "$(cat <<EOF
Convoy {{convoy}} has completed and been archived.
## Summary
{{generated_summary}}
## Metrics
- Duration: {{duration}}
- Issues: {{issue_count}}
- Contributors: {{contributor_list}}
This convoy has been archived. View details: bd show {{convoy}}
EOF
)"
```
**2. Post to activity feed:**
The convoy closure already creates a feed entry. Verify:
```bash
gt feed --since 5m
# Should show convoy completion
```
**Exit criteria:** Overseer notified via mail, activity feed updated."""
[[steps]]
id = "return-to-kennel"
title = "Signal completion and return to kennel"
needs = ["notify-overseer"]
description = """
Signal work complete and return to available pool.
**1. Signal completion to Deacon:**
```bash
gt mail send deacon/ -s "DOG_DONE $(hostname)" -m "Task: convoy-cleanup
Convoy: {{convoy}}
Status: COMPLETE
Duration: {{work_duration}}
Ready for next assignment."
```
**2. Clean workspace:**
- No convoy-specific state to clean
- Workspace should already be clean
**3. Return to kennel:**
Dog returns to available state in the pool. Deacon will assign next work
or retire the dog if pool is oversized.
**Exit criteria:** Deacon notified, dog ready for next work or retirement."""
[vars]
[vars.convoy]
description = "The convoy ID to archive"
required = true

View File

@@ -0,0 +1,208 @@
description = """
Propagate cross-rig dependency resolution.
Dogs execute this formula when dependencies resolve across rig boundaries.
When an issue in one rig closes, dependent issues in other rigs may unblock.
This formula handles:
- Finding cross-rig dependents
- Notifying affected rigs
- Updating blocked status
- Triggering work dispatch if appropriate
## Dog Contract
This is infrastructure work. You:
1. Receive closed issue ID via hook_bead
2. Find all cross-rig dependents (issues in other rigs blocked by this)
3. Notify affected Witnesses
4. Optionally trigger dispatch if issues are now ready
5. Return to kennel
## Variables
| Variable | Source | Description |
|----------|--------|-------------|
| resolved_issue | hook_bead | The issue that just closed |
## Why Dogs?
Cross-rig work requires multi-rig worktrees. Dogs have these, polecats don't.
The Deacon detects the closure, but the propagation needs rig access."""
formula = "mol-dep-propagate"
version = 1
[squash]
trigger = "on_complete"
template_type = "work"
include_metrics = true
[[steps]]
id = "load-resolved-issue"
title = "Load resolved issue and find dependents"
description = """
Load the closed issue and identify cross-rig dependents.
**1. Check your assignment:**
```bash
gt mol status # Shows hook_bead = resolved issue ID
bd show {{resolved_issue}} # Full issue details
```
**2. Verify issue is closed:**
```bash
bd show {{resolved_issue}}
# Status should be 'closed' or similar terminal state
```
**3. Find dependents (issues blocked by this one):**
```bash
bd show {{resolved_issue}}
# Look at 'blocks' field - these are issues waiting on this one
```
**4. Identify cross-rig dependents:**
- Same-rig dependents: Already handled by local beads (automatic unblock)
- Cross-rig dependents: Different prefix (e.g., gt- vs bd-) need propagation
```bash
# Example: resolved_issue is bd-xxx, blocks gt-yyy
# gt-yyy is cross-rig and needs notification
```
**Exit criteria:** Resolved issue loaded, cross-rig dependents identified."""
[[steps]]
id = "update-blocked-status"
title = "Update blocked status in affected rigs"
needs = ["load-resolved-issue"]
description = """
Update the blocked status for cross-rig dependents.
**1. For each cross-rig dependent:**
```bash
# Navigate to the rig containing the dependent issue
# Dogs have multi-rig worktrees for this
bd show <dependent-id>
# Check if this was the only blocker
```
**2. Check if now unblocked:**
```bash
bd blocked <dependent-id>
# If empty or only shows other blockers, issue is now unblocked
```
**3. Verify automatic unblock worked:**
Beads should auto-update blocked status when dependencies close.
This step verifies and fixes if needed:
```bash
# If still showing as blocked by resolved issue (shouldn't happen):
bd dep remove <dependent-id> {{resolved_issue}}
```
**Exit criteria:** All cross-rig dependents have updated blocked status."""
[[steps]]
id = "notify-witnesses"
title = "Notify affected rig Witnesses"
needs = ["update-blocked-status"]
description = """
Send notifications to Witnesses of affected rigs.
**1. Group dependents by rig:**
- gastown/witness: for gt-* issues
- beads/witness: for bd-* issues
- etc.
**2. For each affected rig, send notification:**
```bash
gt mail send <rig>/witness -s "Dependency resolved: {{resolved_issue}}" -m "$(cat <<EOF
External dependency has closed, unblocking work in your rig.
## Resolved Issue
- ID: {{resolved_issue}}
- Title: {{resolved_issue.title}}
- Rig: {{resolved_issue.prefix}}
## Unblocked in Your Rig
{{range dependent}}
- {{dependent.id}}: {{dependent.title}} ({{dependent.status}})
{{end}}
These issues may now proceed. Check bd ready for available work.
EOF
)"
```
**3. Log notification:**
Note which Witnesses were notified for audit trail.
**Exit criteria:** All affected Witnesses notified."""
[[steps]]
id = "trigger-dispatch"
title = "Optionally trigger work dispatch"
needs = ["notify-witnesses"]
description = """
Trigger work dispatch for newly-unblocked issues if appropriate.
**1. For each unblocked issue, check if ready for work:**
```bash
bd show <issue-id>
# Check:
# - Status: should be 'open' (not already in_progress)
# - Priority: high priority may warrant immediate dispatch
# - No other blockers: bd blocked should be empty
```
**2. Decision: trigger dispatch?**
| Condition | Action |
|-----------|--------|
| High priority (P0-P1) + open + unblocked | Recommend immediate dispatch |
| Medium priority (P2) + open + unblocked | Note in Witness notification |
| Low priority (P3-P4) | Let Witness handle in next patrol |
**3. If triggering dispatch:**
```bash
# For high priority, suggest to Mayor:
gt mail send mayor/ -s "High-priority work unblocked: <issue>" -m "..."
```
Usually, the Witness notification (previous step) is sufficient - Witnesses
handle their own dispatch decisions.
**Exit criteria:** Dispatch recommendations sent where appropriate."""
[[steps]]
id = "return-to-kennel"
title = "Signal completion and return to kennel"
needs = ["trigger-dispatch"]
description = """
Signal work complete and return to available pool.
**1. Signal completion to Deacon:**
```bash
gt mail send deacon/ -s "DOG_DONE $(hostname)" -m "Task: dep-propagate
Resolved: {{resolved_issue}}
Cross-rig dependents: {{dependent_count}}
Witnesses notified: {{witness_list}}
Status: COMPLETE
Ready for next assignment."
```
**2. Update activity feed:**
The propagation creates implicit feed entries (dependency updates).
No explicit entry needed.
**3. Return to kennel:**
Dog returns to available state in the pool.
**Exit criteria:** Deacon notified, dog ready for next work or retirement."""
[vars]
[vars.resolved_issue]
description = "The issue ID that just closed and needs propagation"
required = true

View File

@@ -0,0 +1,227 @@
description = """
Generate daily digest for overseer (Mayor).
Dogs execute this formula on a scheduled basis (daily, or triggered by plugin)
to create summary digests of Gas Town activity. This aggregates:
- Work completed across all rigs
- Issues filed and closed
- Incidents and escalations
- Agent health metrics
- Key statistics and trends
## Dog Contract
This is infrastructure work. You:
1. Receive digest period via hook_bead (e.g., daily, weekly)
2. Collect data from all rigs you have access to
3. Generate formatted digest
4. Send to overseer
5. Archive digest as bead
6. Return to kennel
## Variables
| Variable | Source | Description |
|----------|--------|-------------|
| period | hook_bead | Time period for digest (daily, weekly) |
| since | computed | Start timestamp for data collection |
| until | computed | End timestamp (usually now) |
## Why Dogs?
Digest generation requires reading from multiple rigs. Dogs have multi-rig
worktrees. This is also a periodic task that doesn't need a dedicated polecat."""
formula = "mol-digest-generate"
version = 1
[squash]
trigger = "on_complete"
template_type = "work"
include_metrics = true
[[steps]]
id = "determine-period"
title = "Determine digest time period"
description = """
Establish the time range for this digest.
**1. Check assignment:**
```bash
gt mol status # Shows period type
```
**2. Calculate time range:**
| Period | Since | Until |
|--------|-------|-------|
| daily | Yesterday 00:00 | Today 00:00 |
| weekly | Last Monday 00:00 | This Monday 00:00 |
| custom | From hook_bead | From hook_bead |
```bash
# For daily digest
since=$(date -v-1d +%Y-%m-%dT00:00:00)
until=$(date +%Y-%m-%dT00:00:00)
```
**3. Record period for reporting:**
Note the exact timestamps for the digest header.
**Exit criteria:** Time period established with precise timestamps."""
[[steps]]
id = "collect-rig-data"
title = "Collect activity data from all rigs"
needs = ["determine-period"]
description = """
Gather activity data from each rig in the town.
**1. List accessible rigs:**
```bash
gt rigs
# Returns list of rigs: gastown, beads, etc.
```
**2. For each rig, collect:**
a) **Issues filed and closed:**
```bash
# From rig beads
bd list --created-after={{since}} --created-before={{until}}
bd list --status=closed --updated-after={{since}}
```
b) **Agent activity:**
```bash
gt polecats <rig> # Polecat activity
gt feed --since={{since}} # Activity feed entries
```
c) **Merges:**
```bash
# Git log for merges to main
git -C <rig-path> log --merges --since={{since}} --oneline main
```
d) **Incidents:**
```bash
# Issues tagged as incident or high-priority
bd list --label=incident --created-after={{since}}
```
**3. Aggregate across rigs:**
Sum counts, collect notable items, identify trends.
**Exit criteria:** Raw data collected from all accessible rigs."""
[[steps]]
id = "generate-digest"
title = "Generate formatted digest"
needs = ["collect-rig-data"]
description = """
Transform collected data into formatted digest.
**1. Calculate summary statistics:**
- Total issues filed
- Total issues closed
- Net change (closed - filed)
- By type (task, bug, feature)
- By rig
**2. Identify highlights:**
- Biggest completions (epics, large features)
- Incidents (any P0/P1 issues)
- Notable trends (increasing backlog, fast closure rate)
**3. Generate digest text:**
```markdown
# Gas Town Daily Digest: {{date}}
## Summary
- **Issues filed**: N (tasks: X, bugs: Y, features: Z)
- **Issues closed**: N
- **Net change**: +/-N
## By Rig
| Rig | Filed | Closed | Active Polecats |
|-----|-------|--------|-----------------|
| gastown | X | Y | Z |
| beads | X | Y | Z |
## Highlights
### Completed
- {{epic or feature}} - completed by {{polecat}}
### Incidents
- {{incident summary if any}}
## Agent Health
- Polecats spawned: N
- Polecats retired: N
- Average work duration: Xh
## Trends
- Backlog: {{increasing/stable/decreasing}}
- Throughput: {{issues/day}}
```
**Exit criteria:** Formatted digest ready for delivery."""
[[steps]]
id = "send-digest"
title = "Send digest to overseer"
needs = ["generate-digest"]
description = """
Deliver digest to the Mayor.
**1. Send via mail:**
```bash
gt mail send mayor/ -s "Gas Town Digest: {{date}}" -m "$(cat <<EOF
{{formatted_digest}}
EOF
)"
```
**2. Archive as bead:**
Create a digest bead for permanent record:
```bash
bd create --title="Digest: {{date}}" --type=digest \
--description="{{formatted_digest}}" \
--label=digest,{{period}}
```
**3. Sync:**
```bash
bd sync
```
**Exit criteria:** Digest sent to Mayor and archived as bead."""
[[steps]]
id = "return-to-kennel"
title = "Signal completion and return to kennel"
needs = ["send-digest"]
description = """
Signal work complete and return to available pool.
**1. Signal completion to Deacon:**
```bash
gt mail send deacon/ -s "DOG_DONE $(hostname)" -m "Task: digest-generate
Period: {{period}}
Date range: {{since}} to {{until}}
Status: COMPLETE
Digest sent to Mayor.
Ready for next assignment."
```
**2. Return to kennel:**
Dog returns to available state in the pool.
**Exit criteria:** Deacon notified, dog ready for next work."""
[vars]
[vars.period]
description = "The digest period type (daily, weekly, custom)"
required = true
default = "daily"

View File

@@ -0,0 +1,312 @@
description = """
Find and reassign orphaned work.
Dogs execute this formula to scan for orphaned state across the town:
- Issues marked in_progress with no active polecat
- Molecules attached but worker gone
- Merge queue entries with dead owners
- Wisps from terminated sessions
This is a cleanup and recovery formula. Found orphans are either:
- Reassigned to available workers
- Reset to open status for next dispatch
- Escalated if data loss occurred
## Dog Contract
This is infrastructure work. You:
1. Receive scan scope via hook_bead (rig or town-wide)
2. Scan for orphaned state
3. Classify and triage orphans
4. Take recovery action
5. Report findings
6. Return to kennel
## Variables
| Variable | Source | Description |
|----------|--------|-------------|
| scope | hook_bead | Scan scope: 'town' or specific rig name |
## Why Dogs?
Orphan scanning requires multi-rig access and may need to interact with
multiple Witnesses. Dogs have the cross-rig worktrees needed for this."""
formula = "mol-orphan-scan"
version = 1
[squash]
trigger = "on_complete"
template_type = "work"
include_metrics = true
[[steps]]
id = "determine-scope"
title = "Determine scan scope"
description = """
Establish what to scan for orphans.
**1. Check assignment:**
```bash
gt mol status # Shows scope in hook_bead
```
**2. Resolve scope:**
- 'town': Scan all rigs
- '<rig>': Scan specific rig only
```bash
# If town-wide
gt rigs # Get list of all rigs
# If specific rig
# Just use that rig
```
**Exit criteria:** Scope determined, rig list established."""
[[steps]]
id = "scan-orphaned-issues"
title = "Scan for orphaned issues"
needs = ["determine-scope"]
description = """
Find issues marked in_progress with no active worker.
**1. For each rig in scope, find in_progress issues:**
```bash
bd list --status=in_progress
```
**2. For each in_progress issue, check assignee:**
```bash
bd show <issue-id>
# Get assignee field
```
**3. Check if assignee session exists:**
```bash
# If assignee is a polecat
gt polecats <rig> # Is the polecat active?
tmux has-session -t <session> 2>/dev/null
```
**4. Identify orphans:**
- Issue in_progress + assignee session dead = orphan
- Issue in_progress + no assignee = orphan
Record each orphan with:
- Issue ID
- Last assignee (if any)
- How long orphaned (last update timestamp)
**Exit criteria:** Orphaned issues identified."""
[[steps]]
id = "scan-orphaned-molecules"
title = "Scan for orphaned molecules"
needs = ["determine-scope"]
description = """
Find molecules attached to dead sessions.
**1. List active molecules:**
```bash
bd mol list --active
```
**2. For each molecule, check owner session:**
```bash
bd mol show <mol-id>
# Get agent/session info
```
**3. Check if owner session exists:**
```bash
tmux has-session -t <session> 2>/dev/null
```
**4. Identify orphans:**
- Molecule in_progress + owner session dead = orphan
- Molecule hooked + owner session dead = orphan
Record each orphan for triage.
**Exit criteria:** Orphaned molecules identified."""
[[steps]]
id = "scan-orphaned-wisps"
title = "Scan for orphaned wisps"
needs = ["determine-scope"]
description = """
Find wisps from terminated sessions.
**1. List wisps in ephemeral storage:**
```bash
ls .beads-wisp/ # Or equivalent location
```
**2. For each wisp, check spawner session:**
Wisps should have metadata indicating the spawning session.
**3. Identify orphans:**
- Wisp age > 1 hour + spawner session dead = orphan
- Wisp with no spawner metadata = orphan
**4. Check for unsquashed content:**
Orphaned wisps may have audit-worthy content that wasn't squashed.
**Exit criteria:** Orphaned wisps identified."""
[[steps]]
id = "triage-orphans"
title = "Classify and triage orphans"
needs = ["scan-orphaned-issues", "scan-orphaned-molecules", "scan-orphaned-wisps"]
description = """
Classify orphans by severity and determine action.
**1. Classify by type:**
| Type | Severity | Typical Action |
|------|----------|----------------|
| Issue in_progress, no work done | Low | Reset to open |
| Issue in_progress, work in progress | Medium | Check branch, reassign |
| Molecule mid-execution | Medium | Resume or restart |
| Wisp with content | Low | Squash or burn |
| Wisp empty | None | Delete |
**2. Check for data loss:**
For issues/molecules with possible work:
```bash
# Check for branch with work
git branch -a | grep <polecat-or-issue>
git log --oneline <branch>
```
**3. Categorize for action:**
- RESET: Return to open status for normal dispatch
- REASSIGN: Assign to specific worker immediately
- RECOVER: Salvage work from branch/state
- ESCALATE: Data loss or complex situation
- BURN: Safe to delete (empty wisps, etc.)
**Exit criteria:** All orphans categorized with planned action."""
[[steps]]
id = "execute-recovery"
title = "Execute recovery actions"
needs = ["triage-orphans"]
description = """
Take action on each orphan based on triage.
**1. RESET orphans:**
```bash
bd update <issue> --status=open --assignee=""
# Clears in_progress, ready for dispatch
```
**2. REASSIGN orphans:**
```bash
# Notify Witness to handle assignment
gt mail send <rig>/witness -s "Orphan needs assignment: <issue>" \
-m "Issue <id> was orphaned. Has partial work. Needs reassignment."
```
**3. RECOVER orphans:**
```bash
# For issues with work on branch:
# - Preserve the branch
# - Create recovery note
bd update <issue> --status=open \
--note="Recovery: work exists on branch <branch>"
```
**4. ESCALATE orphans:**
```bash
gt mail send mayor/ -s "Orphan requires escalation: <issue>" \
-m "Issue <id> orphaned with possible data loss.
Details: ...
Recommended action: ..."
```
**5. BURN orphans:**
```bash
# For empty wisps, etc.
rm .beads-wisp/<wisp-file>
```
**Exit criteria:** All orphans handled."""
[[steps]]
id = "report-findings"
title = "Generate and send orphan report"
needs = ["execute-recovery"]
description = """
Create summary report of orphan scan and actions.
**1. Generate report:**
```markdown
## Orphan Scan Report: {{timestamp}}
**Scope**: {{scope}}
**Orphans found**: {{total_count}}
### By Type
- Issues: {{issue_count}}
- Molecules: {{mol_count}}
- Wisps: {{wisp_count}}
### Actions Taken
- Reset to open: {{reset_count}}
- Reassigned: {{reassign_count}}
- Recovered: {{recover_count}}
- Escalated: {{escalate_count}}
- Burned: {{burn_count}}
### Details
{{#each orphan}}
- {{type}} {{id}}: {{action}} - {{reason}}
{{/each}}
```
**2. Send to Deacon (for logs):**
```bash
gt mail send deacon/ -s "Orphan scan complete: {{total_count}} found" \
-m "{{report}}"
```
**3. Send to Mayor (if escalations):**
```bash
# Only if there were escalations
gt mail send mayor/ -s "Orphan scan: {{escalate_count}} escalations" \
-m "{{escalations_section}}"
```
**Exit criteria:** Reports sent."""
[[steps]]
id = "return-to-kennel"
title = "Signal completion and return to kennel"
needs = ["report-findings"]
description = """
Signal work complete and return to available pool.
**1. Signal completion to Deacon:**
```bash
gt mail send deacon/ -s "DOG_DONE $(hostname)" -m "Task: orphan-scan
Scope: {{scope}}
Orphans found: {{total_count}}
Actions taken: {{action_summary}}
Status: COMPLETE
Ready for next assignment."
```
**2. Return to kennel:**
Dog returns to available state in the pool.
**Exit criteria:** Deacon notified, dog ready for next work."""
[vars]
[vars.scope]
description = "Scan scope: 'town' or specific rig name"
required = true
default = "town"

View File

@@ -0,0 +1,250 @@
description = """
Clean stale sessions and garbage collect.
Dogs execute this formula to clean up dead sessions, orphaned processes, and
other system cruft. This is the garbage collector for Gas Town's runtime:
- Dead tmux sessions (no Claude process)
- Orphaned Claude processes (no tmux parent)
- Stale wisps past retention
- Leftover state files
## Dog Contract
This is infrastructure work. You:
1. Receive gc scope via hook_bead (aggressive or conservative)
2. Identify garbage across the system
3. Safely remove dead state
4. Report what was cleaned
5. Return to kennel
## Variables
| Variable | Source | Description |
|----------|--------|-------------|
| mode | hook_bead | GC mode: 'conservative' (safe) or 'aggressive' (thorough) |
## Safety
GC is destructive. This formula errs on the side of caution:
- Conservative mode: Only obviously dead things
- Aggressive mode: Includes old but possibly-recoverable state
Running `gt doctor --fix` handles most of this. This formula wraps it with
reporting and multi-rig scope."""
formula = "mol-session-gc"
version = 1
[squash]
trigger = "on_complete"
template_type = "work"
include_metrics = true
[[steps]]
id = "determine-mode"
title = "Determine GC mode"
description = """
Establish GC aggressiveness level.
**1. Check assignment:**
```bash
gt mol status # Shows mode in hook_bead
```
**2. Mode definitions:**
| Mode | Description | Risk |
|------|-------------|------|
| conservative | Only clearly dead state | Very low |
| aggressive | Includes stale state | Low but non-zero |
**Conservative targets:**
- tmux sessions with no processes
- Claude processes with no tmux parent
- Wisps > 24 hours old
**Aggressive additions:**
- Wisps > 1 hour old
- Branches with no matching polecat
- State files > 7 days old
**Exit criteria:** GC mode determined."""
[[steps]]
id = "preview-cleanup"
title = "Preview what will be cleaned"
needs = ["determine-mode"]
description = """
Identify garbage without removing it yet.
**1. Run doctor in preview mode:**
```bash
gt doctor -v
# Shows what would be cleaned, doesn't do it
```
**2. Parse doctor output for:**
- orphan-sessions: Tmux sessions to kill
- orphan-processes: Claude processes to terminate
- wisp-gc: Wisps to delete
**3. Additional scans (for aggressive mode):**
```bash
# Old branches
git branch --list 'polecat/*' | while read branch; do
last_commit=$(git log -1 --format=%ct "$branch")
# If > 7 days old and no matching polecat, candidate for cleanup
done
# Old state files
find ~/.gt/ -name "*.state" -mtime +7
```
**4. Compile cleanup manifest:**
Record each item to be cleaned with:
- Type (session, process, wisp, branch, state)
- Identifier
- Age
- Reason for cleanup
**Exit criteria:** Cleanup manifest ready, nothing deleted yet."""
[[steps]]
id = "execute-gc"
title = "Execute garbage collection"
needs = ["preview-cleanup"]
description = """
Actually remove the garbage.
**1. Run doctor with fix:**
```bash
gt doctor --fix
# This handles sessions, processes, and wisps
```
**2. For aggressive mode, additional cleanup:**
```bash
# Old branches (if aggressive mode)
git branch -D <old-branch>
# Old state files (if aggressive mode)
rm <state-file>
```
**3. Track what was deleted:**
Record each item actually removed for the report.
**Safety checks:**
- Never delete active sessions (tmux list-clients)
- Never delete branches with uncommitted polecat work
- Never delete wisps < 1 hour old
**Exit criteria:** Garbage collected."""
[[steps]]
id = "verify-cleanup"
title = "Verify cleanup was successful"
needs = ["execute-gc"]
description = """
Confirm garbage was actually removed.
**1. Re-run doctor to verify:**
```bash
gt doctor -v
# Should show no issues (or fewer issues)
```
**2. Check for stragglers:**
```bash
# Tmux sessions
tmux list-sessions 2>/dev/null
# Claude processes
pgrep -f claude
# Wisps
ls .beads-wisp/ 2>/dev/null | wc -l
```
**3. Compare before/after:**
- Sessions before: N → after: M
- Processes before: N → after: M
- Wisps before: N → after: M
**Exit criteria:** Cleanup verified."""
[[steps]]
id = "report-gc"
title = "Generate GC report"
needs = ["verify-cleanup"]
description = """
Create summary report of garbage collection.
**1. Generate report:**
```markdown
## Session GC Report: {{timestamp}}
**Mode**: {{mode}}
### Summary
| Type | Before | After | Cleaned |
|------|--------|-------|---------|
| Sessions | X | Y | Z |
| Processes | X | Y | Z |
| Wisps | X | Y | Z |
| Branches | X | Y | Z |
| State files | X | Y | Z |
### Items Cleaned
{{#each cleaned}}
- {{type}}: {{identifier}} (age: {{age}}, reason: {{reason}})
{{/each}}
### Errors
{{#if errors}}
{{#each errors}}
- {{item}}: {{error}}
{{/each}}
{{else}}
None
{{/if}}
### Space Recovered
~{{bytes_freed}} bytes
```
**2. Send to Deacon:**
```bash
gt mail send deacon/ -s "GC complete: {{total_cleaned}} items" \
-m "{{report}}"
```
**Exit criteria:** Report sent."""
[[steps]]
id = "return-to-kennel"
title = "Signal completion and return to kennel"
needs = ["report-gc"]
description = """
Signal work complete and return to available pool.
**1. Signal completion to Deacon:**
```bash
gt mail send deacon/ -s "DOG_DONE $(hostname)" -m "Task: session-gc
Mode: {{mode}}
Items cleaned: {{total_cleaned}}
Space recovered: {{bytes_freed}}
Status: COMPLETE
Ready for next assignment."
```
**2. Return to kennel:**
Dog returns to available state in the pool.
**Exit criteria:** Deacon notified, dog ready for next work."""
[vars]
[vars.mode]
description = "GC mode: 'conservative' or 'aggressive'"
required = true
default = "conservative"