| name | ralph-wiggum |
| description | Skill for driving the Ralph Wiggum parallel plugin factory: create task files, run developer/tester ping-pong loops, monitor progress, and merge results. Use when asked to build ATK plugins via Ralph, create a task file, or run/monitor the ralph.py orchestrator.
|
Ralph Wiggum โ Developer/Tester Ping-Pong Loop
The Ralph Wiggum technique (Geoffrey Huntley): AI coding agents run in a tight loop,
one task per iteration, fresh context each time, a living task file as backlog.
Applied here with two specialized roles to eliminate confirmation bias:
- Developer: builds the plugin, self-validates, hands off to testing
- Tester: independently breaks the plugin, logs bugs, hands back to developer
A developer who tests their own work wants to prove it works.
A separate tester wants to find what doesn't. Same code, opposite mindsets.
Project Context
atk-registry is a Git repository containing ATK (AI Toolkit) plugin definitions.
ATK is a CLI (uv tool install atk-cli) that lets developers install, configure, and
manage AI development tools (MCP servers, databases, observability stacks) through a
declarative YAML manifest at ~/.atk/manifest.yaml.
Repository layout:
atk-registry/
plugins/ โ one directory per completed plugin
<name>/
plugin.yaml โ machine-readable spec (required)
README.md โ human-readable guide (required)
SKILL.md โ agent guide for using the plugin (optional)
install.sh / start.sh / stop.sh / uninstall.sh โ lifecycle scripts (if needed)
skills/
ralph-wiggum/
ralph.py โ the loop orchestrator (this skill's engine)
SKILL.md โ this file
create-atk-plugin/
SKILL.md โ authoritative guide for building any ATK plugin
Makefile โ `make validate` validates all plugins
index.yaml โ registry index (auto-generated, do not edit)
The authoritative plugin spec is skills/create-atk-plugin/SKILL.md. Developer
agents receive it in full. Tester agents receive only its Testing Protocol section
(so they probe the plugin against the spec, not the implementation).
Task files (ralph-tasks.yaml, ralph-batch-2.yaml, etc.) live at the registry
root and are gitignored (ralph-*.yaml, ralph-*.lock) โ operator artefacts,
not source. Split large batches into multiple files (10โ15 tasks each).
The Ping-Pong Loop
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Multiple โ Developer Agent (ralph.py --role developer) โ
devs pick โโโโโบโ 1. claim pending task โ
tasks in โ 2. read create-atk-plugin SKILL.md โ
parallel โ 3. implement plugin, self-test lifecycle โ
โ 4. run make validate โ
โ 5. commit; mark: ready_for_testing โ
โ 6. write MANDATORY suggestions โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโ
โ status: ready_for_testing
โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโ
Multiple โ Tester Agent (ralph.py --role tester) โ
testers pick โโบโ 1. claim ready_for_testing task โ
tasks in โ 2. read task spec only โ NOT the SKILL.md โ
parallel โ 3. run full ATK lifecycle: addโtestโremove โ
โ 4. log ALL bugs found (structured) โ
โ 5. mark: complete OR back to pending โ
โ 6. write MANDATORY suggestions โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโ
bugs found? โ no bugs?
โโโโโโโโโโโโโโโโโโโโโ โ
โ status: pending โ status: complete
โ (with bug list) โ
โผ โผ
Developer picks Done โ
up again, reads
bug list, fixes
Task Status Lifecycle
pending โโโบ developing โโโบ ready_for_testing โโโบ testing โโโบ complete
โฒ โ
โโโโโ pending โโโโโโโโ
(bugs found โ back to developer)
| Status | Set by | Meaning |
|---|
pending | human / tester | Ready for a developer to claim |
developing | ralph.py (dev) | A developer is actively building it |
ready_for_testing | developer agent | Built and self-tested; needs independent QA |
testing | ralph.py (test) | A tester is actively running the test suite |
complete | tester agent | All tests passed; plugin is production-ready |
failed | ralph.py | Meta-failure (worktree error, stale lock, etc) |
skipped | human / ralph.py (max_cycles) | Intentionally excluded, or cycle limit reached |
developing vs pending: developing is set the instant ralph.py claims a task.
The agent then does all its work. Only when the agent itself writes ready_for_testing
into the YAML does the task leave the developer's ownership. If the agent crashes
mid-session, ralph.py can detect the stale state via --stale-timeout and reclaim it.
YAML Task File Schema
Place task files at the root of atk-registry/. Name them ralph-*.yaml
(e.g. ralph-tasks.yaml, ralph-batch-2.yaml) โ the wildcard pattern is gitignored.
schema_version: "2.0"
project: my-plugin-batch
description: Build a set of ATK registry plugins
process:
developer:
cmd: auggie
flags:
- "--print"
- "--model"
- "sonnet4.6"
- "--rules"
- "/path/to/ai-assistant/AGENTS.md"
- "--permission"
- "bash:allow"
instruction_flag: "--instruction-file"
workspace_flag: "--workspace-root"
tester:
cmd: auggie
flags:
- "--print"
- "--model"
- "sonnet4.6"
- "--rules"
- "/path/to/ai-assistant/AGENTS.md"
- "--permission"
- "bash:allow"
worktree_base: /tmp/ralph-worktrees
branch_prefix: "plugin/"
max_cycles: 5
tasks:
- id: "001"
name: my-plugin
description: |
Create an ATK registry plugin for <tool>.
[Enough detail for BOTH developer AND tester to understand what the plugin
should do โ this description IS the shared specification.]
status: pending
worker_id: null
branch: null
dev_cycles: 0
started_at: null
completed_at: null
bugs: []
suggestions: []
Process config field reference:
| Field | Default | Description |
|---|
developer.cmd | auggie | CLI command for the developer role |
developer.flags | ["--print"] | Flags passed to the developer agent |
developer.instruction_flag | "--instruction-file" | Flag to pass the prompt file; null โ pipe via stdin |
developer.workspace_flag | "--workspace-root" | Flag to pass worktree path; null โ skip (agent uses cwd) |
tester.cmd | auggie | CLI command for the tester role |
tester.flags | ["--print"] | Flags passed to the tester agent |
tester.instruction_flag | "--instruction-file" | Same as developer |
tester.workspace_flag | "--workspace-root" | Same as developer |
worktree_base | /tmp/ralph-worktrees | Base dir where git worktrees are created |
branch_prefix | plugin/ | Branch name = {branch_prefix}{task-name} |
max_cycles | 0 (unlimited) | Auto-skips a task when dev_cycles reaches this |
The old flat format (developer_agent, developer_flags, tester_agent, tester_flags) is still accepted for backward compatibility but deprecated. New task files should use the nested format above.
Creating a Task File
When asked to create a Ralph task file, generate a YAML file at the registry root:
cat > ralph-<batch-name>.yaml << 'EOF'
EOF
Task description template โ descriptions are the shared specification between
developer and tester. Both roles receive only the task description; neither receives
extra context. A good description answers:
- What tool/service is this plugin for? (link to upstream project)
- What type of plugin is it? (MCP-only stdio | MCP-only SSE | service + MCP)
- What is the exact install command or Docker image?
- Which environment variables are required? Which are optional?
- What MCP capabilities must be verified? (name specific tools, not just "GitHub operations")
- Any known gotchas or configuration quirks from the upstream docs?
tasks:
- id: "001"
name: my-plugin
description: |
Create an ATK plugin for <Tool Name> (<upstream-url>).
Plugin type: <mcp-stdio | mcp-sse | service>
Install: <exact install command or Docker image>
Required env vars:
MY_TOKEN โ API token from https://...
MY_HOST โ host to connect to (e.g. localhost)
Optional env vars:
MY_PORT โ default 8080
MY_DEBUG โ set "true" to enable verbose logging
MCP capabilities to verify:
- tool: create_item โ creates a new item; verify it returns item ID
- tool: list_items โ lists items; verify pagination param works
- resource: item:///<id> โ verify it returns item JSON
Known gotchas:
- The server takes ~5 seconds to initialize; health check must retry.
status: pending
worker_id: null
branch: null
dev_cycles: 0
started_at: null
completed_at: null
bugs: []
suggestions: []
Running the Loop
All commands run from atk-registry/. Use uv run python (not bare python):
Default โ one combined worker, tester-first:
uv run python skills/ralph-wiggum/ralph.py --tasks ralph-tasks.yaml
Each iteration checks for ready_for_testing tasks first; if none, falls back to pending.
Developer and tester work happens sequentially in one thread โ no coordination needed.
Bounded run โ process exactly N tasks then exit:
uv run python skills/ralph-wiggum/ralph.py --tasks ralph-tasks.yaml --count 3
Parallel workers (multiple files or higher throughput):
uv run python skills/ralph-wiggum/ralph.py --tasks ralph-tasks.yaml --worker-id worker-a &
uv run python skills/ralph-wiggum/ralph.py --tasks ralph-tasks.yaml --worker-id worker-b &
Debug / single-role mode โ lock a worker to one role:
uv run python skills/ralph-wiggum/ralph.py --role developer --tasks ralph-tasks.yaml
uv run python skills/ralph-wiggum/ralph.py --role tester --tasks ralph-tasks.yaml
Recovery โ reclaim stale tasks (agent crashed mid-run):
uv run python skills/ralph-wiggum/ralph.py --tasks ralph-tasks.yaml --stale-timeout 3600
All CLI options:
| Flag | Default | Description |
|---|
--role ROLE | none (combined) | Lock to developer or tester only (debug/parallel) |
--tasks FILE | ralph-tasks.yaml | Path to task YAML file |
--worker-id ID | hostname-pid | Unique worker label; used in worktree dir names |
--count N | none (run until exhausted) | Stop after processing N tasks |
--stale-timeout N | none | Reclaim tasks stuck in developing/testing for >N seconds |
--worktree-base DIR | from process config | Override worktree base directory |
How ralph.py works internally (per task):
- Acquire exclusive file lock on
{tasks_file}.lock (via fcntl.flock)
- Scan tasks for the next eligible task (combined mode:
ready_for_testing first, then pending)
- Claim the task: set
status: developing / testing, worker_id, started_at
- Create a git worktree on branch
{branch_prefix}{task-name} in worktree_base/
- Build a role-specific prompt (injecting the full task file path, skill content, and task data)
- Write the prompt to a temp file; invoke the agent with
--workspace-root <worktree-dir>
(ralph.py always overrides --workspace-root to the worktree, not the main repo)
- When the agent exits, remove the worktree; loop to the next task
- If
max_cycles is set and dev_cycles >= max_cycles, auto-mark the task skipped
Monitoring:
grep "status:" ralph-tasks.yaml | sort | uniq -c
grep -A3 "severity:" ralph-tasks.yaml | grep -v "^--"
git worktree list
git branch | grep plugin/
Agent Configuration Reference
ralph.py works with any CLI agent โ auggie, claude, a custom shell script, etc. The
instruction_flag and workspace_flag fields in AgentConfig control how the prompt
and worktree path are delivered. Set either to null to skip that delivery mechanism.
Key flags for auggie (non-interactive operation):
| Flag | Purpose |
|---|
--print | One-shot mode โ no interactive prompts, exits when done |
--model sonnet4.6 | Claude Sonnet 4.6 via Augment |
--rules /path/to/AGENTS.md | Engineering standards injected into every session |
--permission "bash:allow" | Approve shell commands without pausing to ask |
For agents that read from stdin (e.g. claude --print), set instruction_flag: null.
For agents that use the subprocess working directory naturally, set workspace_flag: null.
Developer Agent โ What You Must Do
You are the DEVELOPER. Your job is to build one ATK registry plugin and hand it to
an independent tester. Read the create-atk-plugin SKILL.md carefully โ it defines
every requirement. Then implement, self-test, commit, and update the task file.
The task description is a starting point, not a ceiling. If you discover that
the upstream server accepts additional environment variables, supports optional
configuration, or has behaviors the description didn't mention โ document them.
Update plugin.yaml, the README, and write an implementation_note suggestion.
Expanding beyond the spec is correct behaviour, not scope creep.
Steps (in order):
- Read
create-atk-plugin/SKILL.md in full before writing a single file.
- If there are open bugs in
bugs[], read each one carefully. You will address them.
- Create
plugins/<name>/ with plugin.yaml and all files required by the SKILL.
- Full implementations only โ no stub scripts, no
echo "TODO", no placeholder configs.
- Run
make validate from the repo root. Fix every error. Repeat until it passes.
- Self-test the full lifecycle:
atk add ./plugins/<name>
atk status
atk stop <name> && atk start <name>
atk mcp show <name>
atk uninstall <name> --force && atk install <name>
atk remove <name> --force
- If there were open bugs: address each one, then mark each fixed via the CLI shown in your prompt.
- Commit:
git add plugins/<name>/ && git commit -m "feat: add <name> plugin (cycle N)"
- Mark the task ready for testing via the ralph CLI (command shown in your prompt):
uv run skills/ralph-wiggum/ralph.py task update \
--tasks TASKS_FILE --id TASK_ID --status ready_for_testing --dev-cycles N
Do NOT edit the tasks YAML directly โ the CLI validates the input. (see format below)
DO NOT mark ready_for_testing until make validate passes and the lifecycle test
completes without errors.
Tester Agent โ What You Must Do
You are the TESTER. Your job is to find what the developer got wrong โ not to confirm
that they got it right. Approach this as a professional QA engineer who is trying to
break the plugin, not validate it.
Critical mindset: The developer was motivated to make it look working. You are
motivated to find where it actually fails. These are opposite motivations. Lean into
yours. A tester who reports "all tests passed" in the first cycle is being lazy.
Steps (in order):
-
Read the task description โ this is your specification. Do not read the SKILL.md.
Test the plugin against what it's supposed to do, not against how it was implemented.
-
If there are previously logged bugs, list them out. You will verify each one.
-
Run the full ATK testing protocol (from create-atk-plugin SKILL.md, Testing section):
atk add ./plugins/<name> โ does install complete cleanly?
atk status โ does it show running? Are all ports healthy?
atk stop <name> then atk start <name> โ does stop/start cycle work?
atk mcp show <name> โ is the command correct? Are all configured env vars shown?
atk uninstall <name> --force then atk install <name> โ is it idempotent?
atk remove <name> --force โ is cleanup complete?
-
For each previously logged bug: explicitly test whether it is fixed. Note the result.
-
Update the task via the ralph CLI (exact commands shown in your prompt):
- Log each bug:
ralph.py task add-bug --tasks FILE --id ID --severity S --description D --steps S
- Mark fixed bugs:
ralph.py task update-bug --tasks FILE --id ID --bug-id BID --status addressed ...
- If all tests pass:
ralph.py task update --tasks FILE --id ID --status complete
- If any bugs found:
ralph.py task update --tasks FILE --id ID --status pending
Do NOT edit the tasks YAML directly โ the CLI validates statuses and rejects invalid values.
DO NOT set status: complete if any functional test failed or any previously
logged bug with severity high or above is still reproducible.
Low-severity documentation inaccuracies (e.g., a wrong default value in a README
table) do not block completion if the plugin installs, runs, and its MCP output is
correct. Log them as open bugs, but mark the task complete and note the doc fix
in a suggestion so the next human review catches it.
Mandatory Suggestions โ The Law
Both roles must write suggestions every cycle for genuine gaps found. This is how
the process learns and improves across batches.
Write suggestions for real gaps only. Do not manufacture suggestions to meet a
count โ a thin suggestion wastes reviewer time and trains agents to prioritize
commentary over finishing. If you found nothing worth flagging, write one honest
"nothing new to flag" note and move on. Quality over quantity.
A suggestion with no proposed_fix is incomplete. If you can describe a problem,
you can propose a fix โ even if it is "add a warning note to section X of SKILL.md."
What to write suggestions about:
- Something in
create-atk-plugin/SKILL.md that was wrong, ambiguous, or missing
- ATK behaviour that differed from what the SKILL or documentation described
- A step in the lifecycle that the SKILL didn't warn you about
- A pattern that tripped you up and would trip up a future agent
- A test that should be required but isn't mentioned anywhere
- A process step in this ralph-wiggum loop that should be improved
- Something you discovered during implementation that the task spec didn't mention
implementation_note suggestions are first-class. If you found an undocumented
env var, chose a deliberate default, or noticed an upstream quirk that users will hit โ
write it up. Do not suppress discoveries just because they weren't explicitly asked for.
These notes are exactly how the task descriptions and SKILL improve across batches.
Suggestion CLI format (agents use the CLI โ do NOT edit the YAML directly):
uv run skills/ralph-wiggum/ralph.py task add-suggestion \
--tasks TASKS_FILE --id TASK_ID \
--author-role developer \
--cycle 1 \
--type skill_bug \
--description "The SKILL.md says to use 'docker compose up -d' in the start lifecycle,
but on macOS Sequoia (Docker Desktop 4.x) this fails silently when the compose file uses
'platform: linux/amd64' without a matching buildx context. The SKILL does not mention this." \
--proposed-fix "Add a note to create-atk-plugin/SKILL.md start section: 'If using
platform: linux/amd64, ensure Rosetta is enabled in Docker Desktop. Without it, compose
exits 0 but no container starts.'"
The CLI validates --type and rejects the command if --proposed-fix is absent.
The human running ralph reviews suggestions between batches and updates
create-atk-plugin/SKILL.md accordingly. Over iterations, the SKILL gets sharper,
agents make fewer mistakes, and cycles get shorter.
Merging Completed Plugins
After status: complete, each plugin lives on its own branch
({branch_prefix}{task-name}, e.g. plugin/my-plugin with the default prefix):
git checkout plugin/my-plugin
make validate
atk add ./plugins/my-plugin
atk mcp show my-plugin
atk remove my-plugin --force
git checkout main
git merge plugin/my-plugin --no-ff -m "feat: add my-plugin"
Tuning Between Batches
- Agent used the wrong pattern โ add a "sign" to
create-atk-plugin/SKILL.md:
e.g., "DO NOT use sleep 5 โ use retry loops with curl."
- Tester found the same bug twice โ developer is not reading bug list carefully.
Add explicit instruction:
"Before writing any code, read every entry in bugs[] and plan how you will address each one."
- Suggestions are thin or generic โ add to both role prompts:
"Each suggestion must quote the specific text that was wrong or missing. Vague suggestions are not accepted."
- Cycle count climbing โ examine suggestions for pattern; fix the root cause in SKILL.md.
- Agent crashed without updating YAML โ run ralph.py with
--stale-timeout 3600
to auto-reclaim tasks stuck in developing or testing for more than 1 hour.