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:
209
.beads/formulas/mol-convoy-cleanup.formula.toml
Normal file
209
.beads/formulas/mol-convoy-cleanup.formula.toml
Normal 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
|
||||
208
.beads/formulas/mol-dep-propagate.formula.toml
Normal file
208
.beads/formulas/mol-dep-propagate.formula.toml
Normal 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
|
||||
227
.beads/formulas/mol-digest-generate.formula.toml
Normal file
227
.beads/formulas/mol-digest-generate.formula.toml
Normal 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"
|
||||
312
.beads/formulas/mol-orphan-scan.formula.toml
Normal file
312
.beads/formulas/mol-orphan-scan.formula.toml
Normal 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"
|
||||
250
.beads/formulas/mol-session-gc.formula.toml
Normal file
250
.beads/formulas/mol-session-gc.formula.toml
Normal 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"
|
||||
Reference in New Issue
Block a user