Skip to content

Comments

feat: add cross-tool support for OpenCode and Codex CLI#91

Open
tzachbon wants to merge 19 commits intomainfrom
feat/opencode-codex-support
Open

feat: add cross-tool support for OpenCode and Codex CLI#91
tzachbon wants to merge 19 commits intomainfrom
feat/opencode-codex-support

Conversation

@tzachbon
Copy link
Owner

@tzachbon tzachbon commented Feb 15, 2026

Summary

  • 8 universal SKILL.md files for portable workflow discovery across Claude Code, OpenCode, and Codex CLI
  • OpenCode adapter with TypeScript execution loop hooks
  • Codex CLI adapter with SKILL.md-based manual task progression
  • AGENTS.md generator that extracts project instructions from design.md
  • Configuration bridge for multi-tool setup from a single ralph-config.json
  • Zero regression for existing Claude Code plugin (v3.4.0)

Tool Support Matrix

Feature Claude Code OpenCode Codex CLI
Spec workflow Full (plugin commands) Full (SKILL.md) Full (SKILL.md)
Execution loop Auto (stop-hook) Auto (TS hooks) Manual (re-invoke)
Parallel research TeamCreate Subagents Sequential
AGENTS.md Optional Recommended Recommended

Test Plan

  • SKILL.md discoverability tests (51 checks)
  • Spec artifact portability tests (71 checks)
  • Claude Code zero-regression tests (35 checks)
  • CI checks pass

Summary by CodeRabbit

Release Notes

  • New Features

    • Added cross-tool support for OpenCode and Codex CLI alongside Claude Code.
    • Introduced comprehensive workflow documentation for all spec development phases.
    • Added unified configuration system to manage tool-specific settings across multiple platforms.
    • Enabled AGENTS.md generation from design specifications.
  • Documentation

    • Extended troubleshooting and cross-tool setup guidance.
    • Added detailed adapter documentation for OpenCode and Codex integrations.
  • Tests

    • Added artifact portability validation tests across tool boundaries.
    • Added skill discovery validation for workflow documentation.
    • Added regression testing to protect existing functionality.
  • Chores

    • Version bumped to 3.4.0.

tzachbon and others added 17 commits February 15, 2026 11:19
Spec artifacts:
- research.md: feasibility analysis and codebase exploration
- requirements.md: user stories and acceptance criteria
- design.md: architecture and technical decisions
- tasks.md: POC-first implementation plan (25 tasks, 4 phases)

Ready for implementation.
…lity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ogression

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The regression test incorrectly flagged the required version bump (3.3.3
to 3.4.0) as a regression. Updated tests 1, 7, and 10 to accept
version-only changes in plugin.json, since CLAUDE.md mandates version
bumps for any plugin modification. Also commits updated spec index files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

📝 Walkthrough

Walkthrough

This PR introduces cross-tool support for the Ralph specification workflow, extending it to OpenCode and Codex CLI alongside Claude Code. It adds eight universal SKILL.md documentation files defining each workflow phase, creates OpenCode and Codex adapters with execution logic, establishes a configuration bridge via ralph-config.json, and includes comprehensive test coverage and documentation.

Changes

Cohort / File(s) Summary
Version Management
.claude-plugin/marketplace.json, plugins/ralph-specum/.claude-plugin/plugin.json
Version bumped from 3.3.3 to 3.4.0 across plugin manifests.
Core Documentation
CLAUDE.md, CONTRIBUTING.md, README.md, plugins/ralph-specum/templates/settings-template.md
Added Cross-Tool Support sections, updated troubleshooting guidance, provided tool-specific configuration locations, and adjusted sample settings values.
Universal Workflow SKILL.md Files
plugins/ralph-specum/skills/workflow/start/SKILL.md, research/SKILL.md, requirements/SKILL.md, design/SKILL.md, tasks/SKILL.md, implement/SKILL.md, status/SKILL.md, cancel/SKILL.md
Added eight comprehensive workflow phase documentation files covering spec initialization, research, requirements, design, task planning, implementation with state management, status reporting, and cancellation with detailed procedures, templates, and quality checklists.
OpenCode Adapter
adapters/opencode/README.md, adapters/opencode/hooks/execution-loop.ts
Implemented OpenCode execution loop via TypeScript hooks with state-driven task progression, spec detection, completion signal handling, and safety guards; includes configuration and troubleshooting documentation.
Codex CLI Adapter
adapters/codex/README.md, adapters/codex/AGENTS.md.template, adapters/codex/skills/ralph-implement/SKILL.md
Added Codex CLI adapter with skill-based SKILL.md progression, AGENTS.md template for project documentation, and comprehensive workflow documentation including state management via .ralph-state.json and per-task execution.
Configuration Bridge
adapters/config/README.md, adapters/config/ralph-config.schema.json, adapters/config/generate-config.sh
Introduced unified ralph-config.json schema and generator script to produce tool-specific configurations for Claude Code, OpenCode, and Codex CLI with support for dry-run mode and monorepo layouts.
Artifact Generation
plugins/ralph-specum/scripts/generate-agents-md.sh
Added script to generate AGENTS.md from spec design.md with architecture, coding conventions, and file structure extraction.
Test Infrastructure
tests/test-skill-discovery.sh, tests/test-artifact-portability.sh, tests/test-claude-code-regression.sh
Introduced three test suites validating SKILL.md structure, artifact portability across tools, and Claude Code plugin regression prevention.
Spec Artifacts
specs/opencode-codex-support/research.md, requirements.md, design.md, tasks.md, .progress.md, specs/.index/index-state.json, specs/.index/index.md
Added complete specification artifacts for opencode-codex-support feature including research findings, functional/non-functional requirements, layered architecture design, multi-phase task plan, progress log, and index updates.
Configuration
.gitignore
Added AGENTS.md to generated files list.

Sequence Diagrams

sequenceDiagram
    participant User
    participant Tool as Tool (Claude/OpenCode/Codex)
    participant Adapter as Tool Adapter
    participant State as State Management<br/>(.ralph-state.json)
    participant Spec as Spec Artifacts<br/>(tasks.md, design.md)

    User->>Tool: Initiate ralph:start
    Tool->>Adapter: Execute skill
    Adapter->>State: Initialize state<br/>(phase, taskIndex=0)
    Adapter->>Spec: Create research.md
    Tool-->>User: Begin Research Phase

    loop Workflow Progression (research → implement)
        User->>Tool: Continue workflow
        Tool->>Adapter: Trigger next phase
        Adapter->>State: Read current phase
        Adapter->>Spec: Read phase artifact
        Adapter->>Spec: Execute phase logic
        Adapter->>State: Update phase, set<br/>awaitingApproval
        Tool-->>User: Provide phase output
    end

    User->>Tool: ralph:implement
    Tool->>Adapter: Execute implement skill
    loop Task Execution (per task)
        Adapter->>State: Read taskIndex
        Adapter->>Spec: Get current task<br/>from tasks.md
        Adapter->>User: Display task details
        User->>Spec: Execute task<br/>(Do, Verify, Commit)
        Adapter->>State: Advance taskIndex
        alt All tasks complete
            Adapter->>State: Mark execution complete
            Tool-->>User: Spec implementation done
        else Tasks remaining
            Adapter->>User: Prompt for next task
        end
    end
Loading
sequenceDiagram
    participant Claude as Claude Code
    participant OpenCode as OpenCode + Hook
    participant Codex as Codex CLI
    participant Config as ralph-config.json
    participant Adapter as Tool Adapter

    User->>Config: Provide unified config
    Config->>Claude: Claude Code setup<br/>(plugin_dir)
    Config->>OpenCode: OpenCode setup<br/>(hooks_dir)
    Config->>Codex: Codex setup<br/>(skills_dir)

    Claude->>Claude: Uses built-in SKILL.md
    Claude-->>User: Execute workflow

    OpenCode->>Adapter: Hook triggered<br/>(session.idle)
    Adapter->>Adapter: Read .ralph-state.json
    Adapter->>Adapter: Detect active spec
    alt Execution phase + tasks remain
        Adapter->>OpenCode: Inject continuation<br/>prompt + guidance
        OpenCode-->>User: Continue task
    else All tasks complete
        Adapter->>OpenCode: Block with<br/>completion message
    end

    Codex->>Adapter: Skill discovered<br/>(ralph-implement)
    Adapter->>Adapter: Read SKILL.md
    Adapter->>Adapter: Execute single task<br/>from tasks.md
    Adapter->>Adapter: Update .ralph-state.json
    Codex-->>User: Prompt for re-invocation
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through tool-lands wide,
Universal SKILLs as trusty guide,
Claude, OpenCode, Codex in stride—
One spec to rule them all with pride! 🌟

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add cross-tool support for OpenCode and Codex CLI' directly and clearly summarizes the main change: adding support for OpenCode and Codex CLI alongside the existing Claude Code tool. It is concise, specific, and accurately represents the primary objective of the changeset.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/opencode-codex-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

