Ctrl K
ComunidadGuías…

ralph.sh

Rama dev · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/bin/bash
# RALPH Loop Runner - Claude Code Edition (with Flight Recorder)
#
# Usage:
#   ./ralph.sh                               # Run (5 iterations default)
#   ./ralph.sh 10                            # Run 10 iterations
#   ./ralph.sh --model <m>                   # Run with model override
#   ./ralph.sh --postmortem-model <m>        # Different model for postmortem
#   ./ralph.sh --review-interval 3           # Run adversarial review every 3 iterations
#   ./ralph.sh --model <m> 10
#   RALPH_MODEL=claude-sonnet-4-20250514 ./ralph.sh
#   Postmortem runs automatically after the loop.
#
# Each iteration is a FRESH Claude context window.
# Progress lives in files + git + .ralph flight recorder logs.

set -euo pipefail

# Ensure Ctrl+C kills the whole loop, not just the current child process.
# Without this, claude catches SIGINT and exits 0, so the `if !` block
# doesn't fire and the loop continues to the next iteration.
trap 'echo ""; echo "RALPH loop interrupted."; exit 130' INT TERM

PLAN_FILE="IMPLEMENTATION_PLAN.md"
ITERATIONS=5
MODEL="${RALPH_MODEL:-claude-opus-4-6}"
POSTMORTEM_MODEL="${RALPH_POSTMORTEM_MODEL:-$MODEL}"
REVIEW_INTERVAL="${RALPH_REVIEW_INTERVAL:-0}"  # 0 = disabled
L3_GATE_ENABLED="${RALPH_L3_GATE:-true}"       # Block commits without L3 evidence
L3_GATE_BYPASS=false

