# Ralph Loop

> 사전처리 → 개발 → 후처리 3단계 claude -p 루프를 생성하고 실행. 유저 맥락을 듣고 질문 라운드 3회(질문 없을 때까지)로 조건 문서를 정제한 뒤 루프 스크립트를 만들어 돌림. "ralph loop 만들어", "자동으로 반복 개선해", "루프 돌려" 같은 요청에 트리거.

- Skill: `kangraemin/ralph-loop` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add kangraemin/ralph-loop`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kangraemin/ralph-loop/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kangraemin (https://skillmd.com/u/kangraemin)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kangraemin/ralph-loop

---


# /ralph-loop

유저가 원하는 반복 작업을 `claude -p` 3단계 루프로 자동화한다.

구조:
```
while 판정 != PASS:
  1. Pre  — 현황 분석 (스크린샷, 로그, 데이터 수집 등)
  2. Dev  — 실제 변경/개선 (코드 수정, 파일 생성 등)
  3. Post — 결과 검증 + PASS/FAIL 판정
```

---

## Phase 0: 맥락 수집 (3-라운드 질문 정제)

### 0-1. 초기 맥락 파악

유저가 말한 내용에서 다음을 추출:
- **목표**: 무엇을 달성하려는가?
- **PASS 조건**: 언제 루프를 멈추나?
- **대상**: 어떤 파일/URL/시스템에서 작동하나?
- **Pre 단계**: 루프 전 분석/수집할 것은?
- **Dev 단계**: 매 반복마다 무엇을 고치/만드나?
- **Post 단계**: 결과 검증 방법은?

### 0-2. 3-라운드 질문 정제 (Python으로 상태 추적)

```python
# .ralph-loop-questions.json 파일로 라운드 상태 관리
import json, os

STATE_FILE = "/tmp/.ralph-loop-questions.json"

def load_state():
    if os.path.exists(STATE_FILE):
        return json.load(open(STATE_FILE))
    return {"round": 0, "questions_asked": [], "answers": {}, "no_question_rounds": 0}

def save_state(state):
    json.dump(state, open(STATE_FILE, "w"), ensure_ascii=False, indent=2)