🤖 Fix all issues with AI agents
In `@adapters/codex/AGENTS.md.template`:
- Line 25: Update the incorrect GitHub URL string
"https://github.com/zachbonfil/smart-ralph" in the AGENTS.md.template line that
references Smart Ralph so the repository owner username is correct; replace
"zachbonfil" with "tzachbon" resulting in
"https://github.com/tzachbon/smart-ralph" to match the rest of the codebase.

In `@adapters/codex/skills/ralph-implement/SKILL.md`:
- Line 331: Replace the double backticks around `.ralph-state.json` with single
backticks in the SKILL.md text that states "Codex CLI does not support hooks,
stop events, or automatic continuation. The state file (``.ralph-state.json``)
acts as the coordination mechanism:" so the filename is rendered correctly as
`.ralph-state.json`.

In `@adapters/config/generate-config.sh`:
- Line 26: The variables PROJECT_ROOT, COMMIT_SPEC, MAX_ITERATIONS, and
MAX_TASK_ITERATIONS are assigned but never used; either remove their assignments
to declutter the script or explicitly mark them for future use by exporting them
or adding a TODO comment; update the generate-config.sh snippet that creates
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" and the lines that assign
COMMIT_SPEC, MAX_ITERATIONS, and MAX_TASK_ITERATIONS so they are either deleted
or changed to export VARIABLE_NAME=# TODO: intended for future use, keeping only
the variables you actually reference elsewhere.
- Around line 339-344: The fallback loop for discovering the latest spec
(iterating design_file and setting latest_spec) does not actually pick the most
recently modified file; update the logic to sort design.md files by modification
time and pick the newest one (e.g., use ls -t "$spec_root"/*/design.md | head
-n1 or use find ... -printf '%T@ %p' | sort -n | tail -n1) then set
latest_spec="$(dirname "<that-most-recent-path>")"; ensure the code references
the existing variables design_file, latest_spec, and spec_root so behavior and
variable names remain consistent.

In `@adapters/opencode/hooks/execution-loop.ts`:
- Around line 302-318: The continuation prompt in the array assigned to reason
contains a Claude-specific phrase "Delegate via Task tool - do NOT implement
yourself"; update the string in that array (the reason constant built near where
specName and state are used) to use tool-agnostic wording such as "Delegate via
the designated task-delegation mechanism - do NOT implement yourself" or "Use
the system's task delegation tool/mechanism - do NOT implement yourself" so it
no longer references Claude-specific concepts; keep the rest of the reason text
unchanged and ensure the edit touches only the literal string in the reason
array that mentions "Task tool" (refer to reason, specName, state,
STATE_FILE_NAME).
- Around line 67-92: getSpecsDirs() and isPluginDisabled() currently read Claude
Code-specific ".claude/ralph-specum.local.md" which is wrong for the OpenCode
adapter; update both functions to prefer a tool-agnostic project config
(ralph-config.json at repo root with a "spec_dirs" array) and then fall back to
an OpenCode-specific config (e.g., ".opencode/ralph-config.json" or a
".opencode" frontmatter file) before using DEFAULT_SPECS_DIR; specifically,
modify getSpecsDirs to: 1) attempt to read and parse ralph-config.json in cwd
and return its spec_dirs if present and valid, 2) if not present, attempt to
read an ".opencode" config (either JSON or frontmatter) for spec dirs, 3) only
if both are missing fallback to DEFAULT_SPECS_DIR; similarly update
isPluginDisabled to check ralph-config.json and .opencode config for the plugin
disabled flag instead of ".claude/ralph-specum.local.md", and keep existing
file-parsing error handling and trimming logic while removing any dependency on
".claude/ralph-specum.local.md".

In `@AGENTS.md`:
- Around line 56-66: The markdown fenced code blocks in AGENTS.md (the directory
listings like the block containing "skills/workflow/" and other blocks showing
"adapters/opencode/" and "adapters/codex/") lack language tags and trigger
MD040; update each triple-backtick fence to include a language tag (use "text")
so they read ```text ... ``` for every fenced block (including those around the
blocks at the other reported ranges ~118-130 and 142-148) while preserving the
exact block contents.

In `@CLAUDE.md`:
- Around line 105-118: The fenced code block in CLAUDE.md that begins with the
directory tree ("adapters/ ...") is missing a language tag and triggers MD040;
update the opening fence from ``` to ```text (or another appropriate language)
so the block is explicitly tagged (locate the block that starts with "adapters/"
in CLAUDE.md and change the opening triple backticks to include the language).

In `@plugins/ralph-specum/scripts/generate-agents-md.sh`:
- Around line 37-59: The --spec-path and --output branches in the
argument-parsing case (inside the while loop handling "$1") assume a following
argument and use "$2" then shift 2; add a guard that verifies a next argument
exists and is not another flag (e.g., test $# -ge 2 and that "$2" does not start
with '-') before assigning SPEC_PATH or OUTPUT_PATH, and if the check fails call
usage or print a clear error and exit; update both branches consistently so the
script (and variables SPEC_PATH/OUTPUT_PATH) won’t trigger an "unbound variable"
under set -u.
- Around line 92-114: The current extract_section logic uses index($0, "## "
target) == 1 which does a prefix match and can capture headings like "##
Architecture Overview" when target is "Architecture"; update the heading check
inside the awk block that uses the heading variable so it only matches an exact
heading (e.g., anchor the pattern to the line start and end), allowing
optionally a trailing space or colon; modify the condition that references
heading/target to use a regex match comparing the full heading line (for example
matching /^##[[:space:]]+target([[:space:]]|:)?$/ using the heading variable)
instead of index(... ) to avoid false positives.

In `@plugins/ralph-specum/skills/workflow/cancel/SKILL.md`:
- Around line 55-58: The markdown output blocks in SKILL.md currently lack
language fences; update each triple-backtick code block (the plain text messages
such as "No spec found at: $SPEC_PATH", "Canceled: $SPEC_NAME", "Canceled and
removed: $SPEC_NAME", "No active execution loop found for spec: $SPEC_NAME",
etc.) to use ```text language tags so they become ```text ... ```; ensure you
apply this change to the other similar blocks referenced (around the other
occurrences noted) so all user-facing output blocks are fenced as text.

In `@plugins/ralph-specum/skills/workflow/design/SKILL.md`:
- Around line 67-80: The outer triple-fenced markdown blocks (the blocks that
start with ```markdown) contain inner fenced blocks like ```mermaid which closes
the outer fence and breaks rendering; fix each occurrence by changing the outer
fence to a four-backtick fence (````markdown ... ````) or use tilde fences (~~~)
so the inner ```mermaid (and other inner ``` blocks) remain intact; search for
the outer "```markdown" blocks and any nested "```mermaid" (and similar nested
fenced blocks) and update those outer fences consistently (also apply the same
fix to the other repeated sections containing nested code fences).

In `@plugins/ralph-specum/skills/workflow/start/SKILL.md`:
- Around line 17-19: The Markdown fenced code blocks in SKILL.md lack language
tags and trigger MD040; update each triple-backtick fence in the shown sections
(the blocks containing the flow line "research -> requirements -> design ->
tasks -> implement" and the subsequent example blocks around specs/,
specs/my-feature/, decision flow, resuming output, start CLI usage examples,
quick-mode rules, and flags examples) by adding a language tag (suggest "text")
after the opening ``` so each block becomes ```text, ensuring all similar blocks
at the other listed ranges (27-33, 37-43, 74-85, 187-191, 224-228, 240-251,
257-259, 265-267, 275-278) are updated consistently to satisfy MD040.

In `@plugins/ralph-specum/skills/workflow/status/SKILL.md`:
- Around line 125-144: The fenced code blocks in SKILL.md (e.g., the sample
block starting with "# Ralph Spec Status", the "Next: Run the requirements
skill..." block, the "## api-auth [packages/api/specs]" block, and other blocks
around lines noted in the review) lack language tags and violate MD040; update
each triple-backtick fence to include a language tag such as ```text or ```md so
they are explicitly labeled (apply to the blocks containing "# Ralph Spec
Status", the example command block "ralph:start my-feature...", the "Next: Run
the requirements skill..." paragraph, and the "## api-auth [packages/api/specs]"
/ "Related: auth-system..." blocks) and ensure every opening ``` has a matching
closing ``` afterward.

In `@specs/.index/index-state.json`:
- Around line 19-23: The "opencode-codex-support" tasks entry is missing the
taskIndex and totalTasks fields; update the JSON object for the entry with name
"opencode-codex-support" to include the same task indexing fields used by other
"tasks" phase entries (add "taskIndex": <number> and "totalTasks": <number> with
the appropriate values consistent with the rest of the phase), ensuring the
object structure matches the other entries (e.g., those for
"implement-ralph-wiggum", "speckit-stop-hook",
"reality-verification-principle").

In `@specs/.index/index.md`:
- Line 19: The index entry for spec "opencode-codex-support" is missing the
task-count in the status column; update the index generator logic that builds
the index row for specs (the code that formats spec rows and the renderer that
produces the "| opencode-codex-support | ./specs | tasks |  |" line) to compute
completed/total tasks (16/20) and render it as "16/20 tasks" in the status
column; specifically, locate the function that assembles spec metadata (the spec
row formatter / index row renderer) and add a calculation using the spec's
completedTasks and totalTasks fields, then insert the formatted string into the
fourth column for in-progress specs.

In `@specs/opencode-codex-support/tasks.md`:
- Around line 129-221: Phase 2 lacks a mid-phase quality checkpoint: insert a
new "[VERIFY]" checkpoint immediately after task 2.2 (after the "Create OpenCode
execution loop adapter" block) that validates the state of the work so far; the
checkpoint should confirm adapters/opencode directory exists,
adapters/opencode/hooks/execution-loop.ts is present and TypeScript-valid,
adapters/opencode/README.md exists, and that the AGENTS.md generator script
(plugins/ralph-specum/scripts/generate-agents-md.sh) can read design.md and
produce AGENTS.md (or at minimum the generator file exists and is executable);
label it as a verification task consistent with existing 2.5 format and update
the checklist to include this new verify item.
- Around line 11-127: Insert a new [VERIFY] checkpoint after task 1.3 that
validates the first three SKILL.md files (start, research, requirements) exist
under plugins/ralph-specum/skills/workflow/, contain frontmatter, and are free
of Claude Code-specific references; update the Phase 1 list to include this
checkpoint (e.g., "1.4 [VERIFY] — verify start/research/requirements SKILL.md
existence and tool-agnosticness") and renumber subsequent tasks (design, tasks,
implement, status/cancel) accordingly so every 2–3 tasks has a quality
checkpoint as required by the specs; ensure the verification commands reference
the three paths and grep for the banned tokens ("Task
tool|AskUserQuestion|TeamCreate|allowed-tools|subagent_type") in those files.

In `@tests/test-artifact-portability.sh`:
- Around line 37-47: The aggregate search uses grep -rn with TOOL_KEYWORDS
containing '|' but without extended regex, so the alternation is treated
literally; update the invocation that sets TEMPLATE_MATCHES (the grep command
referencing "$TOOL_KEYWORDS" and "$TEMPLATE_DIR") to use extended regex (add -E)
so the '|' separators work as intended and the aggregate check actually finds
any of the TOOL_KEYWORDS; ensure you keep the existing 2>/dev/null || true
behavior and the variable names TEMPLATE_MATCHES, TOOL_KEYWORDS, and
TEMPLATE_DIR unchanged.
🧹 Nitpick comments (11)
plugins/ralph-specum/skills/workflow/tasks/SKILL.md (1)

124-128: Hardcoded /tmp/state.json is a collision risk.

If two specs run concurrently (or another process uses the same path), writing to a fixed /tmp/state.json can clobber data. The same pattern appears in the research and requirements SKILL.md files.

Consider using mktemp instead:

Proposed fix
-jq --argjson total "$TOTAL" '.totalTasks = $total | .awaitingApproval = true' "$SPEC_DIR/.ralph-state.json" > /tmp/state.json && mv /tmp/state.json "$SPEC_DIR/.ralph-state.json"
+TMP=$(mktemp) && jq --argjson total "$TOTAL" '.totalTasks = $total | .awaitingApproval = true' "$SPEC_DIR/.ralph-state.json" > "$TMP" && mv "$TMP" "$SPEC_DIR/.ralph-state.json"
plugins/ralph-specum/skills/workflow/requirements/SKILL.md (1)

147-150: Same /tmp/state.json collision risk as in tasks/SKILL.md.

Use mktemp for the temporary file to avoid concurrent-write collisions.

Proposed fix
-jq '.awaitingApproval = true' "$SPEC_DIR/.ralph-state.json" > /tmp/state.json && mv /tmp/state.json "$SPEC_DIR/.ralph-state.json"
+TMP=$(mktemp) && jq '.awaitingApproval = true' "$SPEC_DIR/.ralph-state.json" > "$TMP" && mv "$TMP" "$SPEC_DIR/.ralph-state.json"
adapters/codex/AGENTS.md.template (1)

35-38: Available Skills table only lists ralph-implement.

The PR adds 8 SKILL.md files (start, research, requirements, design, tasks, implement, status, cancel), but the template only surfaces ralph-implement. This may be intentional for Codex (where the user manually drives earlier phases), but consider listing all skills so Codex users can discover them.

adapters/opencode/README.md (1)

48-59: Shared config path .claude/ralph-specum.local.md may confuse OpenCode-only users.

The adapter reuses the Claude Code config path (.claude/ralph-specum.local.md) for settings. This is documented as intentional for cross-tool config sharing, but OpenCode-only users who have never used Claude Code may find the .claude/ directory name misleading. Consider mentioning this rationale briefly in the README (e.g., "This path is shared with the Claude Code plugin so configuration works across both tools").

plugins/ralph-specum/skills/workflow/implement/SKILL.md (1)

155-160: Hardcoded /tmp/state.json temp path in state-update snippets is fragile.

The jq update patterns throughout this document (lines 155-160, 212-214, 322-323, 328-330, 348) all use /tmp/state.json as an intermediate file. This is a predictable path that can cause issues in multi-user or concurrent environments (race conditions, symlink attacks). Since AI agents will follow these snippets literally, consider using a spec-local temp path or mktemp.

♻️ Example: use spec-local temp path
 jq '.taskIteration += 1 | .globalIteration += 1' \
-  "$SPEC_DIR/.ralph-state.json" > /tmp/state.json && \
-  mv /tmp/state.json "$SPEC_DIR/.ralph-state.json"
+  "$SPEC_DIR/.ralph-state.json" > "$SPEC_DIR/.ralph-state.json.tmp" && \
+  mv "$SPEC_DIR/.ralph-state.json.tmp" "$SPEC_DIR/.ralph-state.json"
tests/test-claude-code-regression.sh (1)

73-94: Glob patterns may break the script if no matching files exist.

If $PLUGIN_DIR/commands/*.md matches nothing, bash iterates once with the literal glob string, and head -1 on it will fail — aborting the script under set -e. Same applies to agents/*.md on line 100. Adding a nullglob guard or an existence check would make this more resilient.

♻️ Suggested guard
 echo "Test 4: Command frontmatter validation..."
+shopt -s nullglob
 for cmd in "$PLUGIN_DIR"/commands/*.md; do

Or check before looping:

+CMD_FILES=("$PLUGIN_DIR"/commands/*.md)
+if [ ! -e "${CMD_FILES[0]:-}" ]; then
+  fail "No command .md files found"
+else
 for cmd in "$PLUGIN_DIR"/commands/*.md; do
   ...
 done
+fi
adapters/config/generate-config.sh (1)

96-118: cfg and cfg_bool are identical — consolidate.

Both functions have the exact same implementation. This duplication adds maintenance burden without benefit.

♻️ Proposed fix
 cfg() {
   local path="$1"
   local default="$2"
   local val
   val="$(printf '%s' "$CONFIG" | jq -r "$path // empty")"
   if [ -z "$val" ]; then
     printf '%s' "$default"
   else
     printf '%s' "$val"
   fi
 }
-
-cfg_bool() {
-  local path="$1"
-  local default="$2"
-  local val
-  val="$(printf '%s' "$CONFIG" | jq -r "$path // empty")"
-  if [ -z "$val" ]; then
-    printf '%s' "$default"
-  else
-    printf '%s' "$val"
-  fi
-}

Then replace all cfg_bool calls with cfg.

specs/opencode-codex-support/design.md (1)

53-63: Add language identifiers to fenced code blocks.

The directory-structure code blocks at lines 53, 115, and 139 have no language specified, triggering markdownlint MD040. Use text or plaintext to satisfy the linter while conveying they are not executable code.

♻️ Example fix
-```
+```text
 skills/workflow/
   start/SKILL.md

Also applies to: 115-127, 139-145

adapters/opencode/hooks/execution-loop.ts (3)

200-223: Cleanup loop aborts on first statSync/unlinkSync failure, skipping remaining files.

If fs.statSync or fs.unlinkSync throws for one entry (e.g., a race with another process), the outer catch swallows the error and exits the entire loop, leaving other orphaned files uncleaned.

Suggested fix: per-file try-catch
     for (const entry of entries) {
       if (/^\.progress-task-\d+\.md$/.test(entry)) {
-        const fullPath = path.join(specDir, entry);
-        const stat = fs.statSync(fullPath);
-        if (now - stat.mtimeMs > cutoffMs) {
-          fs.unlinkSync(fullPath);
+        try {
+          const fullPath = path.join(specDir, entry);
+          const stat = fs.statSync(fullPath);
+          if (now - stat.mtimeMs > cutoffMs) {
+            fs.unlinkSync(fullPath);
+          }
+        } catch {
+          // Ignore per-file cleanup errors (e.g., race condition)
         }
       }
     }
-  } catch {
-    // Ignore cleanup errors
-  }

134-150: Parsed JSON fields are not type-validated — non-numeric taskIndex/totalTasks would silently corrupt loop logic.

data.taskIndex ?? 0 only falls back when the value is null/undefined. A string like "3" passes through and will cause incorrect arithmetic comparisons (e.g., "3" >= 20 is false in JS but "3" >= "20" is true). Consider coercing with Number() or adding basic type guards.

Suggested fix
     return {
       phase: data.phase ?? "unknown",
-      taskIndex: data.taskIndex ?? 0,
-      totalTasks: data.totalTasks ?? 0,
-      taskIteration: data.taskIteration ?? 1,
-      globalIteration: data.globalIteration ?? 1,
-      maxGlobalIterations: data.maxGlobalIterations ?? 100,
-      maxTaskIterations: data.maxTaskIterations ?? 5,
+      taskIndex: Number(data.taskIndex) || 0,
+      totalTasks: Number(data.totalTasks) || 0,
+      taskIteration: Number(data.taskIteration) || 1,
+      globalIteration: Number(data.globalIteration) || 1,
+      maxGlobalIterations: Number(data.maxGlobalIterations) || 100,
+      maxTaskIterations: Number(data.maxTaskIterations) || 5,
       recoveryMode: data.recoveryMode ?? false,
     };

181-195: Entire transcript is read into memory to check the last 500 lines.

For large transcripts this is wasteful. Since this is a POC, it's acceptable now, but consider reading only the tail of the file (e.g., last ~50 KB) if transcripts grow large in production.

Comment on lines +339 to +344
# Fallback: find most recently modified design.md
for design_file in "$spec_root"/*/design.md; do
if [ -f "$design_file" ]; then
latest_spec="$(dirname "$design_file")"
fi
done
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fallback spec discovery doesn't sort by modification time despite the comment.

The comment on line 339 says "find most recently modified design.md", but the glob loop just overwrites latest_spec on each iteration, yielding the last alphabetically — not the most recently modified.

🐛 Proposed fix: use `ls -t` or `find` with `-newer` to sort by mtime
           # Fallback: find most recently modified design.md
-          for design_file in "$spec_root"/*/design.md; do
-            if [ -f "$design_file" ]; then
-              latest_spec="$(dirname "$design_file")"
-            fi
-          done
+          local newest
+          newest="$(find "$spec_root" -maxdepth 2 -name 'design.md' -printf '%T@ %p\n' 2>/dev/null \
+            | sort -rn | head -1 | cut -d' ' -f2-)"
+          if [ -n "$newest" ]; then
+            latest_spec="$(dirname "$newest")"
+          fi

Note: -printf is GNU find-specific. On macOS, use stat -f '%m %N' or find ... -exec stat ... instead, depending on portability requirements.

🤖 Prompt for AI Agents
In `@adapters/config/generate-config.sh` around lines 339 - 344, The fallback loop
for discovering the latest spec (iterating design_file and setting latest_spec)
does not actually pick the most recently modified file; update the logic to sort
design.md files by modification time and pick the newest one (e.g., use ls -t
"$spec_root"/*/design.md | head -n1 or use find ... -printf '%T@ %p' | sort -n |
tail -n1) then set latest_spec="$(dirname "<that-most-recent-path>")"; ensure
the code references the existing variables design_file, latest_spec, and
spec_root so behavior and variable names remain consistent.