# --- arg parsing (allow: [--model X] [--review-interval N] [iterations]) ---
while [[ $# -gt 0 ]]; do
  case "$1" in
    --model|-m)
      if [[ $# -lt 2 ]]; then
        echo "Missing value for $1"
        echo "Usage: $0 [--model <model>] [--postmortem-model <model>] [--review-interval N] [iterations]"
        exit 1
      fi
      MODEL="$2"
      POSTMORTEM_MODEL="${RALPH_POSTMORTEM_MODEL:-$MODEL}"
      shift 2
      ;;
    --postmortem-model)
      if [[ $# -lt 2 ]]; then
        echo "Missing value for $1"
        echo "Usage: $0 [--model <model>] [--postmortem-model <model>] [--review-interval N] [iterations]"
        exit 1
      fi
      POSTMORTEM_MODEL="$2"
      shift 2
      ;;
    --review-interval)
      if [[ $# -lt 2 ]]; then
        echo "Missing value for $1"
        echo "Usage: $0 [--model <model>] [--postmortem-model <model>] [--review-interval N] [--skip-l3-gate] [iterations]"
        exit 1
      fi
      REVIEW_INTERVAL="$2"
      shift 2
      ;;
    --skip-l3-gate)
      L3_GATE_BYPASS=true
      shift
      ;;
    *)
      # if it's a number, treat as iterations
      if [[ "$1" =~ ^[0-9]+$ ]]; then
        ITERATIONS="$1"
        shift
      else
        echo "Unknown arg: $1"
        echo "Usage: $0 [--model <model>] [--postmortem-model <model>] [--review-interval N] [--skip-l3-gate] [iterations]"
        exit 1
      fi
      ;;
  esac
done

# Check if claude is installed
if ! command -v claude &> /dev/null; then
  echo "Error: claude is not installed or not in PATH"
  exit 1
fi

# Run ID and log directory
RUN_ID="${RUN_ID:-$(date +%Y%m%d-%H%M%S)}"
RUN_DIR=".ralph/runs/${RUN_ID}"
mkdir -p "$RUN_DIR"

echo "=========================================="
echo "  RALPH Loop (Claude Code)"
echo "  Model: $MODEL"
echo "  Postmortem Model: $POSTMORTEM_MODEL"
echo "  Review Interval: $REVIEW_INTERVAL (0=disabled)"
echo "  L3 Gate: $L3_GATE_ENABLED (bypass=$L3_GATE_BYPASS)"
echo "  Iterations: $ITERATIONS"
echo "  Mode: AUTONOMOUS (permissions skipped)"
echo "  Run ID: $RUN_ID"
echo "  Run Dir: $RUN_DIR"
echo "=========================================="
echo ""
echo "WARNING: Running with --dangerously-skip-permissions"
echo "Press Ctrl+C within 3 seconds to abort..."
sleep 3
echo ""

# Ensure we're on the right branch
BRANCH=$(git branch --show-current)
echo "Current branch: $BRANCH"

if [[ "$BRANCH" == "dev" || "$BRANCH" == "main" || "$BRANCH" == "master" ]]; then
  NEW_BRANCH="ralph/claude-${RUN_ID}"
  echo "On protected branch, creating feature branch: $NEW_BRANCH"
  git checkout -b "$NEW_BRANCH"
  BRANCH=$(git branch --show-current)
  echo "Now on: $BRANCH"
fi
echo ""

START_COMMIT=$(git rev-parse HEAD)
LAST_REVIEW_COMMIT="$START_COMMIT"
{
  echo "Run ID: $RUN_ID"
  echo "Branch: $BRANCH"
  echo "Model: $MODEL"
  echo "Postmortem model: $POSTMORTEM_MODEL"
  echo "Review interval: $REVIEW_INTERVAL"
  echo "Run start commit: $START_COMMIT"
  echo "Started: $(date)"
  echo ""
} | tee "$RUN_DIR/run.md" >/dev/null

# Function to run mid-loop adversarial review
run_mid_review() {
  local iteration=$1
  local current_commit
  current_commit=$(git rev-parse HEAD)

  echo ""
  echo "=========================================="
  echo "  Mid-Loop Adversarial Review (after iteration $iteration)"
  echo "  Reviewing commits: ${LAST_REVIEW_COMMIT}..${current_commit}"
  echo "=========================================="
  echo ""

  local review_log="${RUN_DIR}/review-after-iter-$(printf "%02d" "$iteration").md"

  # Find prior review files for cumulative context
  local prior_reviews=""
  for f in "$RUN_DIR"/review-after-iter-*.md; do
    [[ -f "$f" ]] && prior_reviews="$prior_reviews\n- $f"
  done

  if ! claude --dangerously-skip-permissions --model "$POSTMORTEM_MODEL" -p "Run a full adversarial review using the adversarial review skill.

## Context
- RUN_ID: $RUN_ID
- RUN_DIR: $RUN_DIR
- Iteration just completed: $iteration
- Commit range to review: ${LAST_REVIEW_COMMIT}..${current_commit}
- Review log to write: $review_log
- Prior review files (read these FIRST for cumulative context):
${prior_reviews:-  (none — this is the first review)}

## Instructions

1. **REQUIRED:** Load .claude/skills/ralph-output-adversarial-review.md and execute the FULL review protocol.
   This is NOT optional. Do not perform a lightweight review.

2. **Cumulative review protocol:**
   - Read ALL prior review files listed above
   - For each prior review's open issues: check if resolved in commits since that review
   - If resolved: note resolution with commit hash
   - If NOT resolved: carry forward as open issue in THIS review
   - If a prior review missed something you now see: add it as a NEW finding

3. **Full review areas (from skill):**
   - A) Checkbox Integrity — do changes satisfy Done-when criteria?
   - B) Testing Strategy Compliance — integration tests for I/O, screenshots for UI
   - C) Architecture Compliance — follow constraints from AGENTS.md/CLAUDE.md
   - D) Framework compliance per CLAUDE.md
   - E) UI Sanity — error states, loading states, runtime errors
   - E2) UI Screenshot Gate — UI files must have L3+ with screenshots
   - F) Regression Risk — edge cases, N+1 queries, unsafe assumptions
   - G) Slopwatch — reward hacking patterns
   - H-K) Duplication, useless tests, L3 evidence audit, L3+ artifact verification

4. **Write findings to: $review_log** using the skill's deliverable format for mid-loop reviews.

5. **Write actionable items:**
   - NOW items: insert at top of IMPLEMENTATION_PLAN.md
   - PARK items: append to BACKLOG_PARKING_LOT.md
   - Every finding MUST have a disposition (NOW, PARK, or FIX INLINE)

6. **Process improvement authority (additive only):**
   - If you identify a recurring pattern that should be a skill: create it in .claude/skills/
   - If you identify a gap in ralph-loop.md or testing-strategy.md: add the missing check/gate
   - You may ONLY add rules, never remove or weaken existing ones
   - You may NOT edit CLAUDE.md (constitution requires human approval)
   - Log all process edits under '## Process Improvements Applied' in the review file

7. **Verdict:**
   - Output 'VERDICT: FAIL' if hard fail criteria met (pauses the loop)
   - Output 'VERDICT: PARTIAL' if issues found but not blocking
   - Output 'VERDICT: PASS' if clean
