Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Scaffold repo-local Ralph autonomous harness under scripts/ralph/. Use when user runs /flow-next:ralph-init.
.claude/skills/gmickel-flow-next-ralph-init/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 137% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 254% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 144% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 167% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 247% | 0% |
Scaffold or update repo-local Ralph harness. Opt-in only.
The plugin root resolves once via the cross-platform env-var fallback (Droid uses DROID_PLUGIN_ROOT; Claude Code documents CLAUDE_PLUGIN_ROOT as its compat alias). Subsequent blocks use $PLUGIN_ROOT:
bashPLUGIN_ROOT="${CODEX_HOME:-$HOME/.codex}"
scripts/ralph/ in the current repo. A file written anywhere else has broken this.scripts/ralph/ already exists, offer to update (preserves config.env).templates/ into scripts/ralph/ (includes ralphctl.py for pause/resume/stop/status).flowctl, flowctl.cmd, flowctl.py, flowctl_bootstrap.py, flowctl-help.txt, and the flowctl_tracker/ package (from $PLUGIN_ROOT/scripts/) and pick-python.sh (from $PLUGIN_ROOT/scripts/lib/) into scripts/ralph/ — flat, so the resolver lands at scripts/ralph/pick-python.sh where ralph.sh and the hook wrapper source it. A pick-python.sh that landed under scripts/ralph/lib/ has broken this.scripts/ralph/ralph.sh, scripts/ralph/ralph_once.sh, scripts/ralph/flowctl, and scripts/ralph/ralphctl.py.git rev-parse --show-toplevelscripts/ralph/ exists:bash if command -v rpce-cli >/dev/null 2>&1 \ || [ -x "$HOME/RepoPrompt/repoprompt_ce_cli" ] \ || [ -x "$HOME/Library/Application Support/RepoPrompt CE/repoprompt_ce_cli" ] \ || command -v rp-cli >/dev/null 2>&1; then HAVE_RP=1; else HAVE_RP=0; fi HAVE_CODEX=$(which codex >/dev/null 2>&1 && echo 1 || echo 0) HAVE_COPILOT=$(which copilot >/dev/null 2>&1 && echo 1 || echo 0) HAVE_CURSOR=$(which cursor-agent >/dev/null 2>&1 && echo 1 || echo 0)
Show only the options whose CLIs were detected: Multiple review backends available. Which one? a) RepoPrompt (macOS, visual builder) b) Codex CLI (cross-platform, reviewer models via a Codex subscription) c) GitHub Copilot CLI (cross-platform, Claude/GPT via Copilot) d) Cursor CLI (cross-platform, runs cursor-agent; reviewer models via a Cursor subscription)
(Reply: "a", "rp", "b", "codex", "c", "copilot", "d", "cursor", or just tell me) Wait for response. Default if empty/ambiguous: prefer rp > codex > copilot > cursor.
rpcodexcopilotcursornonecp, never the Write tool. A template reproduced by writing its contents has broken this:If UPDATE_MODE=1 (updating): bash # Backup config.env cp scripts/ralph/config.env /tmp/ralph-config-backup.env
# Update templates (preserves runs/) cp "${CODEX_HOME:-$HOME/.codex}/templates/flow-next-ralph-init/ralph.sh" scripts/ralph/ cp "${CODEX_HOME:-$HOME/.codex}/templates/flow-next-ralph-init/ralph_once.sh" scripts/ralph/ cp "${CODEX_HOME:-$HOME/.codex}/templates/flow-next-ralph-init/prompt_plan.md" scripts/ralph/ cp "${CODEX_HOME:-$HOME/.codex}/templates/flow-next-ralph-init/prompt_work.md" scripts/ralph/ cp "${CODEX_HOME:-$HOME/.codex}/templates/flow-next-ralph-init/prompt_completion.md" scripts/ralph/ cp "${CODEX_HOME:-$HOME/.codex}/templates/flow-next-ralph-init/watch-filter.py" scripts/ralph/ cp "${CODEX_HOME:-$HOME/.codex}/templates/flow-next-ralph-init/ralphctl.py" scripts/ralph/ cp "$PLUGIN_ROOT/scripts/flowctl" "$PLUGIN_ROOT/scripts/flowctl.cmd" "$PLUGIN_ROOT/scripts/flowctl.py" "$PLUGIN_ROOT/scripts/flowctl_bootstrap.py" "$PLUGIN_ROOT/scripts/flowctl-help.txt" "$PLUGIN_ROOT/scripts/lib/pick-python.sh" scripts/ralph/ rm -rf scripts/ralph/flowctl_tracker && cp -R "$PLUGIN_ROOT/scripts/flowctl_tracker" scripts/ralph/flowctl_tracker # fn-139.5: verify the tracker package post-copy - fail loudly here, never # later as an ImportError mid-run python3 "$PLUGIN_ROOT/scripts/lib/verify_tracker_manifest.py" scripts/ralph mkdir -p scripts/ralph/hooks cp "$PLUGIN_ROOT/scripts/hooks/ralph-guard.py" "$PLUGIN_ROOT/scripts/hooks/ralph-guard" scripts/ralph/hooks/ chmod +x scripts/ralph/ralph.sh scripts/ralph/ralph_once.sh scripts/ralph/flowctl scripts/ralph/ralphctl.py scripts/ralph/hooks/ralph-guard.py scripts/ralph/hooks/ralph-guard
# Restore config.env cp /tmp/ralph-config-backup.env scripts/ralph/config.env
If UPDATE_MODE=0 (fresh install): bash mkdir -p scripts/ralph/runs scripts/ralph/hooks cp -R "${CODEX_HOME:-$HOME/.codex}/templates/flow-next-ralph-init/." scripts/ralph/ cp "$PLUGIN_ROOT/scripts/flowctl" "$PLUGIN_ROOT/scripts/flowctl.cmd" "$PLUGIN_ROOT/scripts/flowctl.py" "$PLUGIN_ROOT/scripts/flowctl_bootstrap.py" "$PLUGIN_ROOT/scripts/flowctl-help.txt" "$PLUGIN_ROOT/scripts/lib/pick-python.sh" scripts/ralph/ rm -rf scripts/ralph/flowctl_tracker && cp -R "$PLUGIN_ROOT/scripts/flowctl_tracker" scripts/ralph/flowctl_tracker # fn-139.5: verify the tracker package post-copy - fail loudly here, never # later as an ImportError mid-run python3 "$PLUGIN_ROOT/scripts/lib/verify_tracker_manifest.py" scripts/ralph cp "$PLUGIN_ROOT/scripts/hooks/ralph-guard.py" "$PLUGIN_ROOT/scripts/hooks/ralph-guard" scripts/ralph/hooks/ chmod +x scripts/ralph/ralph.sh scripts/ralph/ralph_once.sh scripts/ralph/flowctl scripts/ralph/ralphctl.py scripts/ralph/hooks/ralph-guard.py scripts/ralph/hooks/ralph-guard Note: cp -R templates/. copies all files including dotfiles (.gitignore).
scripts/ralph/config.env to set the chosen review backend (skip if UPDATE_MODE=1):PLAN_REVIEW={{PLAN_REVIEW}} with PLAN_REVIEW=<chosen>WORK_REVIEW={{WORK_REVIEW}} with WORK_REVIEW=<chosen>COMPLETION_REVIEW={{COMPLETION_REVIEW}} with COMPLETION_REVIEW=<chosen>Detect host (same signals as /flow-next:setup Step 0 when available; otherwise probe the settings paths below). Then Read the target file, merge the flow-next Ralph guard entries, Edit/Write the result. The host's existing hooks survive the merge — a settings file whose hooks object now contains only flow-next entries has broken this. Idempotent: if an entry's command already contains scripts/ralph/hooks/ralph-guard, leave that matcher group alone (or refresh the command string to the canonical form below if it drifted).
Fingerprint for "this is a flow-next Ralph guard entry": the hook command string contains scripts/ralph/hooks/ralph-guard (wrapper and/or .py fallback).
Canonical guard command (same on every host that can run bash wrappers):
if [ -f scripts/ralph/hooks/ralph-guard ]; then bash scripts/ralph/hooks/ralph-guard; elif [ -f scripts/ralph/hooks/ralph-guard.py ]; then scripts/ralph/hooks/ralph-guard.py; fi
Timeout: 5 seconds. Type: command.
### Claude Code → merge into .claude/settings.json
Target: project file .claude/settings.json (create {"hooks":{}} skeleton if missing; preserve every non-hooks key).
Merge these four event groups under hooks (Claude schema). Matchers use regex OR so Droid interop and Claude share one entry shape:
| Event | Matcher | Notes | |---|---|---| | PreToolUse | Bash\|Execute | shell (Claude Bash, Droid Execute) | | PreToolUse | Edit\|Write | file tools (Claude host names) | | PostToolUse | Bash\|Execute | shell | | PostToolUse | Edit\|Write | file tools (receipt-path gate parity) | | Stop | (no matcher) | stop gate | | SubagentStop | (no matcher) | subagent stop gate |
Each event's array entry is one matcher group with a single hook object {type, command, timeout} using the canonical command above.
Consent gate: Claude Code's project-hooks trust prompt is the human consent surface. Do not invent a second consent ceremony. After merge, tell the user they may need to accept/trust project hooks in the host UI for them to load this session.
### Factory Droid → merge into .factory/hooks.json
Target (verified against Factory hooks-reference): project file .factory/hooks.json. Prefer that path. Fallback only if the project already stores hooks under the hooks key of .factory/settings.json and has no .factory/hooks.json — merge there instead; never invent a third path.
Host-appropriate matchers for Droid (Factory's shell tool is Execute; file tools include Create / ApplyPatch). The guard body accepts the full dual-platform sets (Bash/Execute, Edit/Write/Create/ApplyPatch).
| Event | Matcher | Notes | |---|---|---| | PreToolUse | Bash\|Execute | shell | | PreToolUse | Edit\|Write\|Create\|ApplyPatch | Droid file tools | | PostToolUse | Bash\|Execute | shell | | PostToolUse | Edit\|Write\|Create\|ApplyPatch | file tools (receipt-path gate) | | Stop | (no matcher) | stop gate | | SubagentStop | (no matcher) | subagent stop gate |
Prefer project-relative command as above (Ralph harness is repo-local). If the host requires absolute paths, rewrite with "$FACTORY_PROJECT_DIR"/scripts/ralph/hooks/... but keep the same fingerprint substring scripts/ralph/hooks/ralph-guard.
### Codex → write/merge project .codex/hooks.json
Codex has no Claude-schema plugin hooks auto-load from the marketplace plugin. Project scope is .codex/hooks.json.
Codex subset (no SubagentStop; no Edit/Write matchers — Codex only intercepts shell):
| Event | Matcher | |---|---| | PreToolUse | Bash\|Execute | | PostToolUse | Bash\|Execute | | Stop | (no matcher) |
The top-level JSON is exactly {"hooks":{...}} — a sibling description key has broken this (Codex rejects unknown fields and disables all hooks).
If .codex/config.toml exists, ensure exactly one hooks = true under [features] (drop deprecated codex_hooks). Same normalization intent as setup's historical Codex hooks step; do it with a careful edit, not a second copy of setup's python block unless you need it.
### Cursor / Grok
afterFileEdit / beforeShellExecution). Scaffold scripts/ralph/ only; print that the guard will not fire on Cursor; do not invent a Cursor-format hook file..claude/settings.json).### Re-run / update
On UPDATE_MODE=1 still re-merge hooks so a project that had scaffold but lost settings entries is repaired. Skip only when every required event already has a fingerprinted entry with the canonical command.
Done when: the host's registered event set matches its platform (Codex without SubagentStop or file-tool matchers; Droid with its own file-tool matchers; Cursor scaffold-only plus the printed will-not-fire note), every entry carries the canonical command, and unrelated hooks are still present.
ralph.sh has broken this:If UPDATE_MODE=1: Ralph updated! Your config.env was preserved.
Hooks: project settings were re-merged (idempotent). Accept the host's project-hooks trust prompt if it appears.
Run from terminal:
If UPDATE_MODE=0: Ralph initialized!
Next steps (run from terminal, NOT inside the agent session):
Maintenance:
Other measured skills in the registry, with their headline benchmark lift.