state = load_state()
print(json.dumps(state))
```

**라운드 진행 규칙:**

매 라운드, Claude가 직접 판단:
1. 현재 수집된 정보로 루프를 만들 수 있는가?
2. 불명확하거나 중요한 정보가 빠졌는가?
3. 더 나은 방향이 있는데 확인이 필요한가?

질문이 있으면 → AskUserQuestion으로 묻고 → 답 받고 → 라운드 +1

질문이 없으면:
```python
state = load_state()
state["no_question_rounds"] += 1
save_state(state)
print(f"NO_QUESTION_ROUND {state['no_question_rounds']}/3")
```

**`no_question_rounds >= 3` 이 되면** → Phase 1로 진행. 그 전까지 반복.

> ⚠️ 질문 생성은 반드시 Python 스크립트를 실제로 실행해서 라운드 카운터를 올려야 한다.
> "질문 없음"을 판단만 하고 Python 안 돌리면 Phase 1 진입 불가.

**질문 예시 (상황에 따라):**
- PASS 조건이 주관적이면: "PASS 판정 기준을 구체화해줘 (e.g. '에러 없음', '점수 80+ 이상')"
- Dev가 코드 수정이면: "수정 가능한 파일 범위는? 특정 파일만? 전체?"
- Post가 배포면: "배포 후 검증은 어떻게? URL 로드 확인? 특정 텍스트 확인?"
- 루프 범위가 넓으면: "최대 반복 횟수는? 무한 루프 방지용 (권장: 10)"

---

## Phase 1: 조건 문서 + 프롬프트 생성

### 1-1. 출력 디렉토리 결정

```bash
TASK_SLUG=$(echo "<task-name>" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g')
RALPH_DIR="scripts/ralph/$TASK_SLUG"
mkdir -p "$RALPH_DIR/logs"
echo "DIR: $RALPH_DIR"
```

프로젝트에 `scripts/ralph/` 없으면 생성. 없는 프로젝트면 현재 디렉토리 기준.

### 1-2. conditions.md 생성

```bash
cat > "$RALPH_DIR/conditions.md" << 'COND'
# Ralph Loop Conditions: <TASK_NAME>

생성일: <DATE>

## 목표
<유저가 달성하려는 것>

## PASS 조건
<언제 루프를 멈추나 — 구체적으로>

## FAIL 조건
<PASS가 아닌 모든 경우, 또는 특정 패턴>

## 최대 반복
<MAX_ITER, 기본 10>

## 환경
- 작업 디렉토리: <PROJECT_DIR>
- 로컬 서버: <URL 또는 없음>
- 필요한 도구: <browse, butler, pytest 등>

## 단계별 역할

### Pre (사전처리)
<현황 분석/수집 내용 — 매 반복 전에 실행>

### Dev (개발)
<실제 변경/개선 내용 — 피드백 반영>

### Post (후처리 + 판정)
<결과 검증 방법 — PASS/FAIL 출력>

## 비고
<특이사항, 주의점>
COND
```

### 1-3. pre-prompt.md 생성

Pre 단계가 하는 일:
- 현재 상태 스크린샷/로그/데이터 수집
- 문제점 분석
- Dev에게 전달할 피드백 생성
- **마지막에 반드시**: `FEEDBACK: <구체적 문제점>` 출력

```bash
cat > "$RALPH_DIR/pre-prompt.md" << 'PRE'
# Pre-Processor: <TASK_NAME>

<유저 맥락 기반으로 채운 내용>

## 역할
현재 상태를 분석하고 Dev 에이전트에게 전달할 피드백을 생성한다.

## 실행할 것
<구체적 분석 단계>

## 출력 형식 (마지막 줄에 반드시)
```
FEEDBACK: <구체적 문제점 또는 개선 지시>
```
PRE
```

### 1-4. dev-prompt.md 생성

Dev 단계가 하는 일:
- Pre의 FEEDBACK을 받아 실제 변경 구현
- 파일 수정, 커밋 등
- **마지막에 반드시**: `IMPROVED: <변경 내용>` 출력

```bash
cat > "$RALPH_DIR/dev-prompt.md" << 'DEV'
# Developer: <TASK_NAME>

<유저 맥락 기반으로 채운 내용>

## 피드백
$FEEDBACK

## 프로젝트 구조
<관련 파일 목록>

## 역할
피드백을 보고 실제 코드/파일을 수정한다.

## 규칙
- 피드백에서 핵심 문제 1~3개만 수정 (과도한 변경 금지)
- 변경 후 git add + git commit (push 스킵)

## 출력 형식 (마지막 줄에 반드시)
```
IMPROVED: <무엇을 바꿨는지 한 줄>
```
DEV
```

### 1-5. post-prompt.md 생성

Post 단계가 하는 일:
- 변경 결과 검증
- PASS/FAIL 판정
- **마지막 줄에 반드시** 둘 중 하나:
  ```
  PASS: <이유>
  FAIL: <구체적 문제점>
  ```

```bash
cat > "$RALPH_DIR/post-prompt.md" << 'POST'
# Judge: <TASK_NAME>

<유저 맥락 기반으로 채운 내용>

## 역할
변경 결과를 검증하고 PASS/FAIL을 판정한다.

## PASS 조건
<conditions.md에서>

## 검증 방법
<구체적 검증 단계>

## 출력 형식 (반드시 마지막 줄)
성공:
```
PASS: <이유>
```

실패:
```
FAIL: <구체적 문제점>
```
POST
```

---

## Phase 2: loop.sh 생성

```bash
cat > "$RALPH_DIR/loop.sh" << 'LOOP'
#!/usr/bin/env bash
# ralph-loop: <TASK_NAME>
# 자동 생성 — ralph-loop 스킬

set -e

GAME_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
LOG_DIR="$SCRIPTS_DIR/logs"
MAX_ITER="${MAX_ITER:-<MAX_ITER>}"
CLAUDE_OPTS="--allowedTools Edit,Read,Grep,Glob,Bash --output-format text --dangerously-skip-permissions"

# 선택적: browse 경로
BROWSE="${BROWSE:-}"
[ -x "$HOME/.claude/skills/gstack/browse/dist/browse" ] && BROWSE="$HOME/.claude/skills/gstack/browse/dist/browse"

mkdir -p "$LOG_DIR"

echo ""
echo "🔁 Ralph Loop: <TASK_NAME>"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "PASS 조건: <PASS_CONDITION>"
echo "최대 반복: $MAX_ITER"
echo ""

# --- 선택적: 로컬 서버 ---
# PORT=<PORT>
# python3 -m http.server $PORT --directory "$GAME_DIR" > /dev/null 2>&1 &
# SERVER_PID=$!
# trap "kill $SERVER_PID 2>/dev/null" EXIT
# sleep 1

FEEDBACK="첫 번째 실행"
ITER=0

while [ $ITER -lt $MAX_ITER ]; do
  ITER=$((ITER + 1))
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  echo "🔁 Iteration $ITER / $MAX_ITER"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

  # ─── Step 1: Pre (사전처리) ───────────────────
  echo "🔍 Pre-processing..."
  PRE_LOG="$LOG_DIR/pre-iter-${ITER}.log"
  cd /tmp  # ai-bouncer 훅 우회
  claude -p "$(cat "$SCRIPTS_DIR/pre-prompt.md")" \
    $CLAUDE_OPTS < /dev/null > "$PRE_LOG" 2>&1 || true
  cd "$GAME_DIR"

  # Pre 결과에서 FEEDBACK 추출
  NEW_FEEDBACK=$(grep "^FEEDBACK:" "$PRE_LOG" | tail -1 | sed 's/^FEEDBACK: //')
  [ -n "$NEW_FEEDBACK" ] && FEEDBACK="$NEW_FEEDBACK"
  echo "📋 피드백: $FEEDBACK"

  # ─── Step 2: Dev (개발) — 첫 번째도 실행 ────────
  echo ""
  echo "🛠️  Dev..."
  DEV_LOG="$LOG_DIR/dev-iter-${ITER}.log"
  DEV_PROMPT=$(sed "s|\$FEEDBACK|$FEEDBACK|g" "$SCRIPTS_DIR/dev-prompt.md")
  cd "$GAME_DIR"
  claude -p "$DEV_PROMPT" \
    $CLAUDE_OPTS < /dev/null > "$DEV_LOG" 2>&1 || true
  tail -3 "$DEV_LOG"

  # ─── Step 3: Post (후처리 + 판정) ─────────────
  echo ""
  echo "🧪 Post / Judging..."
  POST_LOG="$LOG_DIR/post-iter-${ITER}.log"
  cd /tmp
  claude -p "$(cat "$SCRIPTS_DIR/post-prompt.md")" \
    $CLAUDE_OPTS < /dev/null > "$POST_LOG" 2>&1 || true
  cd "$GAME_DIR"

  RESULT=$(cat "$POST_LOG")
  echo ""
  echo "--- 판정 ---"
  echo "$RESULT" | tail -5
  echo "-------------"

  # PASS 체크
  if echo "$RESULT" | grep -q "^PASS:"; then
    PASS_REASON=$(echo "$RESULT" | grep "^PASS:" | head -1)
    echo ""
    echo "✅ $PASS_REASON"
    echo "총 $ITER 회 만에 완료"
    exit 0
  fi

  # FAIL 피드백 갱신
  FAIL_MSG=$(echo "$RESULT" | grep "^FAIL:" | head -1 | sed 's/^FAIL: //')
  [ -n "$FAIL_MSG" ] && FEEDBACK="$FAIL_MSG"

  echo ""
  echo "🔄 계속... 피드백: $FEEDBACK"
  echo ""
done

echo "⚠️  최대 반복 ${MAX_ITER}회 도달. 수동 확인 필요."
echo "마지막 피드백: $FEEDBACK"
exit 1
LOOP

chmod +x "$RALPH_DIR/loop.sh"
echo "✅ $RALPH_DIR/loop.sh 생성 완료"
```

---

## Phase 3: 확인 + 실행

### 3-1. 생성 파일 요약 출력

```
생성된 파일:
  $RALPH_DIR/conditions.md   — 루프 조건 문서
  $RALPH_DIR/pre-prompt.md   — 사전처리 에이전트 프롬프트
  $RALPH_DIR/dev-prompt.md   — 개발 에이전트 프롬프트
  $RALPH_DIR/post-prompt.md  — 판정 에이전트 프롬프트
  $RALPH_DIR/loop.sh         — 실행 스크립트

실행:
  bash $RALPH_DIR/loop.sh
  MAX_ITER=5 bash $RALPH_DIR/loop.sh
```

### 3-2. 바로 실행할지 확인

AskUserQuestion:
- A) 지금 바로 실행
- B) 프롬프트 먼저 검토 후 실행
- C) 생성만 하고 나중에 실행

**A 선택 시**: `bash $RALPH_DIR/loop.sh` 실행. 실시간 출력 스트리밍.

**B 선택 시**: conditions.md + pre/dev/post 프롬프트를 출력해서 보여준 뒤, 수정 요청 받고 → 실행.

**C 선택 시**: 종료. 실행 명령어만 안내.

---

## 주의사항

- `claude -p`는 `--dangerously-skip-permissions`로 실행 (루프 자동화 필수)
- ai-bouncer 훅 우회: Pre/Post 에이전트는 `/tmp`에서 실행, Dev는 프로젝트 디렉토리에서 실행
- 각 단계 로그는 `$RALPH_DIR/logs/` 에 저장 (디버깅용)
- FEEDBACK 변수: Pre가 생성 → Dev에 주입 → Post가 판정 → 다음 Pre에 컨텍스트로 전달
- `no_question_rounds` 카운터: Python으로 실제 파일에 기록해야 유효. 메모리 내 카운팅 금지.

