Add TOML versions of formulas (gt-xmyha)
Converted all .formula.json files to .formula.toml using bd formula convert. TOML provides better ergonomics: - Multi-line strings without \n escaping - Human-readable diffs - Comments allowed Original JSON files retained for backwards compatibility. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
241
.beads/formulas/mol-deacon-patrol.formula.toml
Normal file
241
.beads/formulas/mol-deacon-patrol.formula.toml
Normal file
@@ -0,0 +1,241 @@
|
||||
description = """
|
||||
Mayor's daemon patrol loop.
|
||||
|
||||
The Deacon is the Mayor's background process that runs continuously, handling callbacks, monitoring rig health, and performing cleanup. Each patrol cycle runs these steps in sequence, then loops or exits."""
|
||||
formula = "mol-deacon-patrol"
|
||||
version = 1
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Handle callbacks from agents.
|
||||
|
||||
Check the Mayor's inbox for messages from:
|
||||
- Witnesses reporting polecat status
|
||||
- Refineries reporting merge results
|
||||
- Polecats requesting help or escalation
|
||||
- External triggers (webhooks, timers)
|
||||
|
||||
```bash
|
||||
gt mail inbox
|
||||
# For each message:
|
||||
gt mail read <id>
|
||||
# Handle based on message type
|
||||
```
|
||||
|
||||
Callbacks may spawn new polecats, update issue state, or trigger other actions."""
|
||||
id = "inbox-check"
|
||||
title = "Handle callbacks from agents"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Nudge newly spawned polecats that are ready for input.
|
||||
|
||||
When polecats are spawned, their Claude session takes 10-20 seconds to initialize. The spawn command returns immediately without waiting. This step finds spawned polecats that are now ready and sends them a trigger to start working.
|
||||
|
||||
**ZFC-Compliant Observation** (AI observes AI):
|
||||
|
||||
```bash
|
||||
# View pending spawns with captured terminal output
|
||||
gt deacon pending
|
||||
```
|
||||
|
||||
For each pending session, analyze the captured output:
|
||||
- Look for Claude's prompt indicator \"> \" at the start of a line
|
||||
- If prompt is visible, Claude is ready for input
|
||||
- Make the judgment call yourself - you're the AI observer
|
||||
|
||||
For each ready polecat:
|
||||
```bash
|
||||
# 1. Trigger the polecat
|
||||
gt nudge <session> \"Begin.\"
|
||||
|
||||
# 2. Clear from pending list
|
||||
gt deacon pending <session>
|
||||
```
|
||||
|
||||
This triggers the UserPromptSubmit hook, which injects mail so the polecat sees its assignment.
|
||||
|
||||
**Bootstrap mode** (daemon-only, no AI available):
|
||||
The daemon uses `gt deacon trigger-pending` with regex detection. This ZFC violation is acceptable during cold startup when no AI agent is running yet."""
|
||||
id = "trigger-pending-spawns"
|
||||
needs = ["inbox-check"]
|
||||
title = "Nudge newly spawned polecats"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Check Witness and Refinery health for each rig.
|
||||
|
||||
**ZFC Principle**: You (Claude) make the judgment call about what is \"stuck\" or \"unresponsive\" - there are no hardcoded thresholds in Go. Read the signals, consider context, and decide.
|
||||
|
||||
For each rig, run:
|
||||
```bash
|
||||
gt witness status <rig>
|
||||
gt refinery status <rig>
|
||||
```
|
||||
|
||||
**Signals to assess:**
|
||||
|
||||
| Component | Healthy Signals | Concerning Signals |
|
||||
|-----------|-----------------|-------------------|
|
||||
| Witness | State: running, recent activity | State: not running, no heartbeat |
|
||||
| Refinery | State: running, queue processing | Queue stuck, merge failures |
|
||||
|
||||
**Tracking unresponsive cycles:**
|
||||
|
||||
Maintain in your patrol state (persisted across cycles):
|
||||
```
|
||||
health_state:
|
||||
<rig>:
|
||||
witness:
|
||||
unresponsive_cycles: 0
|
||||
last_seen_healthy: <timestamp>
|
||||
refinery:
|
||||
unresponsive_cycles: 0
|
||||
last_seen_healthy: <timestamp>
|
||||
```
|
||||
|
||||
**Decision matrix** (you decide the thresholds based on context):
|
||||
|
||||
| Cycles Unresponsive | Suggested Action |
|
||||
|---------------------|------------------|
|
||||
| 1-2 | Note it, check again next cycle |
|
||||
| 3-4 | Attempt restart: gt witness restart <rig> |
|
||||
| 5+ | Escalate to Mayor with context |
|
||||
|
||||
**Restart commands:**
|
||||
```bash
|
||||
gt witness restart <rig>
|
||||
gt refinery restart <rig>
|
||||
```
|
||||
|
||||
**Escalation:**
|
||||
```bash
|
||||
gt mail send mayor/ -s \"Health: <rig> <component> unresponsive\" \\
|
||||
-m \"Component has been unresponsive for N cycles. Restart attempts failed.
|
||||
Last healthy: <timestamp>
|
||||
Error signals: <details>\"
|
||||
```
|
||||
|
||||
Reset unresponsive_cycles to 0 when component responds normally."""
|
||||
id = "health-scan"
|
||||
needs = ["trigger-pending-spawns"]
|
||||
title = "Check Witness and Refinery health"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Execute registered plugins.
|
||||
|
||||
Scan ~/gt/plugins/ for plugin directories. Each plugin has a plugin.md with YAML frontmatter defining its gate (when to run) and instructions (what to do).
|
||||
|
||||
See docs/deacon-plugins.md for full documentation.
|
||||
|
||||
Gate types:
|
||||
- cooldown: Time since last run (e.g., 24h)
|
||||
- cron: Schedule-based (e.g., \"0 9 * * *\")
|
||||
- condition: Metric threshold (e.g., wisp count > 50)
|
||||
- event: Trigger-based (e.g., startup, heartbeat)
|
||||
|
||||
For each plugin:
|
||||
1. Read plugin.md frontmatter to check gate
|
||||
2. Compare against state.json (last run, etc.)
|
||||
3. If gate is open, execute the plugin
|
||||
|
||||
Plugins marked parallel: true can run concurrently using Task tool subagents. Sequential plugins run one at a time in directory order.
|
||||
|
||||
Skip this step if ~/gt/plugins/ does not exist or is empty."""
|
||||
id = "plugin-run"
|
||||
needs = ["health-scan"]
|
||||
title = "Execute registered plugins"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Find abandoned work.
|
||||
|
||||
Scan for orphaned state:
|
||||
- Issues marked in_progress with no active polecat
|
||||
- Polecats that stopped responding mid-work
|
||||
- Merge queue entries with no polecat owner
|
||||
- Wisp sessions that outlived their spawner
|
||||
|
||||
```bash
|
||||
bd list --status=in_progress
|
||||
gt polecats --all --orphan
|
||||
```
|
||||
|
||||
For each orphan:
|
||||
- Check if polecat session still exists
|
||||
- If not, mark issue for reassignment or retry
|
||||
- File incident beads if data loss occurred"""
|
||||
id = "orphan-check"
|
||||
needs = ["health-scan"]
|
||||
title = "Find abandoned work"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Clean dead sessions and orphaned state.
|
||||
|
||||
Run `gt doctor --fix` to handle all cleanup:
|
||||
|
||||
```bash
|
||||
# Preview what needs cleaning
|
||||
gt doctor -v
|
||||
|
||||
# Fix everything
|
||||
gt doctor --fix
|
||||
```
|
||||
|
||||
This handles:
|
||||
- **orphan-sessions**: Kill orphaned tmux sessions (gt-* not matching valid patterns)
|
||||
- **orphan-processes**: Kill orphaned Claude processes (no tmux parent)
|
||||
- **wisp-gc**: Garbage collect abandoned wisps (>1h old)
|
||||
|
||||
All cleanup is handled by doctor checks - no need to run separate commands."""
|
||||
id = "session-gc"
|
||||
needs = ["orphan-check"]
|
||||
title = "Clean dead sessions"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Check own context limit.
|
||||
|
||||
The Deacon runs in a Claude session with finite context. Check if approaching the limit:
|
||||
|
||||
```bash
|
||||
gt context --usage
|
||||
```
|
||||
|
||||
If context is high (>80%), prepare for handoff:
|
||||
- Summarize current state
|
||||
- Note any pending work
|
||||
- Write handoff to molecule state
|
||||
|
||||
This enables the Deacon to burn and respawn cleanly."""
|
||||
id = "context-check"
|
||||
needs = ["session-gc"]
|
||||
title = "Check own context limit"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Burn and let daemon respawn, or exit if context high.
|
||||
|
||||
Decision point at end of patrol cycle:
|
||||
|
||||
If context is LOW:
|
||||
- Sleep briefly (avoid tight loop)
|
||||
- Return to inbox-check step
|
||||
|
||||
If context is HIGH:
|
||||
- Write state to persistent storage
|
||||
- Exit cleanly
|
||||
- Let the daemon orchestrator respawn a fresh Deacon
|
||||
|
||||
The daemon ensures Deacon is always running:
|
||||
```bash
|
||||
# Daemon respawns on exit
|
||||
gt daemon status
|
||||
```
|
||||
|
||||
This enables infinite patrol duration via context-aware respawning."""
|
||||
id = "loop-or-exit"
|
||||
needs = ["context-check"]
|
||||
title = "Burn and respawn or loop"
|
||||
169
.beads/formulas/mol-gastown-boot.formula.toml
Normal file
169
.beads/formulas/mol-gastown-boot.formula.toml
Normal file
@@ -0,0 +1,169 @@
|
||||
description = """
|
||||
Mayor bootstraps Gas Town via a verification-gated lifecycle molecule.
|
||||
|
||||
## Purpose
|
||||
When Mayor executes \"boot up gas town\", this proto provides the workflow.
|
||||
Each step has action + verification - steps stay open until outcome is confirmed.
|
||||
|
||||
## Key Principles
|
||||
1. **Verification-gated steps** - Not \"command ran\" but \"outcome confirmed\"
|
||||
2. **gt peek for verification** - Capture session output to detect stalls
|
||||
3. **gt nudge for recovery** - Reliable message delivery to unstick agents
|
||||
4. **Parallel where possible** - Witnesses and refineries can start in parallel
|
||||
5. **Ephemeral execution** - Boot is a wisp, squashed to digest after completion
|
||||
|
||||
## Execution
|
||||
```bash
|
||||
bd wisp mol-gastown-boot # Create wisp
|
||||
```"""
|
||||
formula = "mol-gastown-boot"
|
||||
version = 1
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Verify the Gas Town daemon is running.
|
||||
|
||||
## Action
|
||||
```bash
|
||||
gt daemon status || gt daemon start
|
||||
```
|
||||
|
||||
## Verify
|
||||
1. Daemon PID file exists: `~/.gt/daemon.pid`
|
||||
2. Process is alive: `kill -0 $(cat ~/.gt/daemon.pid)`
|
||||
3. Daemon responds: `gt daemon status` returns success
|
||||
|
||||
## OnFail
|
||||
Cannot start daemon. Log error and continue - some commands work without daemon."""
|
||||
id = "ensure-daemon"
|
||||
title = "Ensure daemon"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Start the Deacon and verify patrol mode is active.
|
||||
|
||||
## Action
|
||||
```bash
|
||||
gt deacon start
|
||||
```
|
||||
|
||||
## Verify
|
||||
1. Session exists: `tmux has-session -t gt-deacon 2>/dev/null`
|
||||
2. Not stalled: `gt peek deacon/` does NOT show \"> Try\" prompt
|
||||
3. Heartbeat fresh: `deacon/heartbeat.json` modified < 2 min ago
|
||||
|
||||
## OnStall
|
||||
```bash
|
||||
gt nudge deacon/ \"Start patrol.\"
|
||||
sleep 30
|
||||
# Re-verify
|
||||
```"""
|
||||
id = "ensure-deacon"
|
||||
needs = ["ensure-daemon"]
|
||||
title = "Ensure deacon"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Parallel container: Start all rig witnesses.
|
||||
|
||||
Children execute in parallel. Container completes when all children complete."""
|
||||
id = "ensure-witnesses"
|
||||
needs = ["ensure-deacon"]
|
||||
title = "Ensure witnesses"
|
||||
type = "parallel"
|
||||
|
||||
[[steps.children]]
|
||||
description = """
|
||||
Start the gastown rig Witness.
|
||||
|
||||
## Action
|
||||
```bash
|
||||
gt witness start gastown
|
||||
```
|
||||
|
||||
## Verify
|
||||
1. Session exists: `tmux has-session -t gastown-witness 2>/dev/null`
|
||||
2. Not stalled: `gt peek gastown/witness` does NOT show \"> Try\" prompt
|
||||
3. Heartbeat fresh: Last patrol cycle < 5 min ago"""
|
||||
id = "ensure-gastown-witness"
|
||||
title = "Ensure gastown witness"
|
||||
|
||||
[[steps.children]]
|
||||
description = """
|
||||
Start the beads rig Witness.
|
||||
|
||||
## Action
|
||||
```bash
|
||||
gt witness start beads
|
||||
```
|
||||
|
||||
## Verify
|
||||
1. Session exists: `tmux has-session -t beads-witness 2>/dev/null`
|
||||
2. Not stalled: `gt peek beads/witness` does NOT show \"> Try\" prompt
|
||||
3. Heartbeat fresh: Last patrol cycle < 5 min ago"""
|
||||
id = "ensure-beads-witness"
|
||||
title = "Ensure beads witness"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Parallel container: Start all rig refineries.
|
||||
|
||||
Children execute in parallel. Container completes when all children complete."""
|
||||
id = "ensure-refineries"
|
||||
needs = ["ensure-deacon"]
|
||||
title = "Ensure refineries"
|
||||
type = "parallel"
|
||||
|
||||
[[steps.children]]
|
||||
description = """
|
||||
Start the gastown rig Refinery.
|
||||
|
||||
## Action
|
||||
```bash
|
||||
gt refinery start gastown
|
||||
```
|
||||
|
||||
## Verify
|
||||
1. Session exists: `tmux has-session -t gastown-refinery 2>/dev/null`
|
||||
2. Not stalled: `gt peek gastown/refinery` does NOT show \"> Try\" prompt
|
||||
3. Queue processing: Refinery can receive merge requests"""
|
||||
id = "ensure-gastown-refinery"
|
||||
title = "Ensure gastown refinery"
|
||||
|
||||
[[steps.children]]
|
||||
description = """
|
||||
Start the beads rig Refinery.
|
||||
|
||||
## Action
|
||||
```bash
|
||||
gt refinery start beads
|
||||
```
|
||||
|
||||
## Verify
|
||||
1. Session exists: `tmux has-session -t beads-refinery 2>/dev/null`
|
||||
2. Not stalled: `gt peek beads/refinery` does NOT show \"> Try\" prompt
|
||||
3. Queue processing: Refinery can receive merge requests"""
|
||||
id = "ensure-beads-refinery"
|
||||
title = "Ensure beads refinery"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Final verification that Gas Town is healthy.
|
||||
|
||||
## Action
|
||||
```bash
|
||||
gt status
|
||||
```
|
||||
|
||||
## Verify
|
||||
1. Daemon running: Shows daemon status OK
|
||||
2. Deacon active: Shows deacon in patrol mode
|
||||
3. All witnesses: Each rig witness shows active
|
||||
4. All refineries: Each rig refinery shows active
|
||||
|
||||
## OnFail
|
||||
Log degraded state but consider boot complete. Some agents may need manual recovery.
|
||||
Run `gt doctor` for detailed diagnostics."""
|
||||
id = "verify-town-health"
|
||||
needs = ["ensure-witnesses", "ensure-refineries"]
|
||||
title = "Verify town health"
|
||||
145
.beads/formulas/mol-polecat-arm.formula.toml
Normal file
145
.beads/formulas/mol-polecat-arm.formula.toml
Normal file
@@ -0,0 +1,145 @@
|
||||
description = """
|
||||
Single polecat inspection and action cycle.
|
||||
|
||||
This molecule is bonded dynamically by mol-witness-patrol's survey-workers step. Each polecat being monitored gets one arm that runs in parallel with other arms.
|
||||
|
||||
## Variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| polecat_name | Yes | Name of the polecat to inspect |
|
||||
| rig | Yes | Rig containing the polecat |
|
||||
| nudge_text | No | Text to send when nudging (default: \"How's progress?...\") |"""
|
||||
formula = "mol-polecat-arm"
|
||||
version = 1
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Capture recent tmux output for {{polecat_name}}.
|
||||
|
||||
```bash
|
||||
tmux capture-pane -t gt-{{rig}}-{{polecat_name}} -p | tail -50
|
||||
```
|
||||
|
||||
Record:
|
||||
- Last activity timestamp (when was last tool call?)
|
||||
- Visible errors or stack traces
|
||||
- Completion indicators (\"Done\", \"Finished\", etc.)"""
|
||||
id = "capture"
|
||||
title = "Capture polecat state"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Categorize polecat state based on captured output.
|
||||
|
||||
States:
|
||||
- **working**: Recent tool calls, active processing
|
||||
- **idle**: At prompt, no recent activity
|
||||
- **error**: Showing errors or stack traces
|
||||
- **requesting_shutdown**: Sent LIFECYCLE/Shutdown mail
|
||||
- **done**: Showing completion indicators
|
||||
|
||||
Calculate: minutes since last activity."""
|
||||
id = "assess"
|
||||
needs = ["capture"]
|
||||
title = "Assess work status"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Read nudge history for {{polecat_name}} from patrol state.
|
||||
|
||||
```
|
||||
nudge_count = state.nudges[{{polecat_name}}].count
|
||||
last_nudge_time = state.nudges[{{polecat_name}}].timestamp
|
||||
```
|
||||
|
||||
This data was loaded by the parent patrol's load-state step and passed to the arm via the bonding context."""
|
||||
id = "load-history"
|
||||
needs = ["assess"]
|
||||
title = "Load intervention history"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Apply the nudge matrix to determine action for {{polecat_name}}.
|
||||
|
||||
| State | Idle Time | Nudge Count | Action |
|
||||
|-------|-----------|-------------|--------|
|
||||
| working | any | any | none |
|
||||
| idle | <10min | any | none |
|
||||
| idle | 10-15min | 0 | nudge-1 (gentle) |
|
||||
| idle | 15-20min | 1 | nudge-2 (direct) |
|
||||
| idle | 20+min | 2 | nudge-3 (final) |
|
||||
| idle | any | 3 | escalate |
|
||||
| error | any | any | assess-severity |
|
||||
| requesting_shutdown | any | any | pre-kill-verify |
|
||||
| done | any | any | pre-kill-verify |
|
||||
|
||||
Nudge text:
|
||||
1. \"How's progress? Need any help?\"
|
||||
2. \"Please wrap up soon. What's blocking you?\"
|
||||
3. \"Final check. Will escalate in 5 min if no response.\"
|
||||
|
||||
Record decision and rationale."""
|
||||
id = "decide"
|
||||
needs = ["load-history"]
|
||||
title = "Decide intervention action"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Take the decided action for {{polecat_name}}.
|
||||
|
||||
**nudge-N**:
|
||||
```bash
|
||||
tmux send-keys -t gt-{{rig}}-{{polecat_name}} \"{{nudge_text}}\" Enter
|
||||
```
|
||||
|
||||
**pre-kill-verify**:
|
||||
```bash
|
||||
cd polecats/{{polecat_name}}
|
||||
git status # Must be clean
|
||||
git log origin/main..HEAD # Check for unpushed
|
||||
bd show <assigned-issue> # Verify closed/deferred
|
||||
|
||||
# Verify productive work (for 'done' closures)
|
||||
git log --oneline --grep='<issue-id>' | head -1
|
||||
```
|
||||
|
||||
**Commit verification** (ZFC principle - agent makes the call):
|
||||
- If issue closed as 'done' but no commits reference it → flag for review
|
||||
- Legitimate exceptions: already fixed elsewhere, duplicate, deferred
|
||||
- Agent must provide justification if closing without commits
|
||||
|
||||
If clean: kill session, remove worktree, delete branch
|
||||
If dirty: record failure, retry next cycle
|
||||
|
||||
**escalate**:
|
||||
```bash
|
||||
gt mail send mayor/ -s \"Escalation: {{polecat_name}} stuck\" -m \"...\"
|
||||
```
|
||||
|
||||
**none**: No action needed.
|
||||
|
||||
Record: action taken, result, updated nudge count.
|
||||
|
||||
## Output
|
||||
|
||||
The arm completes with:
|
||||
- action_taken: none | nudge-1 | nudge-2 | nudge-3 | killed | escalated
|
||||
- result: success | failed | pending
|
||||
- updated_state: New nudge count and timestamp for {{polecat_name}}
|
||||
|
||||
This data feeds back to the parent patrol's aggregate step."""
|
||||
id = "execute"
|
||||
needs = ["decide"]
|
||||
title = "Execute intervention"
|
||||
|
||||
[vars]
|
||||
[vars.nudge_text]
|
||||
default = "How's progress? Need any help?"
|
||||
description = "Text to send when nudging the polecat"
|
||||
[vars.polecat_name]
|
||||
description = "Name of the polecat to inspect"
|
||||
required = true
|
||||
[vars.rig]
|
||||
description = "Rig containing the polecat"
|
||||
required = true
|
||||
70
.beads/formulas/mol-polecat-lease.formula.toml
Normal file
70
.beads/formulas/mol-polecat-lease.formula.toml
Normal file
@@ -0,0 +1,70 @@
|
||||
description = """
|
||||
Semaphore tracking a single polecat's lifecycle.
|
||||
|
||||
Used by Witness to track polecat lifecycle during patrol. The Witness bonds this proto for each active polecat, creating a lease that tracks the polecat from spawn through work to cleanup.
|
||||
|
||||
## Variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| polecat | Yes | Name of the polecat |
|
||||
| issue | Yes | The issue assigned to the polecat |"""
|
||||
formula = "mol-polecat-lease"
|
||||
version = 1
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Spawned. Verify it starts working.
|
||||
|
||||
Check if the polecat is alive and working:
|
||||
```bash
|
||||
gt peek {{polecat}}
|
||||
```
|
||||
|
||||
If idle for too long, nudge:
|
||||
```bash
|
||||
gt nudge {{polecat}} \"Please start working on your assigned issue.\"
|
||||
```
|
||||
|
||||
Timeout: 60s before escalation to Mayor."""
|
||||
id = "boot"
|
||||
title = "Boot"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Actively working. Monitor for stuck.
|
||||
|
||||
The polecat is processing its assigned issue ({{issue}}).
|
||||
Monitor via peek. Watch for:
|
||||
- Progress on commits
|
||||
- Status updates in beads
|
||||
- SHUTDOWN mail when done
|
||||
|
||||
Wait for SHUTDOWN signal from the polecat."""
|
||||
id = "working"
|
||||
needs = ["boot"]
|
||||
title = "Working"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Exit received. Ready for cleanup.
|
||||
|
||||
The polecat has completed its work and sent SHUTDOWN.
|
||||
Perform cleanup:
|
||||
```bash
|
||||
gt session kill {{polecat}}
|
||||
gt worktree prune {{polecat}}
|
||||
```
|
||||
|
||||
Update beads state and close the lease."""
|
||||
id = "done"
|
||||
needs = ["working"]
|
||||
title = "Done"
|
||||
|
||||
[vars]
|
||||
[vars.issue]
|
||||
description = "The issue assigned to the polecat"
|
||||
required = true
|
||||
[vars.polecat]
|
||||
description = "Name of the polecat"
|
||||
required = true
|
||||
62
.beads/formulas/mol-polecat-work.formula.toml
Normal file
62
.beads/formulas/mol-polecat-work.formula.toml
Normal file
@@ -0,0 +1,62 @@
|
||||
description = """
|
||||
Full polecat lifecycle from assignment to decommission.
|
||||
|
||||
This proto enables nondeterministic idempotence for polecat work. A polecat that crashes after any step can restart, read its molecule state, and continue from the last completed step. No work is lost.
|
||||
|
||||
## Variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| issue | Yes | The source issue ID being worked on |"""
|
||||
formula = "mol-polecat-work"
|
||||
version = 1
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Run gt prime and bd prime. Verify issue assignment.
|
||||
Check inbox for any relevant messages.
|
||||
|
||||
Read the assigned issue ({{issue}}) and understand the requirements.
|
||||
Identify any blockers or missing information."""
|
||||
id = "load-context"
|
||||
title = "Load context"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Implement the solution for {{issue}}. Follow codebase conventions.
|
||||
File discovered work as new issues with bd create.
|
||||
|
||||
Make regular commits with clear messages.
|
||||
Keep changes focused on the assigned issue."""
|
||||
id = "implement"
|
||||
needs = ["load-context"]
|
||||
title = "Implement"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Review your own changes. Look for:
|
||||
- Bugs and edge cases
|
||||
- Style issues
|
||||
- Missing error handling
|
||||
- Security concerns
|
||||
|
||||
Fix any issues found before proceeding."""
|
||||
id = "self-review"
|
||||
needs = ["implement"]
|
||||
title = "Self-review"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Send shutdown request to Witness.
|
||||
Wait for termination.
|
||||
|
||||
The polecat is now ready to be cleaned up.
|
||||
Do not exit directly - wait for Witness to kill the session."""
|
||||
id = "request-shutdown"
|
||||
needs = ["self-review"]
|
||||
title = "Request shutdown"
|
||||
|
||||
[vars]
|
||||
[vars.issue]
|
||||
description = "The source issue ID being worked on"
|
||||
required = true
|
||||
166
.beads/formulas/mol-refinery-patrol.formula.toml
Normal file
166
.beads/formulas/mol-refinery-patrol.formula.toml
Normal file
@@ -0,0 +1,166 @@
|
||||
description = """
|
||||
Merge queue processor patrol loop.
|
||||
|
||||
The Refinery is the Engineer in the engine room. You process polecat branches, merging them to main one at a time with sequential rebasing.
|
||||
|
||||
**The Scotty Test**: Before proceeding past any failure, ask yourself: \"Would Scotty walk past a warp core leak because it existed before his shift?\""""
|
||||
formula = "mol-refinery-patrol"
|
||||
version = 1
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Check mail for MR submissions, escalations, messages.
|
||||
|
||||
```bash
|
||||
gt mail inbox
|
||||
# Process any urgent items
|
||||
```
|
||||
|
||||
Handle shutdown requests, escalations, and status queries."""
|
||||
id = "inbox-check"
|
||||
title = "Check refinery mail"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Fetch remote and identify polecat branches waiting.
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git branch -r | grep polecat
|
||||
gt refinery queue <rig>
|
||||
```
|
||||
|
||||
If queue empty, skip to context-check step. Track branch list for this cycle."""
|
||||
id = "queue-scan"
|
||||
needs = ["inbox-check"]
|
||||
title = "Scan merge queue"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Pick next branch. Rebase on current main.
|
||||
|
||||
```bash
|
||||
git checkout -b temp origin/<polecat-branch>
|
||||
git rebase origin/main
|
||||
```
|
||||
|
||||
If rebase conflicts and unresolvable:
|
||||
- git rebase --abort
|
||||
- Notify polecat to fix and resubmit
|
||||
- Skip to loop-check for next branch"""
|
||||
id = "process-branch"
|
||||
needs = ["queue-scan"]
|
||||
title = "Process next branch"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Run the test suite.
|
||||
|
||||
```bash
|
||||
go test ./...
|
||||
```
|
||||
|
||||
Track results: pass count, fail count, specific failures."""
|
||||
id = "run-tests"
|
||||
needs = ["process-branch"]
|
||||
title = "Run test suite"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
**VERIFICATION GATE**: This step enforces the Beads Promise.
|
||||
|
||||
If tests PASSED: This step auto-completes. Proceed to merge.
|
||||
|
||||
If tests FAILED:
|
||||
1. Diagnose: Is this a branch regression or pre-existing on main?
|
||||
2. If branch caused it:
|
||||
- Abort merge
|
||||
- Notify polecat: \"Tests failing. Please fix and resubmit.\"
|
||||
- Skip to loop-check
|
||||
3. If pre-existing on main:
|
||||
- Option A: Fix it yourself (you're the Engineer!)
|
||||
- Option B: File a bead: bd create --type=bug --priority=1 --title=\"...\"
|
||||
|
||||
**GATE REQUIREMENT**: You CANNOT proceed to merge-push without:
|
||||
- Tests passing, OR
|
||||
- Fix committed, OR
|
||||
- Bead filed for the failure
|
||||
|
||||
This is non-negotiable. Never disavow. Never \"note and proceed.\""""
|
||||
id = "handle-failures"
|
||||
needs = ["run-tests"]
|
||||
title = "Handle test failures"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Merge to main and push immediately.
|
||||
|
||||
```bash
|
||||
git checkout main
|
||||
git merge --ff-only temp
|
||||
git push origin main
|
||||
git branch -d temp
|
||||
git branch -D <polecat-branch> # Local delete (branches never go to origin)
|
||||
```
|
||||
|
||||
Main has moved. Any remaining branches need rebasing on new baseline."""
|
||||
id = "merge-push"
|
||||
needs = ["handle-failures"]
|
||||
title = "Merge and push to main"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
More branches to process?
|
||||
|
||||
If yes: Return to process-branch with next branch.
|
||||
If no: Continue to generate-summary.
|
||||
|
||||
Track: branches processed, branches skipped (with reasons)."""
|
||||
id = "loop-check"
|
||||
needs = ["merge-push"]
|
||||
title = "Check for more work"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Summarize this patrol cycle.
|
||||
|
||||
Include:
|
||||
- Branches processed (count, names)
|
||||
- Test results (pass/fail)
|
||||
- Issues filed (if any)
|
||||
- Branches skipped (with reasons)
|
||||
- Any escalations sent
|
||||
|
||||
This becomes the digest when the patrol is squashed."""
|
||||
id = "generate-summary"
|
||||
needs = ["loop-check"]
|
||||
title = "Generate handoff summary"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Check own context usage.
|
||||
|
||||
If context is HIGH (>80%):
|
||||
- Write handoff summary
|
||||
- Prepare for burn/respawn
|
||||
|
||||
If context is LOW:
|
||||
- Can continue processing"""
|
||||
id = "context-check"
|
||||
needs = ["generate-summary"]
|
||||
title = "Check own context limit"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
End of patrol cycle decision.
|
||||
|
||||
If queue non-empty AND context LOW:
|
||||
- Burn this wisp, start fresh patrol
|
||||
- Return to inbox-check
|
||||
|
||||
If queue empty OR context HIGH:
|
||||
- Burn wisp with summary digest
|
||||
- Exit (daemon will respawn if needed)"""
|
||||
id = "burn-or-loop"
|
||||
needs = ["context-check"]
|
||||
title = "Burn and respawn or loop"
|
||||
212
.beads/formulas/mol-witness-patrol.formula.toml
Normal file
212
.beads/formulas/mol-witness-patrol.formula.toml
Normal file
@@ -0,0 +1,212 @@
|
||||
description = """
|
||||
Per-rig worker monitor patrol loop using the Christmas Ornament pattern.
|
||||
|
||||
The Witness is the Pit Boss for your rig. You watch polecats, nudge them toward completion, verify clean git state before kills, and escalate stuck workers.
|
||||
|
||||
**You do NOT do implementation work.** Your job is oversight, not coding.
|
||||
|
||||
This molecule uses dynamic bonding to spawn mol-polecat-arm for each worker, enabling parallel inspection with a fanout gate for aggregation.
|
||||
|
||||
## The Christmas Ornament Shape
|
||||
|
||||
```
|
||||
★ mol-witness-patrol (trunk)
|
||||
/|\\
|
||||
┌────────┘ │ └────────┐
|
||||
PREFLIGHT DISCOVERY CLEANUP
|
||||
│ │ │
|
||||
inbox-check survey aggregate (WaitsFor: all-children)
|
||||
check-refnry │ save-state
|
||||
load-state │ generate-summary
|
||||
↓ context-check
|
||||
┌───────┼───────┐ burn-or-loop
|
||||
● ● ● mol-polecat-arm (dynamic)
|
||||
ace nux toast
|
||||
```"""
|
||||
formula = "mol-witness-patrol"
|
||||
version = 1
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Process witness mail: lifecycle requests, help requests.
|
||||
|
||||
```bash
|
||||
gt mail inbox
|
||||
```
|
||||
|
||||
Handle by message type:
|
||||
- **LIFECYCLE/Shutdown**: Queue for pre-kill verification
|
||||
- **Blocked/Help**: Assess if resolvable or escalate
|
||||
- **HANDOFF**: Load predecessor state
|
||||
- **Work complete**: Verify issue closed, proceed to pre-kill
|
||||
|
||||
Record any pending actions for later steps. Mark messages as processed when complete."""
|
||||
id = "inbox-check"
|
||||
title = "Process witness mail"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Ensure the refinery is alive and processing merge requests.
|
||||
|
||||
**Redundant system**: This check runs in both gt spawn and Witness patrol to ensure the merge queue processor stays operational.
|
||||
|
||||
```bash
|
||||
# Check if refinery session is running
|
||||
gt session status <rig>/refinery
|
||||
|
||||
# Check for merge requests in queue
|
||||
bd list --type=merge-request --status=open
|
||||
```
|
||||
|
||||
If merge requests are waiting AND refinery is not running:
|
||||
```bash
|
||||
gt session start <rig>/refinery
|
||||
gt mail send <rig>/refinery -s \"PATROL: Wake up\" -m \"Merge requests in queue. Please process.\"
|
||||
```
|
||||
|
||||
If refinery is running but queue is non-empty for >30 min, send nudge. This ensures polecats don't wait forever for their branches to merge."""
|
||||
id = "check-refinery"
|
||||
needs = ["inbox-check"]
|
||||
title = "Ensure refinery is alive"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Read handoff bead and get nudge counts.
|
||||
|
||||
Load persistent state from the witness handoff bead:
|
||||
- Active workers and their status from last cycle
|
||||
- Nudge counts per worker per issue
|
||||
- Last nudge timestamps
|
||||
- Pending escalations
|
||||
|
||||
```bash
|
||||
bd show <handoff-bead-id>
|
||||
```
|
||||
|
||||
If no handoff exists (fresh start), initialize empty state. This state persists across wisp burns and session cycles."""
|
||||
id = "load-state"
|
||||
needs = ["check-refinery"]
|
||||
title = "Load persisted patrol state"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
List polecats and bond mol-polecat-arm for each one.
|
||||
|
||||
```bash
|
||||
# Get list of polecats
|
||||
gt polecat list <rig>
|
||||
```
|
||||
|
||||
For each polecat discovered, dynamically bond an inspection arm:
|
||||
|
||||
```bash
|
||||
# Bond mol-polecat-arm for each polecat
|
||||
for polecat in $(gt polecat list <rig> --names); do
|
||||
bd mol bond mol-polecat-arm $PATROL_WISP_ID \\
|
||||
--ref arm-$polecat \\
|
||||
--var polecat_name=$polecat \\
|
||||
--var rig=<rig>
|
||||
done
|
||||
```
|
||||
|
||||
This creates child wisps like:
|
||||
- patrol-x7k.arm-ace (5 steps)
|
||||
- patrol-x7k.arm-nux (5 steps)
|
||||
- patrol-x7k.arm-toast (5 steps)
|
||||
|
||||
Each arm runs in PARALLEL. The aggregate step will wait for all to complete.
|
||||
|
||||
If no polecats are found, this step completes immediately with no children."""
|
||||
id = "survey-workers"
|
||||
needs = ["load-state"]
|
||||
title = "Survey all polecats (fanout)"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Collect outcomes from all polecat inspection arms.
|
||||
|
||||
This is a **fanout gate** - it cannot proceed until ALL dynamically-bonded polecat arms have completed their inspection cycles.
|
||||
|
||||
Once all arms complete, collect their outcomes:
|
||||
- Actions taken per polecat (nudge, kill, escalate, none)
|
||||
- Updated nudge counts
|
||||
- Any errors or issues discovered
|
||||
|
||||
Build the consolidated state for save-state."""
|
||||
id = "aggregate"
|
||||
needs = ["survey-workers"]
|
||||
title = "Aggregate arm results"
|
||||
waits_for = "all-children"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Update handoff bead with new states.
|
||||
|
||||
Persist state to the witness handoff bead:
|
||||
- Updated worker statuses from all arms
|
||||
- Current nudge counts per worker
|
||||
- Nudge timestamps
|
||||
- Actions taken this cycle
|
||||
- Pending items for next cycle
|
||||
|
||||
```bash
|
||||
bd update <handoff-bead-id> --description=\"<serialized state>\"
|
||||
```
|
||||
|
||||
This state survives wisp burns and session cycles."""
|
||||
id = "save-state"
|
||||
needs = ["aggregate"]
|
||||
title = "Persist patrol state"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Summarize this patrol cycle for digest.
|
||||
|
||||
Include:
|
||||
- Workers inspected (count, names)
|
||||
- Nudges sent (count, to whom)
|
||||
- Sessions killed (count, names)
|
||||
- Escalations (count, issues)
|
||||
- Issues found (brief descriptions)
|
||||
- Actions pending for next cycle
|
||||
|
||||
This becomes the digest when the patrol wisp is squashed."""
|
||||
id = "generate-summary"
|
||||
needs = ["save-state"]
|
||||
title = "Generate handoff summary"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
Check own context usage.
|
||||
|
||||
If context is HIGH (>80%):
|
||||
- Ensure state is saved to handoff bead
|
||||
- Prepare for burn/respawn
|
||||
|
||||
If context is LOW:
|
||||
- Can continue patrolling"""
|
||||
id = "context-check"
|
||||
needs = ["generate-summary"]
|
||||
title = "Check own context limit"
|
||||
|
||||
[[steps]]
|
||||
description = """
|
||||
End of patrol cycle decision.
|
||||
|
||||
If context is LOW:
|
||||
- Burn this wisp (no audit trail needed for patrol cycles)
|
||||
- Sleep briefly to avoid tight loop (30-60 seconds)
|
||||
- Return to inbox-check step
|
||||
|
||||
If context is HIGH:
|
||||
- Burn wisp with summary digest
|
||||
- Exit cleanly (daemon will respawn fresh Witness)
|
||||
|
||||
```bash
|
||||
bd mol burn # Destroy ephemeral wisp
|
||||
```
|
||||
|
||||
The daemon ensures Witness is always running."""
|
||||
id = "burn-or-loop"
|
||||
needs = ["context-check"]
|
||||
title = "Burn and respawn or loop"
|
||||
33
.beads/formulas/rule-of-five.formula.toml
Normal file
33
.beads/formulas/rule-of-five.formula.toml
Normal file
@@ -0,0 +1,33 @@
|
||||
description = "Jeffrey Emanuel's discovery: LLM agents produce best work through 4-5 iterative refinements. Breadth-first exploration, then editorial passes."
|
||||
formula = "rule-of-five"
|
||||
type = "expansion"
|
||||
version = 1
|
||||
|
||||
[[template]]
|
||||
description = "Initial attempt at: {target.description}. Don't aim for perfection. Get the shape right. Breadth over depth."
|
||||
id = "{target}.draft"
|
||||
title = "Draft: {target.title}"
|
||||
|
||||
[[template]]
|
||||
description = "First refinement pass. Focus: CORRECTNESS. Fix errors, bugs, mistakes. Is the logic sound?"
|
||||
id = "{target}.refine-1"
|
||||
needs = ["{target}.draft"]
|
||||
title = "Refine 1: Correctness"
|
||||
|
||||
[[template]]
|
||||
description = "Second refinement pass. Focus: CLARITY. Can someone else understand this? Simplify. Remove jargon."
|
||||
id = "{target}.refine-2"
|
||||
needs = ["{target}.refine-1"]
|
||||
title = "Refine 2: Clarity"
|
||||
|
||||
[[template]]
|
||||
description = "Third refinement pass. Focus: EDGE CASES. What could go wrong? What's missing? Handle the unusual."
|
||||
id = "{target}.refine-3"
|
||||
needs = ["{target}.refine-2"]
|
||||
title = "Refine 3: Edge Cases"
|
||||
|
||||
[[template]]
|
||||
description = "Final polish. Focus: EXCELLENCE. This is the last pass. Make it shine. Is this something you'd be proud to ship?"
|
||||
id = "{target}.refine-4"
|
||||
needs = ["{target}.refine-3"]
|
||||
title = "Refine 4: Excellence"
|
||||
38
.beads/formulas/security-audit.formula.toml
Normal file
38
.beads/formulas/security-audit.formula.toml
Normal file
@@ -0,0 +1,38 @@
|
||||
description = "Cross-cutting security concern. Applies security scanning before and after implementation steps."
|
||||
formula = "security-audit"
|
||||
type = "aspect"
|
||||
version = 1
|
||||
|
||||
[[advice]]
|
||||
target = "implement"
|
||||
[advice.around]
|
||||
|
||||
[[advice.around.after]]
|
||||
description = "Post-implementation security scan. Scan new code for vulnerabilities (SAST). Check for hardcoded secrets. Review for OWASP Top 10 issues."
|
||||
id = "{step.id}-security-postscan"
|
||||
title = "Security postscan for {step.id}"
|
||||
|
||||
[[advice.around.before]]
|
||||
description = "Pre-implementation security check. Review for secrets/credentials in scope. Check dependencies for known vulnerabilities."
|
||||
id = "{step.id}-security-prescan"
|
||||
title = "Security prescan for {step.id}"
|
||||
|
||||
[[advice]]
|
||||
target = "submit"
|
||||
[advice.around]
|
||||
|
||||
[[advice.around.after]]
|
||||
description = "Post-submission security verification. Confirm no new vulnerabilities introduced."
|
||||
id = "{step.id}-security-postscan"
|
||||
title = "Security postscan for {step.id}"
|
||||
|
||||
[[advice.around.before]]
|
||||
description = "Pre-submission security check. Final vulnerability scan before merge."
|
||||
id = "{step.id}-security-prescan"
|
||||
title = "Security prescan for {step.id}"
|
||||
|
||||
[[pointcuts]]
|
||||
glob = "implement"
|
||||
|
||||
[[pointcuts]]
|
||||
glob = "submit"
|
||||
11
.beads/formulas/shiny-enterprise.formula.toml
Normal file
11
.beads/formulas/shiny-enterprise.formula.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
description = "Enterprise-grade engineering workflow. Shiny + Rule of Five expansion on implement step."
|
||||
extends = ["shiny"]
|
||||
formula = "shiny-enterprise"
|
||||
type = "workflow"
|
||||
version = 1
|
||||
|
||||
[compose]
|
||||
|
||||
[[compose.expand]]
|
||||
target = "implement"
|
||||
with = "rule-of-five"
|
||||
8
.beads/formulas/shiny-secure.formula.toml
Normal file
8
.beads/formulas/shiny-secure.formula.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
description = "Shiny workflow with security audit aspect applied."
|
||||
extends = ["shiny"]
|
||||
formula = "shiny-secure"
|
||||
type = "workflow"
|
||||
version = 1
|
||||
|
||||
[compose]
|
||||
aspects = ["security-audit"]
|
||||
40
.beads/formulas/shiny.formula.toml
Normal file
40
.beads/formulas/shiny.formula.toml
Normal file
@@ -0,0 +1,40 @@
|
||||
description = "Engineer in a Box - the canonical right way. Design before you code. Review before you ship. Test before you submit."
|
||||
formula = "shiny"
|
||||
type = "workflow"
|
||||
version = 1
|
||||
|
||||
[[steps]]
|
||||
description = "Think carefully about architecture before writing code. Consider: How does this fit into the existing system? What are the edge cases? What could go wrong? Is there a simpler approach?"
|
||||
id = "design"
|
||||
title = "Design {{feature}}"
|
||||
|
||||
[[steps]]
|
||||
description = "Write the code for {{feature}}. Follow the design. Keep it simple. Don't gold-plate."
|
||||
id = "implement"
|
||||
needs = ["design"]
|
||||
title = "Implement {{feature}}"
|
||||
|
||||
[[steps]]
|
||||
description = "Review the implementation. Check for: Does it match the design? Are there obvious bugs? Is it readable and maintainable? Are there security concerns?"
|
||||
id = "review"
|
||||
needs = ["implement"]
|
||||
title = "Review implementation"
|
||||
|
||||
[[steps]]
|
||||
description = "Write and run tests. Unit tests for new code, integration tests if needed, run the full test suite, fix any regressions."
|
||||
id = "test"
|
||||
needs = ["review"]
|
||||
title = "Test {{feature}}"
|
||||
|
||||
[[steps]]
|
||||
description = "Submit for merge. Final check: git status, git diff. Commit with clear message. Push and create PR."
|
||||
id = "submit"
|
||||
needs = ["test"]
|
||||
title = "Submit for merge"
|
||||
|
||||
[vars]
|
||||
[vars.assignee]
|
||||
description = "Who is assigned to this work"
|
||||
[vars.feature]
|
||||
description = "The feature being implemented"
|
||||
required = true
|
||||
80
.beads/formulas/towers-of-hanoi.formula.toml
Normal file
80
.beads/formulas/towers-of-hanoi.formula.toml
Normal file
@@ -0,0 +1,80 @@
|
||||
description = "Solve Towers of Hanoi for {disks} disks. Generates 2^{disks} - 1 steps, each a trivial move operation. Demonstrates mechanical structure generation for arbitrarily long workflows."
|
||||
formula = "towers-of-hanoi"
|
||||
version = 1
|
||||
|
||||
[example_3_disk]
|
||||
|
||||
[[example_3_disk.steps]]
|
||||
description = "Move disk 1 from A to C"
|
||||
id = "move-1"
|
||||
|
||||
[[example_3_disk.steps]]
|
||||
description = "Move disk 2 from A to B"
|
||||
id = "move-2"
|
||||
needs = ["move-1"]
|
||||
|
||||
[[example_3_disk.steps]]
|
||||
description = "Move disk 1 from C to B"
|
||||
id = "move-3"
|
||||
needs = ["move-2"]
|
||||
|
||||
[[example_3_disk.steps]]
|
||||
description = "Move disk 3 from A to C"
|
||||
id = "move-4"
|
||||
needs = ["move-3"]
|
||||
|
||||
[[example_3_disk.steps]]
|
||||
description = "Move disk 1 from B to A"
|
||||
id = "move-5"
|
||||
needs = ["move-4"]
|
||||
|
||||
[[example_3_disk.steps]]
|
||||
description = "Move disk 2 from B to C"
|
||||
id = "move-6"
|
||||
needs = ["move-5"]
|
||||
|
||||
[[example_3_disk.steps]]
|
||||
description = "Move disk 1 from A to C"
|
||||
id = "move-7"
|
||||
needs = ["move-6"]
|
||||
|
||||
[generate]
|
||||
[generate.for-each]
|
||||
range = "1..2^{disks}"
|
||||
var = "move_num"
|
||||
[generate.step]
|
||||
description = "Move {computed_disk} from {computed_source} to {computed_target}. This is move {move_num} of {total_moves}. Simply execute the move - no decision needed."
|
||||
id = "move-{move_num}"
|
||||
needs = ["move-{move_num - 1}"]
|
||||
[generate.step.compute]
|
||||
disk = "lowest_set_bit({move_num})"
|
||||
source = "peg_for_disk({disk}, {move_num}, 'source')"
|
||||
target = "peg_for_disk({disk}, {move_num}, 'target')"
|
||||
|
||||
[[steps]]
|
||||
description = "Verify initial state: {disks} disks stacked on peg {source_peg}. All disks in order (largest on bottom)."
|
||||
id = "setup"
|
||||
|
||||
[[steps]]
|
||||
description = "Execute all {total_moves} moves to transfer tower from {source_peg} to {target_peg}."
|
||||
id = "solve"
|
||||
needs = ["setup"]
|
||||
|
||||
[[steps]]
|
||||
description = "Verify final state: all {disks} disks now on peg {target_peg}. Tower intact, all moves were legal."
|
||||
id = "verify"
|
||||
needs = ["solve"]
|
||||
|
||||
[vars]
|
||||
[vars.auxiliary_peg]
|
||||
default = "B"
|
||||
description = "Helper peg"
|
||||
[vars.disks]
|
||||
description = "Number of disks to solve"
|
||||
required = true
|
||||
[vars.source_peg]
|
||||
default = "A"
|
||||
description = "Starting peg"
|
||||
[vars.target_peg]
|
||||
default = "C"
|
||||
description = "Target peg"
|
||||
Reference in New Issue
Block a user