Comment on lines 67 to 92
function getSpecsDirs(cwd: string): string[] {
const settingsPath = path.join(cwd, ".claude", "ralph-specum.local.md");

if (!fs.existsSync(settingsPath)) {
return [DEFAULT_SPECS_DIR];
}

try {
const content = fs.readFileSync(settingsPath, "utf-8");
// Extract specs_dirs from YAML frontmatter
const frontmatter = content.match(/^---\n([\s\S]*?)\n---/);
if (!frontmatter) return [DEFAULT_SPECS_DIR];

const match = frontmatter[1].match(/^specs_dirs:\s*\[([^\]]*)\]/m);
if (!match) return [DEFAULT_SPECS_DIR];

const dirs = match[1]
.split(",")
.map((d) => d.trim().replace(/^["']|["']$/g, ""))
.filter(Boolean);

return dirs.length > 0 ? dirs : [DEFAULT_SPECS_DIR];
} catch {
return [DEFAULT_SPECS_DIR];
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if ralph-config.schema.json exists and its content
fd "ralph-config" --type f

Repository: tzachbon/smart-ralph

Length of output: 104


🏁 Script executed:

# Check what config paths the OpenCode adapter and other adapters use
rg -n "\.claude/" adapters/ --type ts --type sh -A 2 -B 2

Repository: tzachbon/smart-ralph

Length of output: 46


🏁 Script executed:

# Search for how other adapters load configuration
rg -n "config|Config" adapters/ --type ts | head -30

Repository: tzachbon/smart-ralph

Length of output: 235


🏁 Script executed:

# Check the actual execution-loop.ts file around lines 67-92 and line 157
fd "execution-loop.ts" --type f -x cat -n {}

Repository: tzachbon/smart-ralph

Length of output: 13523


🏁 Script executed:

# Read the ralph-config.schema.json to see what fields it defines
cat adapters/config/ralph-config.schema.json

Repository: tzachbon/smart-ralph

Length of output: 3785


🏁 Script executed:

# Check how other adapters load configuration
find adapters -name "*.ts" -o -name "*.js" | head -5 | xargs ls -la

Repository: tzachbon/smart-ralph

Length of output: 155


🏁 Script executed:

# Search for references to .opencode/ or opencode-specific config paths
rg "opencode|\.opencode" --type ts --type js

Repository: tzachbon/smart-ralph

Length of output: 556


🏁 Script executed:

# Check what config is actually used by looking at adapter index or main files
find adapters -name "index.ts" -o -name "index.js" -o -name "*adapter*" | xargs cat | head -100

Repository: tzachbon/smart-ralph

Length of output: 93


🏁 Script executed:

# Search for where ralph-config.json is loaded or referenced
rg "ralph-config" --type ts --type js --type json -A 3 -B 1

Repository: tzachbon/smart-ralph

Length of output: 627


🏁 Script executed:

# Check if other adapters exist and how they handle configuration
find adapters -type f -name "*.ts" -o -name "*.js" | xargs ls -la

Repository: tzachbon/smart-ralph

Length of output: 155


🏁 Script executed:

# Search for references to .claude/ in the entire repo to understand its scope
rg "\.claude" -g "!node_modules" -A 2 -B 2

Repository: tzachbon/smart-ralph

Length of output: 50378


🏁 Script executed:

# Check Claude Code plugin configuration to confirm .claude/ is Claude-specific
find . -path "./plugins" -o -path "./plugins/*" | head -20

Repository: tzachbon/smart-ralph

Length of output: 1026


OpenCode adapter reads settings from Claude Code-specific path (.claude/).

getSpecsDirs() (lines 67–92) and isPluginDisabled() (line 157) both read configuration from .claude/ralph-specum.local.md. This is a Claude Code plugin convention. An OpenCode adapter must not depend on Claude Code configuration paths—it should read from either tool-agnostic config (ralph-config.json at project root, defining spec_dirs) or OpenCode-specific config (e.g., .opencode/ or a tool-specific section). As written, the adapter only works if users have Claude Code configured alongside OpenCode.

🤖 Prompt for AI Agents
In `@adapters/opencode/hooks/execution-loop.ts` around lines 67 - 92,
getSpecsDirs() and isPluginDisabled() currently read Claude Code-specific
".claude/ralph-specum.local.md" which is wrong for the OpenCode adapter; update
both functions to prefer a tool-agnostic project config (ralph-config.json at
repo root with a "spec_dirs" array) and then fall back to an OpenCode-specific
config (e.g., ".opencode/ralph-config.json" or a ".opencode" frontmatter file)
before using DEFAULT_SPECS_DIR; specifically, modify getSpecsDirs to: 1) attempt
to read and parse ralph-config.json in cwd and return its spec_dirs if present
and valid, 2) if not present, attempt to read an ".opencode" config (either JSON
or frontmatter) for spec dirs, 3) only if both are missing fallback to
DEFAULT_SPECS_DIR; similarly update isPluginDisabled to check ralph-config.json
and .opencode config for the plugin disabled flag instead of
".claude/ralph-specum.local.md", and keep existing file-parsing error handling
and trimming logic while removing any dependency on
".claude/ralph-specum.local.md".

Comment on lines +19 to +23
{
"name": "opencode-codex-support",
"path": "./specs/opencode-codex-support",
"phase": "tasks"
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

opencode-codex-support entry is missing taskIndex and totalTasks.

Other specs in the "tasks" phase (e.g., implement-ralph-wiggum, speckit-stop-hook, reality-verification-principle) all include taskIndex and totalTasks. This entry should be consistent.

Proposed fix
     {
       "name": "opencode-codex-support",
       "path": "./specs/opencode-codex-support",
-      "phase": "tasks"
+      "phase": "tasks",
+      "taskIndex": <current>,
+      "totalTasks": <total>
     },
🤖 Prompt for AI Agents
In `@specs/.index/index-state.json` around lines 19 - 23, The
"opencode-codex-support" tasks entry is missing the taskIndex and totalTasks
fields; update the JSON object for the entry with name "opencode-codex-support"
to include the same task indexing fields used by other "tasks" phase entries
(add "taskIndex": <number> and "totalTasks": <number> with the appropriate
values consistent with the rest of the phase), ensuring the object structure
matches the other entries (e.g., those for "implement-ralph-wiggum",
"speckit-stop-hook", "reality-verification-principle").

| Spec | Directory | Phase | Status |
|------|-----------|-------|--------|
| add-skills-doc | ./specs | completed | done |
| opencode-codex-support | ./specs | tasks | |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if there's a .ralph-state.json for this spec that might indicate actual phase
echo "=== Checking .ralph-state.json ==="
find specs/opencode-codex-support -name ".ralph-state.json" 2>/dev/null
if [ -f "specs/opencode-codex-support/.ralph-state.json" ]; then
  echo "Content of .ralph-state.json:"
  cat specs/opencode-codex-support/.ralph-state.json
fi

# Check the tasks.md to see if all tasks are checked
echo ""
echo "=== Checking task completion ==="
if [ -f "specs/opencode-codex-support/tasks.md" ]; then
  echo "Unchecked tasks:"
  grep -c '^\- \[ \]' specs/opencode-codex-support/tasks.md || echo "0"
  echo "Checked tasks:"
  grep -c '^\- \[x\]' specs/opencode-codex-support/tasks.md || echo "0"
else
  echo "tasks.md not found"
fi

# Check .progress.md if it exists
echo ""
echo "=== Checking .progress.md ==="
if [ -f "specs/opencode-codex-support/.progress.md" ]; then
  head -50 specs/opencode-codex-support/.progress.md
else
  echo ".progress.md not found"
fi

# Check the index.md itself to understand structure
echo ""
echo "=== Checking index.md structure ==="
head -30 specs/.index/index.md

Repository: tzachbon/smart-ralph

Length of output: 4804


Spec opencode-codex-support status is missing task count in the index.

The entry shows phase: tasks with an empty status column, while other in-progress specs display task counts (e.g., 27/35 tasks, 9/11 tasks). The spec currently has 16/20 tasks completed with 4 remaining. The index generator should compute and display the task count for this spec's status column.

🤖 Prompt for AI Agents
In `@specs/.index/index.md` at line 19, The index entry for spec
"opencode-codex-support" is missing the task-count in the status column; update
the index generator logic that builds the index row for specs (the code that
formats spec rows and the renderer that produces the "| opencode-codex-support |
./specs | tasks |  |" line) to compute completed/total tasks (16/20) and render
it as "16/20 tasks" in the status column; specifically, locate the function that
assembles spec metadata (the spec row formatter / index row renderer) and add a
calculation using the spec's completedTasks and totalTasks fields, then insert
the formatted string into the fourth column for in-progress specs.

Comment on lines +11 to +127
## Phase 1: Make It Work (POC)

Focus: Get SKILL.md portability working end-to-end. Validate that a user can discover and follow the Ralph workflow via SKILL.md files in any tool.

- [x] 1.1 Audit templates and schemas for Claude Code-specific references
- **Do**:
1. Read all files in `plugins/ralph-specum/templates/` and `plugins/ralph-specum/schemas/spec.schema.json`
2. Search for Claude Code-specific references: "Task tool", "AskUserQuestion", "TeamCreate", "SendMessage", "Stop hook", "allowed-tools", "subagent_type", "claude", "plugin.json"
3. Document any findings in `.progress.md`
4. If templates/schemas are already tool-agnostic, note "no changes needed"
5. If changes needed, replace tool-specific references with generic alternatives (e.g., "delegate to subagent" instead of "use Task tool")
- **Files**: `plugins/ralph-specum/templates/*.md`, `plugins/ralph-specum/schemas/spec.schema.json`
- **Done when**: All templates and schemas contain zero Claude Code-specific tool references
- **Verify**: `grep -rn "Task tool\|AskUserQuestion\|TeamCreate\|SendMessage\|Stop hook\|subagent_type\|allowed-tools" plugins/ralph-specum/templates/ plugins/ralph-specum/schemas/ | grep -v "^Binary" | wc -l` returns 0
- **Commit**: `feat(portability): audit and clean templates for cross-tool compatibility`
- _Requirements: FR-4, AC-2.1_
- _Design: Component B_

- [x] 1.2 Create start SKILL.md
- **Do**:
1. Create directory `plugins/ralph-specum/skills/workflow/start/`
2. Create `SKILL.md` with progressive disclosure:
- Level 1: Overview of what start does (detect new vs resume, create spec directory, initialize state)
- Level 2: Step-by-step instructions (parse name/goal, create directory, write .ralph-state.json, write .progress.md, set .current-spec)
- Level 3: Advanced options (--quick mode, --fresh, --specs-dir, --commit-spec)
3. Use tool-agnostic language throughout (no "Task tool", no "AskUserQuestion")
4. Include state file format documentation inline
5. Reference spec workflow phases: research -> requirements -> design -> tasks -> implement
- **Files**: `plugins/ralph-specum/skills/workflow/start/SKILL.md`
- **Done when**: SKILL.md exists with all 3 disclosure levels, zero Claude Code-specific references
- **Verify**: `test -f plugins/ralph-specum/skills/workflow/start/SKILL.md && ! grep -q "Task tool\|AskUserQuestion\|TeamCreate\|allowed-tools" plugins/ralph-specum/skills/workflow/start/SKILL.md && echo "PASS"`
- **Commit**: `feat(skills): add universal start SKILL.md for cross-tool workflow`
- _Requirements: FR-1, FR-2, AC-1.1, AC-1.2, AC-1.3_
- _Design: Component A_

- [x] 1.3 Create research SKILL.md
- **Do**:
1. Create directory `plugins/ralph-specum/skills/workflow/research/`
2. Create `SKILL.md` with progressive disclosure:
- Level 1: Purpose of research phase (codebase analysis, external research, feasibility)
- Level 2: Steps (read goal from .progress.md, explore codebase, search web, write research.md, update state)
- Level 3: Parallel research notes (tool-specific), output format, research.md template
3. Tool-agnostic delegation language: "explore codebase" not "use Explore subagent"
- **Files**: `plugins/ralph-specum/skills/workflow/research/SKILL.md`
- **Done when**: SKILL.md provides complete research phase guidance
- **Verify**: `test -f plugins/ralph-specum/skills/workflow/research/SKILL.md && echo "PASS"`
- **Commit**: `feat(skills): add universal research SKILL.md`
- _Requirements: FR-1, FR-2, AC-1.1_
- _Design: Component A_

- [x] 1.4 Create requirements, design, and tasks SKILL.md files
- **Do**:
1. Create directories: `plugins/ralph-specum/skills/workflow/requirements/`, `design/`, `tasks/`
2. Create each SKILL.md with progressive disclosure following the same pattern as research:
- **requirements/SKILL.md**: User stories, acceptance criteria, FR/NFR tables. Reference requirements.md template.
- **design/SKILL.md**: Architecture, components, data flow, technical decisions. Reference design.md template.
- **tasks/SKILL.md**: POC-first 4-phase breakdown, task format (Do/Files/Done when/Verify/Commit). Reference tasks.md template.
3. All must be tool-agnostic
- **Files**: `plugins/ralph-specum/skills/workflow/requirements/SKILL.md`, `plugins/ralph-specum/skills/workflow/design/SKILL.md`, `plugins/ralph-specum/skills/workflow/tasks/SKILL.md`
- **Done when**: All three SKILL.md files exist with full progressive disclosure
- **Verify**: `for d in requirements design tasks; do test -f "plugins/ralph-specum/skills/workflow/$d/SKILL.md" || echo "MISSING: $d"; done && echo "PASS"`
- **Commit**: `feat(skills): add requirements, design, and tasks SKILL.md files`
- _Requirements: FR-1, FR-2, AC-1.1_
- _Design: Component A_

- [x] 1.5 Create implement SKILL.md (with Codex-compatible task progression)
- **Do**:
1. Create directory `plugins/ralph-specum/skills/workflow/implement/`
2. Create `SKILL.md` with progressive disclosure:
- Level 1: Purpose of execution (run tasks from tasks.md sequentially)
- Level 2: Manual task execution loop:
a. Read .ralph-state.json for taskIndex and totalTasks
b. Read tasks.md, find task at taskIndex
c. Execute Do steps, check Done when criteria
d. Run Verify command
e. If pass: mark task [x] in tasks.md, update .progress.md, increment taskIndex in state file
f. If fail: document error, retry or stop
g. Repeat until taskIndex >= totalTasks
h. When complete: delete .ralph-state.json, report ALL_TASKS_COMPLETE
- Level 3: Tool-specific execution modes:
- Claude Code: Automatic via stop-hook (hands-free)
- OpenCode: Automatic via JS/TS hooks
- Codex CLI: Manual re-invocation per task (re-invoke this skill after each task)
3. Include state file update instructions using jq
4. This is the most critical SKILL.md -- it enables Codex CLI execution
- **Files**: `plugins/ralph-specum/skills/workflow/implement/SKILL.md`
- **Done when**: SKILL.md provides complete execution guidance that works without hooks
- **Verify**: `test -f plugins/ralph-specum/skills/workflow/implement/SKILL.md && grep -q "taskIndex" plugins/ralph-specum/skills/workflow/implement/SKILL.md && echo "PASS"`
- **Commit**: `feat(skills): add universal implement SKILL.md with hook-free task progression`
- _Requirements: FR-1, FR-6, AC-1.1, AC-4.1, AC-4.2, AC-4.3_
- _Design: Component A, Component E_

- [x] 1.6 Create status and cancel SKILL.md files
- **Do**:
1. Create directories: `plugins/ralph-specum/skills/workflow/status/`, `cancel/`
2. **status/SKILL.md**: Read all spec directories, show phase/progress/files for each. List available commands.
3. **cancel/SKILL.md**: Delete .ralph-state.json, optionally remove spec directory, clear .current-spec.
4. Both must be tool-agnostic and reference path resolution patterns
- **Files**: `plugins/ralph-specum/skills/workflow/status/SKILL.md`, `plugins/ralph-specum/skills/workflow/cancel/SKILL.md`
- **Done when**: Both SKILL.md files exist with full guidance
- **Verify**: `test -f plugins/ralph-specum/skills/workflow/status/SKILL.md && test -f plugins/ralph-specum/skills/workflow/cancel/SKILL.md && echo "PASS"`
- **Commit**: `feat(skills): add status and cancel SKILL.md files`
- _Requirements: FR-1, AC-1.1_
- _Design: Component A_

- [ ] 1.7 [VERIFY] POC Checkpoint -- SKILL.md completeness
- **Do**:
1. Verify all 8 SKILL.md files exist under `plugins/ralph-specum/skills/workflow/`
2. Verify zero Claude Code-specific references across all SKILL.md files
3. Verify each has name and description frontmatter
4. Verify progressive disclosure (check for "## Overview", "## Steps", or equivalent headers)
5. Verify templates and schemas are tool-agnostic
- **Verify**: All commands below must pass:
- `ls plugins/ralph-specum/skills/workflow/*/SKILL.md | wc -l` returns 8
- `grep -rl "Task tool\|AskUserQuestion\|TeamCreate\|allowed-tools\|subagent_type" plugins/ralph-specum/skills/workflow/ | wc -l` returns 0
- **Done when**: All 8 SKILL.md files exist, all tool-agnostic, all have progressive disclosure
- **Commit**: `chore(qa): verify SKILL.md completeness checkpoint`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing quality checkpoints in Phase 1 — gap of 6 tasks before the first [VERIFY].

Phase 1 has tasks 1.1–1.6 (6 implementation tasks) before the checkpoint at 1.7. The guideline requires a quality checkpoint every 2–3 tasks. Insert a [VERIFY] checkpoint after task 1.3 (e.g., verify the first three SKILL.md files exist and are tool-agnostic) to stay within the required cadence.

Suggested checkpoint insertion after line 59
   - _Design: Component A_
 
+- [ ] 1.3b [VERIFY] Mid-POC checkpoint -- first SKILL.md files
+  - **Do**:
+    1. Verify start, research SKILL.md files exist
+    2. Verify zero Claude Code-specific references in created files
+    3. Verify each has frontmatter and progressive disclosure
+  - **Verify**: `ls plugins/ralph-specum/skills/workflow/{start,research}/SKILL.md | wc -l` returns 2
+  - **Done when**: First SKILL.md files pass tool-agnostic and structure checks
+  - **Commit**: `chore(qa): mid-POC SKILL.md checkpoint`
+
 - [x] 1.4 Create requirements, design, and tasks SKILL.md files

As per coding guidelines, specs/**/tasks.md: "Quality checkpoints must be inserted every 2-3 tasks throughout all phases in task specifications." Based on learnings, "Quality checkpoints must be inserted every 2-3 tasks throughout all phases in task specifications."

🤖 Prompt for AI Agents
In `@specs/opencode-codex-support/tasks.md` around lines 11 - 127, Insert a new
[VERIFY] checkpoint after task 1.3 that validates the first three SKILL.md files
(start, research, requirements) exist under
plugins/ralph-specum/skills/workflow/, contain frontmatter, and are free of
Claude Code-specific references; update the Phase 1 list to include this
checkpoint (e.g., "1.4 [VERIFY] — verify start/research/requirements SKILL.md
existence and tool-agnosticness") and renumber subsequent tasks (design, tasks,
implement, status/cancel) accordingly so every 2–3 tasks has a quality
checkpoint as required by the specs; ensure the verification commands reference
the three paths and grep for the banned tokens ("Task
tool|AskUserQuestion|TeamCreate|allowed-tools|subagent_type") in those files.

Comment on lines +129 to +221
## Phase 2: Refactoring

After SKILL.md portability validated, add tool-specific adapters and AGENTS.md generation.

- [x] 2.1 Create AGENTS.md generator
- **Do**:
1. Add AGENTS.md generation logic to the plan-synthesizer agent or as a standalone script
2. The generator reads design.md and extracts:
- Architecture overview
- Component responsibilities
- Technical decisions
- File structure
- Existing patterns to follow
3. Outputs AGENTS.md with sections: Architecture, Coding Conventions, File Structure, Key Decisions
4. Generation is optional (controlled by `--generate-agents` flag or config)
5. Place generated AGENTS.md at project root (not inside spec directory)
- **Files**: `plugins/ralph-specum/scripts/generate-agents-md.sh`
- **Done when**: Script reads design.md and outputs valid AGENTS.md
- **Verify**: `bash plugins/ralph-specum/scripts/generate-agents-md.sh --spec-path ./specs/opencode-codex-support && test -f AGENTS.md && echo "PASS"`
- **Commit**: `feat(agents-md): add AGENTS.md generator from design.md`
- _Requirements: FR-7, AC-5.1, AC-5.2, AC-5.3_
- _Design: Component C_

- [x] 2.2 Create OpenCode execution loop adapter
- **Do**:
1. Create `adapters/opencode/` directory structure
2. Create `adapters/opencode/hooks/execution-loop.ts`:
- Reads .ralph-state.json on `session.idle` or `tool.execute.after` events
- If phase=execution and taskIndex < totalTasks: output continuation prompt
- If taskIndex >= totalTasks: signal completion
- Mirrors stop-watcher.sh logic in TypeScript
3. Create `adapters/opencode/README.md` with setup instructions:
- How to register the hook in opencode.json
- How to configure spec directories
- Example opencode.json snippet
- **Files**: `adapters/opencode/hooks/execution-loop.ts`, `adapters/opencode/README.md`
- **Done when**: TypeScript hook file exists with execution loop logic, README has setup instructions
- **Verify**: `test -f adapters/opencode/hooks/execution-loop.ts && test -f adapters/opencode/README.md && echo "PASS"`
- **Commit**: `feat(opencode): add execution loop adapter with JS/TS hooks`
- _Requirements: FR-5, FR-10, AC-3.1, AC-3.2, AC-3.3, AC-3.4_
- _Design: Component D_

- [x] 2.3 Create Codex CLI adapter
- **Do**:
1. Create `adapters/codex/` directory structure
2. Create `adapters/codex/skills/ralph-implement/SKILL.md`:
- Enhanced implement skill specifically for Codex (no hooks)
- Reads .ralph-state.json and shows current task with full context
- Provides explicit "after completing this task, re-invoke this skill for the next task"
- Includes state file update instructions (jq commands for incrementing taskIndex)
3. Create `adapters/codex/AGENTS.md.template`:
- Template that can be populated from any spec's design.md
4. Create `adapters/codex/README.md`:
- How to set up Ralph skills in Codex CLI
- How to place SKILL.md files for discovery
- Workflow walkthrough
- **Files**: `adapters/codex/skills/ralph-implement/SKILL.md`, `adapters/codex/AGENTS.md.template`, `adapters/codex/README.md`
- **Done when**: Codex adapter files exist with complete guidance for hook-free execution
- **Verify**: `test -f adapters/codex/skills/ralph-implement/SKILL.md && test -f adapters/codex/README.md && echo "PASS"`
- **Commit**: `feat(codex): add Codex CLI adapter with SKILL.md-based execution`
- _Requirements: FR-6, FR-10, AC-4.1, AC-4.2, AC-4.3_
- _Design: Component E_

- [x] 2.4 Create configuration bridge
- **Do**:
1. Create `adapters/config/` directory
2. Create `adapters/config/ralph-config.schema.json`:
- Defines tool-agnostic Ralph settings (spec_dirs, default_branch, commit_spec, max_iterations)
3. Create `adapters/config/generate-config.sh`:
- Reads ralph-config.json from project root
- Generates Claude Code config (validates existing .claude-plugin/ is compatible)
- Generates OpenCode config (opencode.json plugin entry, .opencode/ directory)
- Generates Codex config (copies skills, generates AGENTS.md)
4. Create `adapters/config/README.md` with usage instructions
- **Files**: `adapters/config/ralph-config.schema.json`, `adapters/config/generate-config.sh`, `adapters/config/README.md`
- **Done when**: Config schema defined, generator script creates tool-specific configs
- **Verify**: `test -f adapters/config/ralph-config.schema.json && test -f adapters/config/generate-config.sh && echo "PASS"`
- **Commit**: `feat(config): add configuration bridge for multi-tool setup`
- _Requirements: FR-8, AC-6.1, AC-6.2, AC-6.3, AC-6.4_
- _Design: Component F_

- [ ] 2.5 [VERIFY] Quality checkpoint -- Adapters and generators
- **Do**:
1. Verify all adapter directories exist (opencode, codex, config)
2. Verify AGENTS.md generator works on existing spec
3. Verify OpenCode adapter has valid TypeScript
4. Verify Codex adapter SKILL.md has task progression guidance
5. Verify existing Claude Code plugin is unchanged (compare against HEAD~N)
- **Verify**: All commands below must pass:
- `test -d adapters/opencode && test -d adapters/codex && test -d adapters/config`
- `git diff HEAD -- plugins/ralph-specum/.claude-plugin/plugin.json plugins/ralph-specum/hooks/ | wc -l` returns 0 (no changes to existing plugin core)
- **Done when**: All adapters exist, Claude Code plugin unchanged
- **Commit**: `chore(qa): verify adapters and zero-regression checkpoint`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing quality checkpoint in Phase 2 — gap of 4 tasks before [VERIFY].

Phase 2 has tasks 2.1–2.4 (4 implementation tasks) before the checkpoint at 2.5. Insert a [VERIFY] checkpoint after task 2.2 to comply with the every-2–3-task checkpoint cadence.

Suggested checkpoint insertion after line 169
   - _Design: Component D_
 
+- [ ] 2.2b [VERIFY] Mid-refactor checkpoint -- AGENTS.md and OpenCode adapter
+  - **Do**:
+    1. Verify AGENTS.md generator produces valid output
+    2. Verify OpenCode adapter has valid TypeScript structure
+  - **Verify**: `test -f adapters/opencode/hooks/execution-loop.ts && bash plugins/ralph-specum/scripts/generate-agents-md.sh --spec-path ./specs/opencode-codex-support && test -f AGENTS.md && echo "PASS"`
+  - **Done when**: Generator and OpenCode adapter verified
+  - **Commit**: `chore(qa): mid-refactor AGENTS.md and adapter checkpoint`
+
 - [x] 2.3 Create Codex CLI adapter

As per coding guidelines, specs/**/tasks.md: "Quality checkpoints must be inserted every 2-3 tasks throughout all phases in task specifications."

🤖 Prompt for AI Agents
In `@specs/opencode-codex-support/tasks.md` around lines 129 - 221, Phase 2 lacks
a mid-phase quality checkpoint: insert a new "[VERIFY]" checkpoint immediately
after task 2.2 (after the "Create OpenCode execution loop adapter" block) that
validates the state of the work so far; the checkpoint should confirm
adapters/opencode directory exists, adapters/opencode/hooks/execution-loop.ts is
present and TypeScript-valid, adapters/opencode/README.md exists, and that the
AGENTS.md generator script (plugins/ralph-specum/scripts/generate-agents-md.sh)
can read design.md and produce AGENTS.md (or at minimum the generator file
exists and is executable); label it as a verification task consistent with
existing 2.5 format and update the checklist to include this new verify item.

Comment on lines +37 to +47
TOOL_KEYWORDS="Task tool|AskUserQuestion|TeamCreate|SendMessage|Stop hook|allowed-tools|subagent_type"

TEMPLATE_MATCHES=$(grep -rn "$TOOL_KEYWORDS" "$TEMPLATE_DIR"/ 2>/dev/null || true)
if [ -z "$TEMPLATE_MATCHES" ]; then
pass "Templates contain zero tool-specific references"
else
fail "Templates contain tool-specific references:"
echo "$TEMPLATE_MATCHES" | while IFS= read -r line; do
echo " $line"
done
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

grep without -E treats | as literal — the aggregate tool-keyword check always passes.

TOOL_KEYWORDS uses | as an OR separator, but grep -rn (line 39) is basic regex, where | is a literal character. This means the search looks for the full string "Task tool|AskUserQuestion|..." verbatim and will never match individual keywords. The test silently passes even when tool-specific references exist.

The per-template check on line 59 correctly uses \| (basic regex alternation in GNU grep), so it would catch issues — but the aggregate check on line 39 is dead.

🐛 Proposed fix: add -E flag for extended regex
-TEMPLATE_MATCHES=$(grep -rn "$TOOL_KEYWORDS" "$TEMPLATE_DIR"/ 2>/dev/null || true)
+TEMPLATE_MATCHES=$(grep -rn -E "$TOOL_KEYWORDS" "$TEMPLATE_DIR"/ 2>/dev/null || true)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
TOOL_KEYWORDS="Task tool|AskUserQuestion|TeamCreate|SendMessage|Stop hook|allowed-tools|subagent_type"
TEMPLATE_MATCHES=$(grep -rn "$TOOL_KEYWORDS" "$TEMPLATE_DIR"/ 2>/dev/null || true)
if [ -z "$TEMPLATE_MATCHES" ]; then
pass "Templates contain zero tool-specific references"
else
fail "Templates contain tool-specific references:"
echo "$TEMPLATE_MATCHES" | while IFS= read -r line; do
echo " $line"
done
fi
TOOL_KEYWORDS="Task tool|AskUserQuestion|TeamCreate|SendMessage|Stop hook|allowed-tools|subagent_type"
TEMPLATE_MATCHES=$(grep -rn -E "$TOOL_KEYWORDS" "$TEMPLATE_DIR"/ 2>/dev/null || true)
if [ -z "$TEMPLATE_MATCHES" ]; then
pass "Templates contain zero tool-specific references"
else
fail "Templates contain tool-specific references:"
echo "$TEMPLATE_MATCHES" | while IFS= read -r line; do
echo " $line"
done
fi
🤖 Prompt for AI Agents
In `@tests/test-artifact-portability.sh` around lines 37 - 47, The aggregate
search uses grep -rn with TOOL_KEYWORDS containing '|' but without extended
regex, so the alternation is treated literally; update the invocation that sets
TEMPLATE_MATCHES (the grep command referencing "$TOOL_KEYWORDS" and
"$TEMPLATE_DIR") to use extended regex (add -E) so the '|' separators work as
intended and the aggregate check actually finds any of the TOOL_KEYWORDS; ensure
you keep the existing 2>/dev/null || true behavior and the variable names
TEMPLATE_MATCHES, TOOL_KEYWORDS, and TEMPLATE_DIR unchanged.

1. Fix GitHub URL typo (zachbonfil → tzachbon) in AGENTS.md.template
2. Fix double backticks in Codex implement SKILL.md
3. Remove unused variables (PROJECT_ROOT, COMMIT_SPEC, MAX_ITERATIONS,
   MAX_TASK_ITERATIONS) and duplicate cfg_bool function from generate-config.sh
4. OpenCode adapter now reads ralph-config.json first (tool-agnostic),
   falls back to .claude/ralph-specum.local.md
5. Add speculative API note to OpenCode adapter header comment
6. Add "Keeping Config in Sync" section to config bridge README
7. Gitignore AGENTS.md (generated file, should not be tracked)
8. Remove duplicate cfg_bool, use cfg everywhere
9. Make test scripts executable
10. Settings template now shows all three tool config paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@adapters/config/generate-config.sh`:
- Around line 57-75: The --config handling in generate-config.sh assumes $2
exists and will fail under set -u if --config is the last arg; before assigning
CONFIG_PATH="$2" in the case branch for --config, add a guard to verify a next
argument exists and is not another option (check that $# -ge 2 and that $2 does
not start with '-') and if the check fails call usage or log_err and exit;
update the --config case around the assignment to CONFIG_PATH and the shift 2 to
only run after the validation.
🧹 Nitpick comments (2)
adapters/config/generate-config.sh (1)

25-25: SCRIPT_DIR is assigned but never referenced.

Shellcheck flags this (SC2034). Remove the assignment or use it (e.g., to resolve paths to sibling scripts like generate-agents-md.sh).

adapters/codex/skills/ralph-implement/SKILL.md (1)

153-156: Hardcoded /tmp/ralph-state.json in jq examples risks collision.

If two specs are processed concurrently (or another user runs the same flow), the shared temp path causes a race. Consider using mktemp or a spec-scoped temp path in the documented patterns.

♻️ Suggested pattern
-jq '.taskIteration += 1 | .globalIteration += 1' \
-  "$SPEC_DIR/.ralph-state.json" > /tmp/ralph-state.json && \
-  mv /tmp/ralph-state.json "$SPEC_DIR/.ralph-state.json"
+TMP=$(mktemp)
+jq '.taskIteration += 1 | .globalIteration += 1' \
+  "$SPEC_DIR/.ralph-state.json" > "$TMP" && \
+  mv "$TMP" "$SPEC_DIR/.ralph-state.json"

This pattern appears in multiple places (lines 154, 196, 255, 262).

Comment on lines +57 to +75
while [ $# -gt 0 ]; do
case "$1" in
--config)
CONFIG_PATH="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
--help)
usage
;;
*)
log_err "Unknown option: $1"
exit 1
;;
esac
done
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

--config without a following argument will crash under set -u.

If --config is passed as the last argument, $2 is unbound and the script errors out with an unhelpful message. Guard with a check before accessing $2.

🛡️ Proposed fix
     --config)
+      if [ $# -lt 2 ]; then
+        log_err "--config requires a path argument"
+        exit 1
+      fi
       CONFIG_PATH="$2"
       shift 2
       ;;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
while [ $# -gt 0 ]; do
case "$1" in
--config)
CONFIG_PATH="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
--help)
usage
;;
*)
log_err "Unknown option: $1"
exit 1
;;
esac
done
while [ $# -gt 0 ]; do
case "$1" in
--config)
if [ $# -lt 2 ]; then
log_err "--config requires a path argument"
exit 1
fi
CONFIG_PATH="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
--help)
usage
;;
*)
log_err "Unknown option: $1"
exit 1
;;
esac
done
🤖 Prompt for AI Agents
In `@adapters/config/generate-config.sh` around lines 57 - 75, The --config
handling in generate-config.sh assumes $2 exists and will fail under set -u if
--config is the last arg; before assigning CONFIG_PATH="$2" in the case branch
for --config, add a guard to verify a next argument exists and is not another
option (check that $# -ge 2 and that $2 does not start with '-') and if the
check fails call usage or log_err and exit; update the --config case around the
assignment to CONFIG_PATH and the shift 2 to only run after the validation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant