| name | ralph-loop |
| description | 사전처리 → 개발 → 후처리 3단계 claude -p 루프를 생성하고 실행. 유저 맥락을 듣고
질문 라운드 3회(질문 없을 때까지)로 조건 문서를 정제한 뒤 루프 스크립트를 만들어 돌림.
"ralph loop 만들어", "자동으로 반복 개선해", "루프 돌려" 같은 요청에 트리거.
|
| allowed-tools | ["Bash","Read","Write","Edit","Glob","Grep","AskUserQuestion"] |
/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으로 상태 추적)
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가 직접 판단:
- 현재 수집된 정보로 루프를 만들 수 있는가?
- 불명확하거나 중요한 정보가 빠졌는가?
- 더 나은 방향이 있는데 확인이 필요한가?
질문이 있으면 → AskUserQuestion으로 묻고 → 답 받고 → 라운드 +1
질문이 없으면:
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. 출력 디렉토리 결정
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 생성
cat > "$RALPH_DIR/conditions.md" << 'COND'
생성일: <DATE>
<유저가 달성하려는 것>
<언제 루프를 멈추나 — 구체적으로>
<PASS가 아닌 모든 경우, 또는 특정 패턴>
<MAX_ITER, 기본 10>
- 작업 디렉토리: <PROJECT_DIR>
- 로컬 서버: <URL 또는 없음>
- 필요한 도구: <browse, butler, pytest 등>
<현황 분석/수집 내용 — 매 반복 전에 실행>
<실제 변경/개선 내용 — 피드백 반영>
<결과 검증 방법 — PASS/FAIL 출력>
<특이사항, 주의점>
COND
1-3. pre-prompt.md 생성
Pre 단계가 하는 일:
- 현재 상태 스크린샷/로그/데이터 수집
- 문제점 분석
- Dev에게 전달할 피드백 생성
- 마지막에 반드시:
FEEDBACK: <구체적 문제점> 출력
cat > "$RALPH_DIR/pre-prompt.md" << 'PRE'
<유저 맥락 기반으로 채운 내용>
현재 상태를 분석하고 Dev 에이전트에게 전달할 피드백을 생성한다.
<구체적 분석 단계>
FEEDBACK: <구체적 문제점 또는 개선 지시>
PRE
1-4. dev-prompt.md 생성
Dev 단계가 하는 일:
- Pre의 FEEDBACK을 받아 실제 변경 구현
- 파일 수정, 커밋 등
- 마지막에 반드시:
IMPROVED: <변경 내용> 출력
cat > "$RALPH_DIR/dev-prompt.md" << 'DEV'
<유저 맥락 기반으로 채운 내용>
$FEEDBACK
<관련 파일 목록>
피드백을 보고 실제 코드/파일을 수정한다.
- 피드백에서 핵심 문제 1~3개만 수정 (과도한 변경 금지)
- 변경 후 git add + git commit (push 스킵)
IMPROVED: <무엇을 바꿨는지 한 줄>
DEV
1-5. post-prompt.md 생성
Post 단계가 하는 일:
cat > "$RALPH_DIR/post-prompt.md" << 'POST'
<유저 맥락 기반으로 채운 내용>
변경 결과를 검증하고 PASS/FAIL을 판정한다.
<conditions.md에서>
<구체적 검증 단계>
성공:
PASS: <이유>
실패:
FAIL: <구체적 문제점>
POST
Phase 2: loop.sh 생성
cat > "$RALPH_DIR/loop.sh" << '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:-}"
[ -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 ""
FEEDBACK="첫 번째 실행"
ITER=0
while [ $ITER -lt $MAX_ITER ]; do
ITER=$((ITER + 1))
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔁 Iteration $ITER / $MAX_ITER"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔍 Pre-processing..."
PRE_LOG="$LOG_DIR/pre-iter-${ITER}.log"
cd /tmp
claude -p "$(cat "$SCRIPTS_DIR/pre-prompt.md")" \
$CLAUDE_OPTS < /dev/null > "$PRE_LOG" 2>&1 || true
cd "$GAME_DIR"
NEW_FEEDBACK=$(grep "^FEEDBACK:" "$PRE_LOG" | tail -1 | sed 's/^FEEDBACK: //')
[ -n "$NEW_FEEDBACK" ] && FEEDBACK="$NEW_FEEDBACK"
echo "📋 피드백: $FEEDBACK"
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"
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 "-------------"
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_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으로 실제 파일에 기록해야 유효. 메모리 내 카운팅 금지.