关于 ralph-review-deep
ralph-review-deep 会验证 Ralph 文件和 bd 图状态,再通过 opencode 并行运行三个独立模型审查。它面向需要跨模型复核的场景,与单子 Agent 的 ralph-review 不同。
主要功能
- 01验证必需文件和 bd 图
- 02并行运行三个模型审查
- 03为每个模型生成独立报告
- 04跟踪进度、费用和错误
- 05保留日志供后续检查
适用场景
- 01比较多个独立的 Ralph 计划审查
- 02结合图检查结果核查计划缺陷
- 03查看模型运行状态和日志
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jimweller/ clanker-skills --skill ralph-review-deep安装后在 Claude Code 中输入/ralph-review-deep确认已加载。
详细介绍
STARTER_CHARACTER = 🔬
Ralph 深度评审
验证 beads 图,并通过 opencode run 使用不同模型并行启动三项独立的 ralph 产物评审。每个模型都会生成一份评审文件,评估目标是否清晰、任务拆解、排序、计划完整性、风险与缺漏,以及可行性。
如需使用内部子 Agent 进行更快的单模型评审,请改用 ralph-review 技能(/ralph-review,$ralph-review)。这个深度版本以更长耗时和更高成本换取跨模型共识。
模型
| 标签 | 模型 ID |
|---|---|
| openai | openai/gpt-5.5 |
| gemini | google/gemini-3.1-pro-preview |
| claude | az-anthropic/claude-opus-4-6 |
流程
步骤 1:验证产物是否存在
PROJECT_ROOT=$(git rev-parse --show-toplevel)
验证以下各项均存在:
$PROJECT_ROOT/.llmtmp/ralph-plan.md$PROJECT_ROOT/.llmtmp/ralph-prompt-insession.md$PROJECT_ROOT/.llmtmp/ralph-prompt-external.md$PROJECT_ROOT/.beads/(目录;通过bd list >/dev/null 2>&1进行 bd 感知探测)
如果缺少任何一项,则中止。
步骤 2:验证 bd 图
启动 opencode 前运行以下检查。此处的失败属于高严重性问题,应中止或明确标记。
bd 图按每次运行的 epic 组织。slug 根据当前分支生成;通过 ralph:<slug> 标签查找 epic。所有范围限定的检查都使用 --parent ${EPIC} 过滤。
cd "$PROJECT_ROOT"
SLUG=$(git branch --show-current | tr '/' '-')
# 1. Single open epic for this run
EPIC_COUNT=$(bd list -t epic -l "ralph:${SLUG}" --json 2>/dev/null | jq '[.[] | select(.status=="open")] | length')
if [[ "$EPIC_COUNT" -ne 1 ]]; then
echo "HIGH: expected exactly one open epic with label ralph:${SLUG}, found ${EPIC_COUNT}"
fi
EPIC=$(bd list -t epic -l "ralph:${SLUG}" --json 2>/dev/null | jq -r '[.[] | select(.status=="open")] | .[0].id // empty')
# 2. Cycles
if ! bd dep cycles >/dev/null 2>&1; then
echo "HIGH: bd graph has dependency cycles"
bd dep cycles
fi
# 3. Minimum child count under the run epic
COUNT=$(bd list --parent "$EPIC" --json 2>/dev/null | jq 'length')
if [[ "$COUNT" -eq 0 ]]; then
echo "HIGH: run epic ${EPIC} has no child tasks"
fi
# 4. At least one ready task under the run epic
READY_COUNT=$(bd ready --parent "$EPIC" --json 2>/dev/null | jq 'length')
if [[ "$READY_COUNT" -eq 0 && "$COUNT" -gt 0 ]]; then
echo "HIGH: run epic ${EPIC} has tasks but no ready tasks (deadlock or all closed unexpectedly)"
fi
# 5. Isolated nodes within the run epic
if [[ "$COUNT" -gt 1 ]]; then
bd list --parent "$EPIC" --json 2>/dev/null \
| jq -r '.[] | select(.dependency_count == 0 and .dependent_count == 0) | "MEDIUM: isolated task " + .id + " " + .title'
fi
# 6. Description coverage: every child carries the worker's instructions
bd list --parent "$EPIC" --json 2>/dev/null \
| jq -r '.[] | select(((.description // "") | length) == 0) | "HIGH: task " + .id + " has empty description: " + .title'
# 7. Parent set equals label set (defense-in-depth orphan detection)
PARENT_IDS=$(bd list --parent "$EPIC" --json 2>/dev/null | jq -r '.[].id' | sort)
LABEL_IDS=$(bd list --label "ralph:${SLUG}" --json 2>/dev/null | jq -r '.[] | select(.issue_type != "epic") | .id' | sort)
if [[ "$PARENT_IDS" != "$LABEL_IDS" ]]; then
echo "HIGH: parent set (--parent ${EPIC}) and label set (--label ralph:${SLUG} excluding epic) differ"
echo "Parent-only (label missing): $(comm -23 <(echo "$PARENT_IDS") <(echo "$LABEL_IDS"))"
echo "Label-only (orphan, parent missing): $(comm -13 <(echo "$PARENT_IDS") <(echo "$LABEL_IDS"))"
fi
保存这些检查结果;评审者会在最终报告中引用它们。
步骤 3:清理之前的评审
rm -f "$PROJECT_ROOT"/.llmtmp/ralph-review-openai.md \
"$PROJECT_ROOT"/.llmtmp/ralph-review-gemini.md \
"$PROJECT_ROOT"/.llmtmp/ralph-review-claude.md
步骤 4:读取文件并构建提示词上下文
将以下文件的内容串联为一个 CONTEXT 字符串:
.llmtmp/ralph-plan.md.llmtmp/ralph-prompt-insession.md.llmtmp/ralph-prompt-external.md- 在步骤 2 中解析出的 slug 和 epic ID(字面标签
SLUG=...和EPIC=...) bd list --parent "$EPIC" --json的输出bd ready --parent "$EPIC" --json的输出bd list --label "ralph:${SLUG}" --json的输出- 步骤 2 中的 bd 图验证结果
- 计划的
plan documents:行中列出的计划文档。解析该行,以逗号拆分并去除空白,然后读取每个路径。将每项包装为=== plan-documents/<path> ===,以便评审者将其与基线内容区分开。值为空表示无需加载计划文档。 - 项目根目录中的
CLAUDE.md和README.md(如果存在) .llmdocs/中的所有.md文件
将每项包装为:
=== <relative-path or label> ===
<contents>
步骤 5:构建评审提示词
构建每个 opencode 进程执行的提示词。替换 <PROJECT_ROOT> 和 <CONTEXT>:
PROMPT="You are a plan reviewer running headless in a non-interactive session. There is no user present. Do not ask questions. Do not prompt for confirmation. Do not stop to wait for input.
YOUR PRIMARY OBJECTIVE IS TO WRITE A FILE. Everything else is preparation. After completing your review, your VERY NEXT action must be a tool call that writes the output file. Do not summarize, do not reflect, do not plan — write the file immediately.
OUTPUT RULES: You are running headless. Nobody reads your text responses. ALL review content goes exclusively into the output file via tool calls. Any text you generate outside of a tool call is wasted tokens and risks hitting the output token limit before you can write the file. Keep text responses to one short sentence at most.
PROJECT_ROOT: <PROJECT_ROOT>
## Context
<CONTEXT>
## How Ralph Loops Work
A ralph loop is an autonomous, iterative execution mechanism. Two execution modes share the same artifacts:
- **In-session (ralph-loop plugin)**: a Stop hook re-feeds the prompt to the same Claude session. Cheap on short runs; expensive on long runs because context grows quadratically.
- **External (scripts/ralph.sh)**: a bash while-loop spawns a fresh `claude --print` per iteration. Higher fixed overhead per iteration; stays in the cheap part of the cost curve indefinitely.
Authority sources in CONTEXT:
The CONTEXT contains two distinct authority categories. Treat them differently.
- **Plan documents** (under `=== plan-documents/...` blocks): forward-looking intent the planner consulted, e.g., a PRD, a Jira ticket, a design note. The plan must faithfully render these. Flag the plan if it omits, contradicts, or stale-references a requirement from a plan document.
- **Baseline docs** (`CLAUDE.md`, `README.md`, `.llmdocs/*`): the system's current state. The plan's job is to change this state. Do NOT flag the plan for deviating from baseline. Flag only if the plan changes baseline without including a corresponding docs-update bead (typically delegated to the docs skill).
Mechanics that apply to both modes:
- The bd graph is the state machine. The 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. `bd ready --parent <epic> --json` finds the next unblocked task within this run.
- The run epic carries the label `ralph:<slug>` where `<slug>` is derived from the current branch. Every child task carries both `--parent <epic>` and the same `ralph:<slug>` label. The two signals are independent so the reviewer can detect orphans.
- The plan's "Run Identity" section records the literal slug and epic ID. The agent reads them directly from the plan each iteration, no derivation.
- One task per iteration. The agent reads `bd ready --parent <epic> --json`, takes the first result, runs the per-task workflow, then closes the task.
- When the ready queue is empty, the agent closes the epic and emits the sentinel as the terminal action. The epic is not closed by `bd` automatically.
- Resumable. A partially-completed graph resumes cleanly. Partial completion is normal; iterations are cheap.
- Every action is a bd task, including ralph lifecycle scaffolding. The branch creation, BEGIN tag, code work, docs, and END tag are all first-class beads, all parented to the run epic.
- Each bead carries its full per-task instructions in its description: files to touch, expected behavior, verification command, commit message. The worker reads `bd show <id>` and executes the description exactly.
- Run-wide conventions (commit style, language, build command, test command) live in `ralph-plan.md`, not in every description.
- Environment is a precondition. Credentials, network, toolchain, and runtime dependencies are the operator's responsibility. Do not flag missing environment setup as a gap.
Do NOT recommend: collapsing tasks into bundles, adding environment preflight checks, treating partial completion as a risk, modifying the prompt body, replacing the bd graph with a markdown checklist, or reintroducing a workflow-label taxonomy. The `ralph:<slug>` label is run-identity for partition and orphan detection, not workflow dispatch; do not flag it as a label taxonomy.
Flag as HIGH severity if: zero or more than one open epic exists for `ralph:<slug>`; any open child has an empty description; the bd graph contains cycles; the run epic has no children; the run epic has children but no ready tasks; the parent set under the epic differs from the label set for `ralph:<slug>` (orphans or planning typos); the per-task workflow does not explicitly stop after `bd close` (the agent will do multiple beads in one context, defeating the Ralph design); the per-task workflow does not close the epic before emitting the sentinel; the plan lacks a "Run Identity" section recording the literal slug and epic ID; the plan lacks an "Inputs" section with a `plan documents:` line; the plan omits or contradicts a material requirement explicit in any plan document; the plan's Approach prose declares an ordering ("X first", "after Y") that the bd dependency edges do not enforce. Flag as MEDIUM if: a description omits the verification command or commit message; an isolated task exists in a multi-task graph; the plan duplicates information that already lives in bead descriptions; a bead that touches README.md/CLAUDE.md/.llmdocs/ authors edits inline instead of running the docs skill.
## Your Task
Review the Ralph artifacts:
- ralph-plan.md (mode-neutral execution plan)
- ralph-prompt-insession.md (slash-command wrapper for the in-session driver)
- ralph-prompt-external.md (body for scripts/ralph.sh)
- The bd graph (issues, dependencies, ready/closed state)
Evaluate across these areas:
### 1. Goal Clarity
- Is the objective well-defined and unambiguous?
- Would a fresh-context iteration understand what success looks like from the plan alone?
### 2. Task Decomposition
- Are tasks the right granularity (one focused deliverable each)?
- Is each task independently completable?
- Are there missing tasks needed to achieve the goal?
- Are there unnecessary or redundant tasks?
- Do titles name deliverables rather than techniques?
- Do descriptions carry enough detail (files, verification, commit message) for a cold-start worker?
### 3. Sequencing and Dependencies
- Are dependencies correct in the bd graph?
- Would executing in `bd ready --json` order produce correct results?
- Are there implicit dependencies that should be explicit edges?
- Are there cycles or isolated nodes?
### 4. Plan Completeness
- Do the instructions cover repo-specific conventions, tools, and commands?
- Are build, test, and lint commands accurate?
- Is the per-task workflow clear (read description, execute it, close)?
- Does the plan have a "Run Identity" section that records the literal branch slug, the literal epic ID, and the epic label `ralph:<slug>`?
- Does the Per-Task Workflow read the epic ID from the "Run Identity" section and scope `bd ready` with `--parent <epic-id>`?
- Does the Per-Task Workflow close the epic via `bd close <epic-id>` before emitting the sentinel when the ready queue is empty?
- Does the Per-Task Workflow explicitly say STOP after `bd close` so the agent does not loop within a single context?
- Does the Git Workflow section require a `ralph/` feature branch and BEGIN/END tags?
- Is the Per-Task Workflow explicit that `bd close` for the current task runs BEFORE the sentinel?
- Do beads that touch `README.md`, `CLAUDE.md`, or `.llmdocs/` invoke the docs skill (/docs, $docs) rather than authoring edits inline?
### 5. Risk and Gaps
- What could go wrong during autonomous execution?
- Are there tasks that require human judgment or external access?
- Could any task leave the repo in a broken state?
### 6. Feasibility
- Can a single iteration realistically complete each task?
- Are there tasks that exceed what a fresh context can do autonomously?
For each area, list specific findings with severity (high/medium/low) and actionable recommendations.
## Output
Your VERY NEXT action after the review must be a tool call that writes the file. No intermediate steps.
Determine your model label:
- Claude variants: claude
- GPT variants: openai
- Gemini variants: gemini
Write to `<PROJECT_ROOT>/.llmtmp/ralph-review-$MODEL_LABEL.md` using this template:
\`\`\`markdown
# Ralph Loop Review
**Model**: <MODEL_LABEL>
## Goal Clarity
- **[medium]** Short title. Explanation...
## Task Decomposition
- **[high]** Short title. Explanation...
## Sequencing and Dependencies
- **[medium]** Short title. Explanation...
## Plan Completeness
- **[low]** Short title. Explanation...
## Risk and Gaps
- **[high]** Short title. Explanation...
## Feasibility
- **[medium]** Short title. Explanation...
## Summary
<overall assessment and top 3 recommendations>
\`\`\`
Finding format: \`- **[severity]** Title. Description.\`
Every section must be present. If no findings for an area, write 'No findings.' under its heading.
Then verify: \`ls -la '<PROJECT_ROOT>/.llmtmp/ralph-review-<MODEL_LABEL>.md'\`
If the file does not exist, write it again. Do not exit without the file."
步骤 6:将提示词写入文件
避免大型提示词出现 shell 插值问题:
STATE_DIR="$PROJECT_ROOT/.llmtmp/ralph_review_state"
mkdir -p "$STATE_DIR"
OPENAI_DIR=$(mktemp -d)
GEMINI_DIR=$(mktemp -d)
CLAUDE_DIR=$(mktemp -d)
cat > /tmp/ralph-review-prompt.txt <<'PROMPT_EOF'
<the prompt from Step 5>
PROMPT_EOF
步骤 7:启动 3 个独立的后台 Bash 任务
每个 opencode 进程都必须作为独立的后台 Bash 任务运行。不要在单个 shell 中用 & 将它们串联起来;父进程退出时,子进程会被终止。
OpenAI:
STATE_DIR="<PROJECT_ROOT>/.llmtmp/ralph_review_state" && \
opencode run \
-m openai/gpt-5.5 \
--format json \
--print-logs \
--log-level INFO \
--dir "<OPENAI_DIR>" \
--title "Ralph Review - OpenAI" \
"$(cat /tmp/ralph-review-prompt.txt)" \
> "$STATE_DIR/openai.ndjson" 2>"$STATE_DIR/openai.log"
Gemini:
STATE_DIR="<PROJECT_ROOT>/.llmtmp/ralph_review_state" && \
opencode run \
-m google/gemini-3.1-pro-preview \
--format json \
--print-logs \
--log-level INFO \
--dir "<GEMINI_DIR>" \
--title "Ralph Review - Gemini" \
"$(cat /tmp/ralph-review-prompt.txt)" \
> "$STATE_DIR/gemini.ndjson" 2>"$STATE_DIR/gemini.log"
Claude:
STATE_DIR="<PROJECT_ROOT>/.llmtmp/ralph_review_state" && \
opencode run \
-m az-anthropic/claude-opus-4-6 \
--format json \
--print-logs \
--log-level INFO \
--dir "<CLAUDE_DIR>" \
--title "Ralph Review - Claude" \
"$(cat /tmp/ralph-review-prompt.txt)" \
> "$STATE_DIR/claude.ndjson" 2>"$STATE_DIR/claude.log"
3 个任务都要分别启动为后台任务。不要在单个 shell 中使用 &。
输出流
每个 opencode 进程都会生成两个输出文件:
<label>.ndjson(标准输出):来自--format json的结构化 NDJSON 事件。用于以编程方式跟踪进度。<label>.log(标准错误):纯文本信息级日志。用于诊断启动失败、权限问题、MCP 服务错误和插件加载问题。
日志行是结构化文本,每行一条:
INFO 2026-03-13T00:54:25 +4ms service=default directory=/private/tmp creating instance
步骤 8:监控并等待
轮询每个后台任务,直到 3 个任务全部完成。
NDJSON 进度(将 $NDJSON 替换为实际路径):
# Count completed steps
grep -c '"type":"step_finish"' "$NDJSON" 2>/dev/null || echo 0
# Check if done (last step_finish has reason "stop")
tail -1 "$NDJSON" 2>/dev/null | jq -r '.part.reason // empty'
# Check for errors
grep '"type":"error"' "$NDJSON" 2>/dev/null
文本日志(将 $LOGFILE 替换为实际路径):
# Errors or warnings
grep -E "^(ERROR|WARN)" "$LOGFILE" 2>/dev/null
# Recent activity
tail -5 "$LOGFILE" 2>/dev/null
步骤 9:报告结果
对于每个模型,检查 .llmtmp/ralph-review-<label>.md 是否存在。
按模型报告:
- 成功或失败(文件是否存在)
- 总成本:汇总所有
step_finish事件中的cost - 是否发生过错误
在报告顶部单独列出步骤 2 中 bd 图验证的结果。
步骤 10:清理
保留状态目录,以便运行后检查(每个模型的 NDJSON 事件流和文本日志有助于诊断审查失败、校准回归和成本趋势)。
rm -f /tmp/ralph-review-prompt.txt
故意不删除 $STATE_DIR(.llmtmp/ralph_review_state/)。后续每次审查运行都会原地覆盖各模型的文件;如果需要保留历史记录,请在重新运行前归档该目录。
预期输出文件
共 3 个文件,每个模型各 1 个:
.llmtmp/ralph-review-openai.md.llmtmp/ralph-review-gemini.md.llmtmp/ralph-review-claude.md
NDJSON 日志格式参考
每个 opencode 进程都会将 NDJSON 写入 $STATE_DIR/<label>.ndjson。每行一个 JSON 对象。跳过解析失败的行(部分写入)。
关键事件类型:
- step_start - 新的大模型轮次开始。
- text - 模型输出的文本:
{"type":"text","part":{"text":"..."}} - tool_use - 工具调用:
{"type":"tool_use","part":{"tool":"bash","state":{"status":"completed","metadata":{"exit":0}}}} - step_finish - 轮次完成:
{"type":"step_finish","part":{"reason":"stop","cost":0,"tokens":{"total":13494}}}。reason: "stop"= 完成,reason: "tool-calls"= 继续。 - error - 会话错误:
{"type":"error","error":{"data":{"message":"..."}}}
实用的 jq 查询(将 $NDJSON 替换为实际路径):
NDJSON="<PROJECT_ROOT>/.llmtmp/ralph_review_state/openai.ndjson"
# Is done?
tail -1 "$NDJSON" | jq -r 'select(.type=="step_finish") | .part.reason'
# Total cost
jq -s '[.[] | select(.type=="step_finish") | .part.cost] | add' "$NDJSON"
# All errors
jq -r 'select(.type=="error") | .error.data.message' "$NDJSON"
将 $LOGFILE 替换为文本日志路径:
grep -E "^(ERROR|WARN)" "$LOGFILE"
规则
- 调用 Agent 仅负责启动。所有审查工作都在 opencode 进程内部完成。
- 不要直接进行任何审查分析。审查工作由 opencode 进程处理。
- 执行期间不要提问。这是非交互式流程。
- 并行启动全部 3 个进程。不要等一个进程完成后再启动另一个。
- 使用普通消息调用,不要使用
--command。--command标志与 context7 MCP 服务存在已知问题。 - 报告结果后保留状态目录。NDJSON 和日志文件留待运行后检查。
- 如果某个模型失败,仍需等待其他模型并报告结果。
- 步骤 2 中的 bd 图验证在调用 Agent 中运行,而不是在 opencode 中运行。验证结果会作为上下文传递给 opencode 审查者。