"; then
    echo "Mid-loop review failed to execute"
    return 1
  fi

  # Check if the review log contains FAIL verdict
  if [[ -f "$review_log" ]] && grep -q "VERDICT: FAIL" "$review_log"; then
    echo ""
    echo "=========================================="
    echo "  ADVERSARIAL REVIEW FAILED"
    echo "  Review found issues requiring human attention."
    echo "  See: $review_log"
    echo "=========================================="
    return 1
  fi

  # Update last review commit
  LAST_REVIEW_COMMIT="$current_commit"
  echo "Mid-loop review passed, continuing..."
  echo ""
  return 0
}

# Function to verify L3 evidence if L3 was claimed
verify_l3_evidence() {
  local iter_log=$1

  # Skip if gate disabled or bypassed
  if [[ "$L3_GATE_ENABLED" != "true" ]] || [[ "$L3_GATE_BYPASS" == "true" ]]; then
    return 0
  fi

  # Check if iteration claimed L3 verification level
  if ! grep -q "Level: L3\|Level: L4" "$iter_log" 2>/dev/null; then
    # Not an L3/L4 task, no gate needed
    return 0
  fi

  echo ""
  echo "  L3/L4 Verification Gate"
  echo "  Checking for required evidence in: $iter_log"

  local missing_evidence=()

  # Check for application running evidence
  if ! grep -qi "aspire run\|dotnet run\|npm start\|yarn dev\|Application Started\|resources healthy\|Server started\|listening on" "$iter_log" 2>/dev/null; then
    missing_evidence+=("Application running (start command with evidence)")
  fi

  # Check for routes checked evidence
  if ! grep -qi "Routes Checked\|Routes checked\|Route.*200\|Route.*rendered" "$iter_log" 2>/dev/null; then
    missing_evidence+=("Routes navigated (Routes Checked section)")
  fi

  # Check for console errors evidence
  if ! grep -qi "Console errors: none\|Console errors:.*none\|no console errors" "$iter_log" 2>/dev/null; then
    # Also check if they documented errors (which is valid if they then fix them)
    if ! grep -qi "Console errors:" "$iter_log" 2>/dev/null; then
      missing_evidence+=("Console errors checked (Console errors: none)")
    fi
  fi

  # Check for viewport evidence
  if ! grep -qi "Viewport.*pass\|viewport check\|1024.*1280.*1920\|1024px\|viewport sanity" "$iter_log" 2>/dev/null; then
    missing_evidence+=("Viewport sanity check (1024/1280/1920)")
  fi

  if [[ ${#missing_evidence[@]} -gt 0 ]]; then
    echo ""
    echo "  ==========================================="
    echo "  L3 VERIFICATION GATE FAILED"
    echo "  ==========================================="
    echo ""
    echo "  The iteration claimed L3/L4 verification level but is missing required evidence:"
    echo ""
    for item in "${missing_evidence[@]}"; do
      echo "    - $item"
    done
    echo ""
    echo "  Per ralph-loop.md L3 Verification Checklist, these are MANDATORY when claiming L3."
    echo ""
    echo "  Options:"
    echo "    1. Fix the iteration to include proper L3 evidence"
    echo "    2. Downgrade to L2 with documented justification"
    echo "    3. Re-run with --skip-l3-gate (emergency bypass)"
    echo ""
    return 1
  fi

  echo "  L3 evidence verified: PASS"
  return 0
}

# Loop - each iteration is a fresh Claude context
for ((i=1; i<=ITERATIONS; i++)); do
  echo "=========================================="
  echo "  RALPH Iteration $i of $ITERATIONS"
  echo "  $(date)"
  echo "=========================================="
  echo ""

  # Check if there are any unchecked items
  if [[ ! -f "$PLAN_FILE" ]]; then
    echo "Missing required plan file: $PLAN_FILE"
    exit 1
  fi
  if ! grep -q '\- \[ \]' "$PLAN_FILE"; then
    echo "No unchecked items remaining in $PLAN_FILE"
    echo "RALPH loop complete!"
    break
  fi

  ITER_PAD=$(printf "%02d" "$i")
  ITER_LOG="${RUN_DIR}/iter-${ITER_PAD}.md"

  if ! claude --dangerously-skip-permissions --model "$MODEL" -p "You are running RALPH iteration $i.

## Run Metadata (MUST USE)
- RUN_ID: $RUN_ID
- RUN_DIR: $RUN_DIR
- ITERATION: $i
- ITER_LOG (write this file before commit): $ITER_LOG

## Bootstrap (Read these files FIRST)
1. AGENTS.md and/or CLAUDE.md - Constitution (authority, constraints, quality bar, routing)
2. PROJECT_CONTEXT.md - Current architecture and state (if present)
3. TOOLING.md - Available tools/services (if present)
4. IMPLEMENTATION_PLAN.md - Task breakdown

## Instructions (ONE TASK ONLY)

1) Find the next incomplete task in IMPLEMENTATION_PLAN.md:
   - Look for '### Task:' blocks with unchecked 'Done when:' items
   - Work on the FIRST incomplete task you find
   - A task is complete only when ALL its Done-when checkboxes are satisfied

2) Determine MODE from Task Routing in AGENTS.md/CLAUDE.md (engineering/ux/marketing/ops/etc.)

3) Load relevant skills from .claude/skills/:
   - REQUIRED for code: testing-strategy.md (if present — integration vs unit; no fakes)
   - REQUIRED: ralph-loop.md (process discipline)
   - If UI impacted: ui-smoke-validation.md (or follow UI validation policy)
   - If schema/events touched: extend-only-design.md (if present)

