configs/claude-code/skills/ralph-builder/SKILL.md
Author a beads-backed Ralph Wiggum loop for in-session or external autonomous execution.
npx skillsauth add jimweller/dotfiles ralph-builderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
STARTER_CHARACTER = 🔁
Author the artifacts a ralph loop needs to run autonomously against the current repo. Tasks live in a beads (bd) graph database. The plan and two prompt wrappers live in .llmtmp/.
Arguments: $ARGUMENTS
The argument is a goal description. It may reference a file containing a PRD, plan, or task list.
| Path | Purpose |
| ----------------------------------- | ---------------------------------------------------------- |
| .beads/ | Beads database (single source of task state) |
| .llmtmp/ralph-plan.md | Mode-neutral execution plan |
| .llmtmp/ralph-prompt-insession.md | Slash-command wrapper for the in-session ralph-loop plugin |
| .llmtmp/ralph-prompt-external.md | Body fed to claude --print by scripts/ralph.sh |
Both prompt wrappers carry the same body. Only the driver differs.
Read the repo to ground the plan:
README.md (project root).md files in .llmdocs/Create .llmtmp/ if it does not exist.
The bead graph is shared across worktrees of the same repo. Each ralph run is organized under a per-run epic so concurrent runs in different worktrees stay isolated by --parent filtering.
if ! bd list >/dev/null 2>&1; then
bd init --skip-agents
fi
slug=$(git branch --show-current | tr '/' '-')
epic=$(bd q "Ralph: ${slug}" -t epic -p 1 -l "ralph:${slug}")
--skip-agents suppresses bd's default AGENTS.md generation, CLAUDE.md modification, and .claude/settings.json injection. The project's existing agent guidance and the beads skill provide bd workflow context; bd's per-project agent files are redundant and conflict with project conventions.
The epic carries the label ralph:${slug} as run-identity. Children created in Step 3 carry both --parent "${epic}" and the same label, providing two independent signals so the reviewer can detect orphans.
Every action in a ralph run is a bead. Each bead has a title (imperative one-liner) and a description (the worker's full instructions for that task). Lifecycle scaffolding (branch creation, BEGIN tag, END tag) is encoded as ordinary beads, all parented to the run epic.
Create child beads with bd create -t task --parent "${epic}" -l "ralph:${slug}" -q --json | jq -r .id. Capture each ID for downstream bd link calls. Set descriptions with bd update <id> -d "<text>" (or --body-file - heredoc for multi-line). Wire dependencies with bd link <a> <b> (b blocks a). Every run starts with a branch task and a BEGIN tag task; every run ends with an END tag task that depends transitively on every other task.
The block below shows a hypothetical run adding three greeting functions to lib/greeting.go and updating the README. The literal values (SLUG, file paths, function names, commit prefixes) are illustrative; substitute the real run's facts. Bead descriptions carry task-specific facts only. Universal rules (TDD for code, conventional commits, persona constraints) already live in CLAUDE.md. Run-wide conventions (build, test, lint commands) live in ralph-plan.md. Descriptions do not restate either.
DATE=$(date +%Y%m%d)
SLUG=greeting # derive from the goal; lowercase alphanumeric plus hyphen, max ~20 chars
HASH=$(openssl rand -hex 2 | head -c 3)
RUN="${DATE}-${SLUG}-${HASH}"
BRANCH="ralph/${RUN}"
# slug and epic are in scope from Step 2.
bdc() {
bd create "$1" -t task -p 2 --parent "${epic}" -l "ralph:${slug}" -q --json | jq -r .id
}
T_BRANCH=$(bdc "Switch to branch ${BRANCH}")
bd update "$T_BRANCH" -d "Switch to branch ${BRANCH}, creating it if missing. Verify: git rev-parse --abbrev-ref HEAD prints ${BRANCH}."
T_BEGIN=$(bdc "Tag RALPH-${RUN}-BEGIN")
bd link "$T_BEGIN" "$T_BRANCH"
bd update "$T_BEGIN" -d "Run: git tag RALPH-${RUN}-BEGIN. Verify: git tag -l RALPH-${RUN}-BEGIN is non-empty."
T1=$(bdc "Add hello() to lib/greeting.go")
bd link "$T1" "$T_BEGIN"
bd update "$T1" -d "hello() in lib/greeting.go returns \"world\". Commit: feat(greeting): add hello"
T2=$(bdc "Add goodbye() to lib/greeting.go")
bd link "$T2" "$T_BEGIN"
bd update "$T2" -d "goodbye() in lib/greeting.go returns \"bye\". Commit: feat(greeting): add goodbye"
T3=$(bdc "Add greet(name) to lib/greeting.go")
bd link "$T3" "$T1"
bd link "$T3" "$T2"
bd update "$T3" -d "greet(name) in lib/greeting.go composes hello() and goodbye(). greet(\"Jim\") returns \"world Jim bye\". Commit: feat(greeting): add greet"
T4=$(bdc "Document greetings API")
bd link "$T4" "$T3"
bd update "$T4" -d "Run /docs to document hello(), goodbye(), and greet() now exposed by lib/greeting.go. Commit: docs: document greetings API"
T_END=$(bdc "Tag RALPH-${RUN}-END")
bd link "$T_END" "$T4"
bd update "$T_END" -d "Run: git tag RALPH-${RUN}-END. Verify: git tag -l RALPH-${RUN}-END is non-empty."
The 3-char hash suffix prevents branch and tag collisions when multiple ralph runs share a date and slug.
After authoring, assert no cycles, every child has a description, at least one task is ready, and the parent set equals the label set (excluding the epic):
bd dep cycles
bd list --parent "${epic}" --json | jq -e 'all(.[]; (.description // "") | length > 0)'
bd ready --parent "${epic}" --json | jq 'length'
parent_ids=$(bd list --parent "${epic}" --json | jq -r '.[].id' | sort)
label_ids=$(bd list --label "ralph:${slug}" --json | jq -r '.[] | select(.issue_type != "epic") | .id' | sort)
[[ "${parent_ids}" == "${label_ids}" ]] || { echo "parent/label set mismatch: orphans or misclassified beads"; exit 1; }
Title rules:
Description rules:
CLAUDE.md. Do not restate run-wide build, test, or lint commands; those live in ralph-plan.mdSkill delegations (mandatory):
| Work | Skill |
| ------------------------------------------------------------- | ------- |
| Updating README.md, CLAUDE.md, or any file in .llmdocs/ | /docs |
Beads in these categories must invoke the skill in the description, not author edits inline. Example: Run /docs to document the new auth middleware rather than Edit .llmdocs/architecture.md to add an Authentication subsection. The skill carries its own guardrails and parallelism; reproducing its job inline loses both.
.llmtmp/ralph-plan.mdEach iteration reads this file cold with no memory of prior runs. Every command, pattern, and convention belongs here. Dense, repo-specific detail is correct.
The "Run Identity" section records the literal ${slug} and ${epic} values produced in Step 2 so the agent can read them directly without re-deriving each iteration.
The "Inputs" section's plan documents: line records the source documents the planner was passed via $ARGUMENTS. The reviewer parses that line and reads each path as authoritative intent. This is a passthrough: list exactly the files in $ARGUMENTS, no more, no fewer, no inferred additions. If $ARGUMENTS references no files (text-only goal), the value is empty.
Required sections:
# Ralph Plan
## Goal
<one paragraph>
## Approach
<strategy specific to this goal; include all relevant repo-specific detail directly>
## Inputs
plan documents: <comma-separated paths from $ARGUMENTS, or empty if none>
## Run Identity
- Branch slug: `<slug from Step 2>`
- Epic ID: `<epic ID from Step 2>`
- Epic label: `ralph:<slug>`
- Driver: `scripts/ralph.sh .llmtmp/ralph-prompt-external.md`
## Conventions
<repo-specific patterns, tools, test commands, build commands, commit style>
## Git Workflow
All git operations execute as bd tasks per the per-task workflow. Branch creation, BEGIN tag, code commits, docs commits, and END tag are first-class beads in the graph, parented to the run epic. Never commit on `main`.
## Per-Task Workflow
Exactly ONE task per iteration. After step 5, STOP. Do not pick another task. Do not loop back to step 1. The driver (`scripts/ralph.sh` or the in-session loop) spawns a fresh context for the next task. The whole point of Ralph is one task per fresh context window; multiple tasks in one context defeats the design.
Each iteration:
1. Read the epic ID and slug from the "Run Identity" section above.
2. Run `bd ready --parent <epic-id> --json`. If the result is `[]`, run `bd close <epic-id> -m "ralph run complete"`, output `<promise>ALLDONE</promise>`, and stop.
3. Pick the first task. Run `bd show <id>` to read the title and description.
4. Execute the description exactly. The description names the files, commands, verification step, and commit message for this task.
5. Run `bd close <id>`. Then STOP this iteration. Do not pick another task.
The sentinel `<promise>ALLDONE</promise>` is emitted only on the iteration where step 2 finds the ready queue empty (all children closed and the epic just closed). Every other iteration ends silently after step 5.
Plan rules:
plan documents: lists exactly the files referenced in $ARGUMENTS. Do not add README.md, CLAUDE.md, or .llmdocs/* (the reviewer reads those independently as baseline). Do not infer related files from .llmtmp/ or elsewhere. If a path in $ARGUMENTS does not exist, fail the build with a clear error rather than dropping it.Both files share this body:
Read .llmtmp/ralph-plan.md and follow it.
.llmtmp/ralph-prompt-insession.md is one line:
/ralph-loop:ralph-loop "<body>" --max-iterations 100 --completion-promise ALLDONE
.llmtmp/ralph-prompt-external.md is the body alone, no wrapper.
Before finishing, assert:
bd list >/dev/null 2>&1 exits zero
bd dep cycles exits zero
A single open epic exists for this run: bd list -t epic -l "ralph:${slug}" --json | jq -e 'length == 1'
bd ready --parent "${epic}" --json | jq 'length' is greater than zero
Every child of the epic has a non-empty description: bd list --parent "${epic}" --json | jq -e 'all(.[]; (.description // "") | length > 0)'
Parent set equals label set (excluding the epic itself):
diff <(bd list --parent "${epic}" --json | jq -r '.[].id' | sort) \
<(bd list --label "ralph:${slug}" --json | jq -r '.[] | select(.issue_type != "epic") | .id' | sort)
.llmtmp/ralph-plan.md, .llmtmp/ralph-prompt-insession.md, .llmtmp/ralph-prompt-external.md all exist
The plan's "Run Identity" section records the literal slug and epic ID
Both prompt files contain the identical shared body
If any assertion fails, fix and re-validate.
testing
Search saved session transcripts for past decisions, actions, errors, and context that has left the current conversation window.
data-ai
Review a PRD for defects via Claude opus subagent.
development
Markdown authoring guidelines for formatting, code blocks, and structure. Use when writing or editing markdown files.
development
--- name: md-style description: README style guide for concise, direct documentation. Use when writing or editing README files. ß--- <!-- markdownlint-disable-file MD041 --> # README Style Guide Write concise, direct README files for experienced engineers. ## Principles - **No fluff** - Skip tables of contents, verbose explanations, development history - **No roadmaps** - Document current state only, not plans or decisions. Readme is an engineering specification. Not a project plan or chan