feat: initial ralph-workplan skill

Standalone Claude Code skill that ties a ralph loop to a workplan file.
Retires automatically when all tasks are done — no external dependencies.

- plugin/ralph-workplan.md      skill entrypoint
- plugin/scripts/check-done.sh  pre-start guard (reads workplan status)
- plugin/scripts/setup.sh       writes ralph state file with workplan-aware prompt
- install.sh                    copies plugin files to ~/.claude/plugins/
- workplan-spec.md              workplan file format reference
- README.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 19:16:57 +01:00
commit f3174cebc9
7 changed files with 426 additions and 0 deletions

76
plugin/ralph-workplan.md Normal file
View File

@@ -0,0 +1,76 @@
---
description: "Start a Ralph loop tied to a workplan file — retires automatically when all tasks are done"
argument-hint: "<workplan-file> [--max-iterations N]"
allowed-tools: ["Read", "Bash(${CLAUDE_PLUGIN_ROOT}/scripts/check-done.sh:*)", "Bash(${CLAUDE_PLUGIN_ROOT}/scripts/setup.sh:*)"]
hide-from-slash-command-tool: "true"
---
# Ralph Workplan
Start a ralph loop driven by a workplan file. The loop retires automatically
when all tasks in the workplan are marked done.
## Usage
```
/ralph-workplan workplans/WP-0001-my-task.md
/ralph-workplan workplans/WP-0001-my-task.md --max-iterations 15
```
The workplan file must follow the format described in `workplan-spec.md`
(YAML frontmatter with `id`, `title`, `status` fields; tasks as fenced
`task` code blocks with `id` and `status`).
## Steps
Parse `$ARGUMENTS` to extract:
- `WORKPLAN_FILE` — the positional argument (required)
- `MAX_ITERATIONS` — value after `--max-iterations` (default: 20)
**Step 1 — Validate the workplan file exists**
If the file does not exist:
> "❌ Workplan file not found: $WORKPLAN_FILE"
Stop.
**Step 2 — Read the workplan frontmatter**
Read `$WORKPLAN_FILE`. Extract from the YAML frontmatter:
- `id` — workplan identifier
- `title` — workplan title
- `status` — current status
**Step 3 — Guard: check if already done**
Run:
```bash
"${CLAUDE_PLUGIN_ROOT}/scripts/check-done.sh" "$WORKPLAN_FILE"
```
Exit code 0 means the workplan is already done. If so:
> "✅ Workplan $ID ('$TITLE') is already done — all tasks complete.
> Nothing to do. No ralph loop started."
Stop.
**Step 4 — Show current task summary**
Count the task blocks in the file (fenced blocks with language tag `task`).
Report:
> "📋 $ID — $TITLE
> Tasks: X done, Y in progress, Z todo (N total)
> Starting ralph loop (max $MAX_ITERATIONS iterations)..."
**Step 5 — Start the loop**
Run:
```bash
"${CLAUDE_PLUGIN_ROOT}/scripts/setup.sh" \
"$WORKPLAN_FILE" "$ID" "$TITLE" "$MAX_ITERATIONS"
```
Then report:
> "🔄 Ralph loop active. The loop will feed the workplan prompt back on every
> iteration. It retires when all tasks are done and the workplan status is
> updated to 'done' in the file."

33
plugin/scripts/check-done.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
# check-done.sh
# Exit 0 if the workplan is done, 1 if not.
# Used as the pre-start guard in the ralph-workplan skill.
#
# Usage: check-done.sh <workplan_file>
set -euo pipefail
WORKPLAN_FILE="${1:?workplan_file required}"
if [[ ! -f "$WORKPLAN_FILE" ]]; then
echo "❌ Workplan file not found: $WORKPLAN_FILE" >&2
exit 2
fi
# Extract status from YAML frontmatter (first occurrence between --- markers)
STATUS=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$WORKPLAN_FILE" \
| grep '^status:' \
| head -1 \
| sed 's/status:[[:space:]]*//' \
| tr -d '"'"'" )
if [[ -z "$STATUS" ]]; then
echo "⚠️ No status field found in frontmatter of: $WORKPLAN_FILE" >&2
exit 1
fi
if [[ "$STATUS" == "done" ]]; then
exit 0
else
exit 1
fi

102
plugin/scripts/setup.sh Executable file
View File

@@ -0,0 +1,102 @@
#!/bin/bash
# setup.sh
# Writes the .claude/ralph-loop.local.md state file with a workplan-aware prompt.
# Called by the /ralph-workplan skill after the pre-start guard passes.
#
# Usage: setup.sh <workplan_file> <workplan_id> <title> <max_iterations>
set -euo pipefail
WORKPLAN_FILE="${1:?workplan_file required}"
WORKPLAN_ID="${2:?workplan_id required}"
TITLE="${3:?title required}"
MAX_ITERATIONS="${4:-20}"
SESSION_ID="${CLAUDE_CODE_SESSION_ID:-}"
STATE_FILE=".claude/ralph-loop.local.md"
mkdir -p .claude
# Extract workplan body — everything after the second ---
WORKPLAN_BODY=$(awk '/^---$/{i++; next} i>=2' "$WORKPLAN_FILE")
cat > "$STATE_FILE" <<EOF
---
active: true
iteration: 1
session_id: ${SESSION_ID}
max_iterations: ${MAX_ITERATIONS}
completion_promise: "HEUREKA"
workplan_id: ${WORKPLAN_ID}
workplan_file: ${WORKPLAN_FILE}
started_at: "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
---
## Workplan Status Check — Do This First, Every Iteration
Read the workplan file at: \`${WORKPLAN_FILE}\`
Count the task blocks (fenced code blocks with language tag \`task\`):
- How many tasks exist in total?
- How many have \`status: done\`?
If **every task** has \`status: done\` AND the frontmatter \`status\` is \`done\`:
The workplan is complete. Output exactly: <promise>HEUREKA</promise>
Do nothing else. Stop here.
Otherwise: continue with the implementation below.
---
## Workplan: ${WORKPLAN_ID} — ${TITLE}
**File:** \`${WORKPLAN_FILE}\`
${WORKPLAN_BODY}
---
## How to Work
- Stay strictly within the scope of the workplan above
- Work through tasks in priority order (high → medium → low)
- Use TDD where applicable: write a failing test, make it pass, then refactor
- Use whatever test runner, linter, and build tools this repository already uses
- Consult existing documentation (README, docs/, wiki/, specs/) for context
- Document significant architecture decisions as ADRs if the project uses them
## Updating Task Status
As you complete each task, edit the workplan file to update its status:
\`\`\`
status: todo → status: in_progress (when you start it)
status: in_progress → status: done (when it is verified complete)
\`\`\`
When **every task** is \`done\`, also update the workplan frontmatter:
\`\`\`
status: active → status: done
\`\`\`
## Success Criteria
Before marking the workplan done and outputting \`<promise>HEUREKA</promise>\`,
verify all of the following are true:
1. Every task block in \`${WORKPLAN_FILE}\` has \`status: done\`
2. The workplan frontmatter \`status\` is \`done\`
3. The full test suite passes with no failures
4. The codebase passes the project's standard code-quality checks
(linting, type checking, formatting — whatever applies to this project)
5. Documentation reflects the implemented behaviour
Output \`<promise>HEUREKA</promise>\` only when all five are genuinely true.
EOF
echo "✅ Ralph state file written: $STATE_FILE"
echo " Workplan : $WORKPLAN_ID$TITLE"
echo " File : $WORKPLAN_FILE"
echo " Max iter : $MAX_ITERATIONS"
echo " Promise : HEUREKA (output only when workplan is genuinely done)"