4) BEFORE coding: choose Verification Level (L0-L4) and state why:
   - I/O coordination (DB/HTTP/actors/external) => L2+ (integration tests required)
   - UI or UI dependency changed => L3+ (UI smoke / Playwright required)

5) Implement to satisfy ALL unchecked Done-when criteria for the chosen task.

6) Verify (must match chosen level):
   - Minimum: build + test (language-appropriate commands)
   - If Level >= L3: run UI smoke/Playwright and check for console errors
   - Follow any additional quality gates from AGENTS.md/CLAUDE.md

7) FLIGHT RECORDER (MANDATORY):
   - Write $ITER_LOG BEFORE committing.
   - Include:
     - Task selected (exact title)
     - Surface area classification
     - Verification level chosen + reason
     - Skills consulted
     - Commands run + outcomes
     - Deviations/skips + justification
     - Follow-ups noticed but deferred + why
   - If you claim a command was run, it must appear in the log with outcome.
   - 'Log or it didn't happen.'

8) If verification passes:
   - Commit to the current feature branch with a descriptive message
   - Update IMPLEMENTATION_PLAN.md checkboxes in the SAME commit
   - Update TOOLING.md if you used or discovered a new tool/resource

9) Stop at checkpoints (UI approval, architecture decisions, credential setup) and ask the user if needed.

10) Exit - do NOT continue to additional tasks.

## Constraints (Constitution)
- ONE iteration = ONE task block
- Never commit to dev/main/master
- Follow constraints from AGENTS.md/CLAUDE.md
- Test against real infrastructure (per testing-strategy)
"; then
    EXIT_CODE=$?
    echo ""
    echo "Claude exited with code $EXIT_CODE"
    echo "RALPH loop paused at iteration $i"
    exit $EXIT_CODE
  fi

  echo ""
  echo "Iteration $i complete"

  # Run L3 verification gate if L3 was claimed
  if ! verify_l3_evidence "$ITER_LOG"; then
    echo "RALPH loop paused due to L3 verification gate failure at iteration $i"
    echo "See iteration log for details: $ITER_LOG"
    exit 1
  fi

  echo ""

  # Run mid-loop adversarial review if interval is set and we've hit it
  if [[ "$REVIEW_INTERVAL" -gt 0 ]] && (( i % REVIEW_INTERVAL == 0 )) && (( i < ITERATIONS )); then
    if ! run_mid_review "$i"; then
      echo "RALPH loop paused due to adversarial review failure at iteration $i"
      echo "Review the findings and fix issues before continuing."
      exit 1
    fi
  fi

  sleep 2
done

END_COMMIT=$(git rev-parse HEAD)
{
  echo "Finished: $(date)"
  echo "Run end commit: $END_COMMIT"
  echo "Commit range: ${START_COMMIT}..${END_COMMIT}"
} | tee -a "$RUN_DIR/run.md" >/dev/null

echo "=========================================="
echo "  RALPH Loop Finished"
echo "  Run ID: $RUN_ID"
echo "  Branch: $(git branch --show-current)"
echo "  Logs: $RUN_DIR"
echo "  Commit range: ${START_COMMIT}..${END_COMMIT}"
echo "=========================================="

echo ""
echo "Remaining incomplete tasks:"
grep -B5 '^\- \[ \]' "$PLAN_FILE" | grep '### Task:' | head -5 || echo "(none or legacy format)"

echo ""
echo "Running postmortem (OpenProse): ralph-after-action"
if ! claude --dangerously-skip-permissions --model "$POSTMORTEM_MODEL" -p "/open-prose:prose-run @.prose/ralph-after-action.prose RUN_ID=$RUN_ID RUN_DIR=$RUN_DIR BRANCH=$(git branch --show-current)"; then
  POSTMORTEM_EXIT=$?
  echo ""
  echo "Postmortem exited with code $POSTMORTEM_EXIT"
  exit $POSTMORTEM_EXIT
fi
echo "Postmortem complete"
echo "Logs live at: $RUN_DIR"