$npx -y skills add witt3rd/oh-my-hermes --skill omh-ralphexecute plan: 1 task/call, verify evidence, iron law
| 1 | # OMH Ralph — Verified Execution (v2) |
| 2 | |
| 3 | > **Requires the OMH plugin.** Install `plugins/omh/` from this repo to |
| 4 | > `~/.hermes/plugins/omh/`. |
| 5 | |
| 6 | ## When to Use |
| 7 | |
| 8 | - You have a plan (from omh-ralplan or manual) and need verified execution |
| 9 | - The user says: "ralph", "don't stop", "until done", "must complete", "keep going" |
| 10 | - You need guaranteed verification — not just "looks done" but evidence-backed completion |
| 11 | - Multi-step implementation where each task must be independently verified |
| 12 | |
| 13 | ## When NOT to Use |
| 14 | |
| 15 | - No plan or spec exists (use omh-deep-interview and/or omh-ralplan first) |
| 16 | - Trivial single-file changes (just do them directly) |
| 17 | - The user explicitly wants to skip verification |
| 18 | |
| 19 | ## Architecture: One Task Per Invocation |
| 20 | |
| 21 | Each ralph invocation does ONE unit of work and exits. The caller re-invokes for |
| 22 | the next task. This eliminates context window exhaustion and makes every invocation |
| 23 | a clean checkpoint. |
| 24 | |
| 25 | ``` |
| 26 | Invocation N: read state → pick task → execute → verify → update state → EXIT |
| 27 | Invocation N+1: read state → pick next task → execute → verify → update state → EXIT |
| 28 | ... |
| 29 | Final invocation: all tasks pass → architect review → mark complete → EXIT |
| 30 | ``` |
| 31 | |
| 32 | ## Procedure |
| 33 | |
| 34 | ### Step 0: Resolve Instance and Acquire Lock |
| 35 | |
| 36 | Ralph and autopilot mutate a shared `.omh/plans/` plan. Two sessions |
| 37 | running ralph against the same plan would race on `ralph-tasks` state |
| 38 | and produce non-deterministic outcomes. Use per-instance state + |
| 39 | advisory lock to make concurrent plans safe. |
| 40 | |
| 41 | 1. **Resolve `instance_id`** from the plan path: |
| 42 | - Default plan source: `.omh/plans/ralplan-*.md` or `.omh/plans/ralph-plan.md`. |
| 43 | - `instance_id = basename(plan_path) without ".md"` (engine slugifies). |
| 44 | - If no plan exists yet (Step 2 will choose), use `instance_id="default"`. |
| 45 | 2. **Acquire the lock** before reading/writing state: |
| 46 | ``` |
| 47 | lock = omh_state(action="lock", mode="ralph", |
| 48 | lock_key="{instance_id}", |
| 49 | session_id="{HERMES_SESSION_ID or uuid}", |
| 50 | holder_note="ralph executing {plan_path}") |
| 51 | ``` |
| 52 | - `acquired=true`: continue. |
| 53 | - `acquired=false`: report `held_by` to the user (pid + session_id + |
| 54 | started_at). Offer: wait / cancel the holder |
| 55 | (`omh_state(action="cancel", mode="ralph", instance_id="{instance_id}")`, |
| 56 | then on next invocation the dead holder's lock will be released |
| 57 | automatically by stale-pid detection) / pick a different plan. |
| 58 | 3. **Pass `instance_id` to every subsequent `omh_state` call in this |
| 59 | invocation** — both the `ralph` mode and the `ralph-tasks` mode. |
| 60 | 4. **Release the lock at every exit point** (success, blocked, cancel, |
| 61 | max-iterations, exception): |
| 62 | ``` |
| 63 | omh_state(action="unlock", mode="ralph", |
| 64 | lock_key="{instance_id}", |
| 65 | session_id="{HERMES_SESSION_ID or uuid}") |
| 66 | ``` |
| 67 | Wrap the body of the procedure so the unlock fires even on error. |
| 68 | |
| 69 | > **Singleton fallback (legacy).** If a caller omits `instance_id`, |
| 70 | > the engine writes the legacy `.omh/state/ralph-state.json` and skips |
| 71 | > locking. Only use this for one-plan-at-a-time setups. |
| 72 | |
| 73 | ### Step 1: Read State |
| 74 | |
| 75 | ``` |
| 76 | state = omh_state(action="read", mode="ralph", instance_id="{instance_id}") |
| 77 | ``` |
| 78 | |
| 79 | - **`state.exists=false`**: Fresh start — go to Step 2 (Planning Gate). |
| 80 | - **`state.data.active=true`**: Resume — go to Step 3. |
| 81 | - **`state.data.phase="complete"`**: Report completion. Ask if user wants fresh start. |
| 82 | - **`state.data.phase="blocked"`**: Report blockers. Ask if issues are resolved. |
| 83 | - **`state.data.active=false`, `phase="cancelled"`**: Report cancellation. Offer resume. |
| 84 | |
| 85 | Check for cancel signal: |
| 86 | ``` |
| 87 | cancel = omh_state(action="cancel_check", mode="ralph", instance_id="{instance_id}") |
| 88 | ``` |
| 89 | If `cancel.cancelled=true`: set phase="cancelled", write state, exit. |
| 90 | |
| 91 | Check staleness: if `state.stale=true`, warn the user and offer to continue or fresh start. |
| 92 | |
| 93 | Increment `state.data.iteration`. If `iteration > max_iterations` (default 100): |
| 94 | write `phase="blocked"`, report "Max iterations reached", exit. |
| 95 | |
| 96 | ### Step 2: Planning Gate |
| 97 | |
| 98 | Ralph MUST NOT execute without a plan. Check sources in order: |
| 99 | |
| 100 | 1. `omh_state(action="check", mode="ralph-tasks", instance_id="{instance_id}")` → `exists=true` — already parsed, skip to Step 3 |
| 101 | 2. `.omh/plans/ralplan-*.md` — parse into ralph-tasks state: `omh_state(action="write", mode="ralph-tasks", instance_id="{instance_id}", data={...})` |
| 102 | 3. `.omh/plans/ralph-plan.md` — parse into ralph-tasks state |
| 103 | 4. Nothing found → tell user: "No plan found. Run `omh-ralplan` first." |
| 104 | |
| 105 | **Plan parsing rules:** |
| 106 | - Extract numbered tasks with titles, descriptions, and acceptance criteria |
| 107 | - Reject generic criteria like "implementation is complete" — must be testable |
| 108 | - Enforce atomicity: split multi-part tasks into separate entries |
| 109 | - Assign |