콘텐츠로 이동

Claude Code Ralph Loop 플러그인 완전 정리

Anthropic 공식 마켓플레이스에 등록된 ralph-loop 플러그인의 개념·사용법·내부 동작·함정·실전 가이드. 와인 도메인은 아니지만 이 레포의 리서치·자동화 워크플로(예: 수입사 카탈로그 크롤 → LWIN 매핑 → LLM 검수)에 적용 가능한 메타 도구라 위키에 정리한다.


  • Ralph Loop = “같은 프롬프트를 무한 반복해서 Claude에게 먹이는 기법”. 원조는 Geoffrey Huntley의 블로그 ghuntley.com/ralph에서 정의된 Ralph Wiggum 기법.
  • 핵심은 자기 참조(self-reference): 프롬프트는 안 바뀌지만, Claude가 매 iteration마다 자신이 이미 수정한 파일git history를 새로 읽고 다음 단계를 결정한다.
  • 공식 플러그인은 /ralph-loop "<task>" 한 줄로 현재 세션 안에서 루프를 가동한다. 세션을 빠져나가려 할 때마다 Stop hook이 가로채서 같은 프롬프트를 다시 주입한다.
  • 자동 종료 조건은 두 가지뿐: <promise>X</promise> 토큰 출력 감지, 또는 --max-iterations 도달. 둘 다 없으면 세션이 영구 루프에 빠진다.
  • 가장 큰 비판점: 원조 Ralph는 매 iteration마다 fresh session을 띄우는데, 공식 플러그인은 같은 컨텍스트 윈도우에 계속 쌓아 올리기 때문에 ~150k 토큰에서 auto-compact가 일어나 효과가 급락한다.

“Ralph는 Bash 루프다.” — Geoffrey Huntley

원조 Ralph는 본질적으로 다음 한 줄에 불과하다.

Terminal window
while :; do
cat PROMPT.md | claude-code --continue
done

이름은 심슨 가족 캐릭터 Ralph Wiggum 에서 따왔다. “넘어져도 일어서고, 같은 데서 또 넘어져도 일어선다”는 끈질김을 코딩 자동화 철학으로 옮긴 것.

단계무엇이 일어나는가
1동일한 프롬프트 파일을 Claude에게 입력
2Claude가 작업 수행 (파일 수정, 테스트 실행 등)
3세션 종료 시도
4(플러그인의 경우) Stop hook이 종료를 차단하고 같은 프롬프트를 재주입
5Claude는 자기가 방금 수정한 파일git diff를 읽고 다음 행동 결정
6<promise>DONE</promise> 또는 max-iterations 도달까지 반복

철학 — “Deterministically Bad in an Undeterministic World”

섹션 제목: “철학 — “Deterministically Bad in an Undeterministic World””
  • 같은 프롬프트로 같은 환경에서 같은 실수를 반복하면, 그 실수는 예측 가능(deterministic) 해진다.
  • 예측 가능한 실수는 → 프롬프트 튜닝으로 잡을 수 있다.
  • 그래서 Huntley는 “Ralph를 기타처럼 튜닝한다(tune Ralph like a guitar)“고 표현한다. 실수가 보이면 도구를 욕하지 않고 프롬프트에 “Don’t assume — search first” 같은 명시적 안내판을 박는다.

흔한 오해: “Claude가 자기 출력을 다음 입력으로 받는 것” → 아니다. 실제로는:

  • 프롬프트는 절대 안 바뀐다.
  • 바뀌는 건 작업 디렉토리의 상태다.
  • Claude는 매 iteration 자기가 만든 파일·테스트 결과·git log를 새로 읽고 “어디까지 했지?”를 추론한다.

이게 핵심이다. 파일 시스템과 git이 메모리 역할을 한다.


Terminal window
# Claude Code 안에서
/plugin
# 또는
claude plugin install ralph-loop@claude-plugins-official

설치 후 /reload-plugins.

현재 세션에서 루프 시작.

Terminal window
/ralph-loop "Refactor the cache layer" --max-iterations 20
/ralph-loop "Add tests" --completion-promise "TESTS COMPLETE"

옵션

옵션설명
--max-iterations <n>N회 반복 후 자동 종료 (0 또는 미지정 시 무한)
--completion-promise '<text>'종료 신호 문구. 반드시 따옴표로 감싸야 멀티워드 지원
-h, --help도움말

완료 신호 — <promise> 태그

<promise>TASK COMPLETE</promise>
  • Stop hook이 transcript에서 정확히 이 XML 태그를 찾는다.
  • 문자열 매칭은 literal exact match (= "$COMPLETION_PROMISE", glob 아님).
  • 그래서 "SUCCESS"/"BLOCKED" 같은 복수 종료 분기는 불가능 → --max-iterations를 안전망으로 항상 같이 써라.

활성 루프 취소. .claude/ralph-loop.local.md 상태 파일을 삭제하고 현재 iteration 번호를 보고.


플러그인은 두 개의 파일이 본체다.

4.1 상태 파일 — .claude/ralph-loop.local.md

섹션 제목: “4.1 상태 파일 — .claude/ralph-loop.local.md”

/ralph-loop 호출 시 setup-ralph-loop.sh가 만든다. YAML frontmatter + 본문(프롬프트) 구조.

---
active: true
iteration: 1
session_id: <CLAUDE_CODE_SESSION_ID>
max_iterations: 20
completion_promise: "TASK COMPLETE"
started_at: "2026-05-19T12:34:56Z"
---
Build a REST API for todos.
... (전체 프롬프트)
  • .claude/ 디렉토리에 저장되며 프로젝트 스코프.
  • 같은 프로젝트의 다른 Claude Code 세션이 동시에 열려있어도 session_id 필드로 격리된다 (Stop hook이 자기 세션이 아닌 루프의 종료를 막지 않음).

세션이 자연 종료(=Claude가 더 할 일이 없다고 판단)에 도달할 때마다 호출된다. 핵심 로직:

  1. .claude/ralph-loop.local.md 존재 확인. 없으면 즉시 종료(루프 비활성).
  2. frontmatter에서 iteration, max_iterations, completion_promise, session_id 파싱.
  3. 현재 세션이 루프 주인이 아니면 → exit 0.
  4. max_iterations 도달했으면 → 상태 파일 삭제하고 exit 0.
  5. transcript JSONL에서 마지막 100개의 assistant 라인을 읽어 마지막 text block 추출 (tool call만 있는 turn은 무시).
  6. Perl로 <promise>...</promise> 내용 추출 → 정규화 후 completion_promise정확히 일치하면 종료.
  7. 일치 안 하면 → iteration 1 증가 후 JSON 출력:
    {
    "decision": "block",
    "reason": "<원본 프롬프트 그대로>",
    "systemMessage": "🔄 Ralph iteration N | ..."
    }
    Claude Code는 이 JSON을 받아 종료를 막고 reason 필드를 새 사용자 메시지처럼 주입한다.

매 iteration의 시작에는 다음과 비슷한 시스템 메시지가 붙는다.

🔄 Ralph iteration 5 | To stop: output <promise>DONE</promise>
(ONLY when statement is TRUE - do not lie to exit!)

플러그인은 “거짓 promise로 탈출 금지” 를 setup 단계와 매 iteration마다 강하게 경고한다. 이건 LLM이 “지쳤으니 그냥 끝내자”고 우회하는 걸 막기 위한 가드레일.


# ❌ Bad
Build a todo API and make it good.
# ✅ Good
Build a REST API for todos.
완료 기준:
- 모든 CRUD 엔드포인트 동작
- 입력 검증
- 테스트 커버리지 > 80%
- README에 API 문서
완료 시 출력: <promise>COMPLETE</promise>

한 루프에 단일 implementation task만. Context window는 ~170k tokens. 하나라도 더 끼우면 품질이 무너진다.

Phase 1: 사용자 인증 (JWT + 테스트)
Phase 2: 상품 카탈로그 (list/search + 테스트)
Phase 3: 장바구니 (add/remove + 테스트)
모든 phase 완료 시 <promise>COMPLETE</promise> 출력.

5.3 자가 교정 루프 명시 (TDD 패턴)

섹션 제목: “5.3 자가 교정 루프 명시 (TDD 패턴)”
Feature X를 TDD로 구현:
1. 실패하는 테스트 작성
2. 구현
3. 테스트 실행
4. 실패 시 디버그
5. 모두 그린이 될 때까지 반복
6. <promise>COMPLETE</promise>

Huntley가 강조하는 단골 안티-실수 가드:

“Before making changes search codebase (don’t assume not implemented) using subagents. Think hard.”

중복 구현이 가장 잦은 실패 모드라서다.

LLM이 게으르면 # TODO: implement 만 박고 끝내려 한다. Huntley는 격앙된 톤으로 명시한다:

“DO NOT IMPLEMENT PLACEHOLDER OR SIMPLE IMPLEMENTATIONS. WE WANT FULL IMPLEMENTATIONS. DO IT OR I WILL YELL AT YOU.”

(농담이 아니라 실제 효과가 있다는 게 Huntley의 일관된 관찰)

5.6 결정론적 스택 할당 (Deterministic Stack Allocation)

섹션 제목: “5.6 결정론적 스택 할당 (Deterministic Stack Allocation)”

매 루프가 같은 파일들을 같은 순서로 참조해야 한다.

@AGENT.md ← 빌드/실행 방법
@fix_plan.md ← 우선순위가 매겨진 할 일 목록
@specs/*.md ← 사양

이 세 가지는 stateless 루프 사이의 컨텍스트 앵커 역할.


“Cost of a $50k USD contract, delivered, MVP, tested + reviewed with @AmpCode. $297 USD.”

YC 해커톤 테스트에서 하룻밤 동안 6개 레포 동시 생성 사례. 단 모두 greenfield 프로젝트라는 전제.

  • 탐색·검색·파일 쓰기 같은 비용 큰 작업은 병렬 서브에이전트로 분산
  • 빌드·테스트는 단일 스레드 (예: “only 1 subagent for build/tests of rust”)
    • 이유: 빌드 결과의 일관성·캐시 일관성

Stop hook은 transcript의 마지막 100개 assistant 라인만 본다.

  • 매우 긴 turn에서 <promise> 태그가 100라인 이전에 묻히면 감지 실패 가능.
  • 실무 권장: promise는 마지막 메시지의 마지막 줄에 단독으로 출력하도록 프롬프트에 못박기.

같은 프로젝트에서 Claude Code 세션 2개를 동시에 열어도, 루프 시작 세션의 session_id가 아니면 Stop hook이 다른 세션의 종료를 막지 않는다.

→ 안전하게 두 번째 세션을 띄워서 모니터링·수동 점검 가능.

Terminal window
grep '^iteration:' .claude/ralph-loop.local.md
# 또는
head -10 .claude/ralph-loop.local.md

Huntley의 관측: 광고된 200k 윈도우와 달리 실제 품질은 147k~152k 토큰 부근에서 클립된다. → “한 루프 = 한 작업” 규칙이 단순한 미니멀리즘이 아니라 품질 보존을 위한 필수 제약인 이유.


7.1 [중대] 공식 플러그인의 컨텍스트 누적 문제

섹션 제목: “7.1 [중대] 공식 플러그인의 컨텍스트 누적 문제”

원조 Ralph vs 공식 플러그인의 가장 큰 차이.

  • 원조: bash while로 매 iteration마다 완전히 새 Claude 세션을 fork. 컨텍스트는 항상 0에서 시작.
  • 공식 플러그인: 같은 세션 안에서 Stop hook으로 prompt만 다시 주입. → 컨텍스트가 계속 누적.

결과적으로 ~150k 토큰 부근에서 auto-compaction이 발생, 일부 정보가 손실되며 효과가 급락한다. 일부 비평가들은 “공식 플러그인은 사실 Ralph가 아니다” 라고까지 주장한다.

완화책:

  • 짧고 명확한 작업에만 사용 (max-iterations ≤ 20)
  • 매 iteration이 큰 출력을 내지 않도록 프롬프트로 통제 (예: “출력은 5줄 이내 + 파일 수정”)
  • 컨텍스트가 무거워질 작업은 외부 bash 루프 + Claude Code SDK로 진짜 fresh session 방식 고려
⚠️ WARNING: This loop cannot be stopped manually!
It will run infinitely unless you set --max-iterations or --completion-promise.
  • /cancel-ralph 명령은 다음 Stop hook 발화 시점에 효과가 있다. 현재 진행 중인 turn은 계속 돈다.
  • 항상 --max-iterations를 안전망으로 같이 걸어라. completion-promise 단독은 위험.

LLM이 “지쳐서” 또는 “이 정도면 되겠지” 싶어 거짓 promise를 출력해 탈출하려 할 수 있다. 플러그인이 강한 경고를 박지만 100% 차단되지는 않는다.

완화책:

  • promise 문구를 검증 가능한 상태와 결합. 예: <promise>ALL_TESTS_PASS</promise> + 동시에 테스트 실행 결과를 출력하도록 강제.
  • Critical한 단계에서는 사람이 직접 transcript 검토.

.claude/ralph-loop.local.md를 수동 편집해서 iteration 필드가 숫자가 아니게 되면 → Stop hook이 자동 종료하며 파일 삭제. 의도된 안전 동작.

Stop hook이 bash 스크립트라 Git for Windows의 Git/bin/bash.exe로 명시 지정 필요. WSL bash로 잘못 잡히면:

  • wsl: Unknown key 'automount.crossDistro'
  • execvpe(/bin/bash) failed

수정 위치: ~/.claude/plugins/cache/.../hooks/hooks.json.

"command": "\"C:/Program Files/Git/bin/bash.exe\" ${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh"

루프가 도는 동안 token 사용량이 선형으로 누적된다. /cost나 외부 모니터링으로 주기적 확인 필수. “잠깐 자고 일어났더니 $200 청구” 사례 다수 보고됨.


  • 명확한 성공 기준이 있는 task: 테스트 통과, lint 무결, 빌드 그린
  • 반복적 자가 교정이 필요한 작업: TDD, 마이그레이션 스크립트 수정
  • Greenfield 프로젝트: 레거시 컨텍스트가 적어서 컨텍스트 누적 문제가 덜함
  • 사람이 손 떼고 두고 갈 수 있는 일: 대규모 리팩토링 1차 작업, 일괄 변환
  • 자동 검증이 가능한 영역: 테스트·linter·타입체크가 곧 reward signal
  • 인간 판단·디자인 결정이 필요한 일: UX, 아키텍처, 네이밍 선택
  • One-shot 명령: 그냥 한 번 실행하면 끝나는 것
  • 모호한 성공 기준: “코드 품질 개선해줘” 같은 것
  • 레거시·복잡한 컨텍스트가 무거운 곳: Huntley 본인이 “절대 안 쓴다”고 명시: “There’s no way in heck would I use Ralph in an existing code base.”
  • 프로덕션 디버깅: 표적 디버깅이 더 빠르고 정확

Terminal window
/ralph-loop "Fix the token refresh logic in auth.ts. \
Run pnpm test:auth after each change. \
Output <promise>FIXED</promise> when all tests pass." \
--completion-promise "FIXED" \
--max-iterations 10

기대 동작:

  1. auth.ts 읽고 수정
  2. 테스트 실행
  3. 실패 출력 보고 다시 수정
  4. 그린이 되면 <promise>FIXED</promise> 출력
  5. Stop hook이 감지하고 루프 종료

9.2 와인 레포 활용 — 수입사 한글 매핑 LLM 검수 자동화

섹션 제목: “9.2 와인 레포 활용 — 수입사 한글 매핑 LLM 검수 자동화”

이 레포의 LLM 검수 파이프라인 같은 작업에 적용 가능:

Terminal window
/ralph-loop "scripts/llm-review-mfds/에서 다음 작업을 수행:
1. data/mfds/review_queue.jsonl을 100건씩 배치로 읽어 GPT-4o-mini로 1차 검수
2. ACCEPT/REJECT/REVIEW로 분류해 결과 jsonl로 출력
3. REVIEW만 추려서 GPT-4o로 2차 검수
4. 최종 ACCEPT 결과를 data/mfds/accepted.jsonl에 append
5. 모든 batch 완료 시 <promise>MFDS_LLM_REVIEW_DONE</promise> 출력
검수 결과 파일은 idempotent하게 append하고, 이미 처리된 row는 건너뛸 것." \
--completion-promise "MFDS_LLM_REVIEW_DONE" \
--max-iterations 30

9.3 REST API 그린필드 빌드 (Huntley 클래식 예시)

섹션 제목: “9.3 REST API 그린필드 빌드 (Huntley 클래식 예시)”
Terminal window
/ralph-loop "Build a REST API for todos.
Requirements:
- CRUD operations (POST/GET/PATCH/DELETE /todos)
- Input validation with zod
- Integration tests with vitest, coverage > 80%
- README with endpoint examples
Use TDD: write failing test → implement → verify green → move on.
Output <promise>COMPLETE</promise> when all phases done and tests pass." \
--completion-promise "COMPLETE" \
--max-iterations 50

10. 정리: Ralph Loop를 쓸지 말지 30초 체크리스트

섹션 제목: “10. 정리: Ralph Loop를 쓸지 말지 30초 체크리스트”
질문Yes면 Ralph 적합
성공 기준을 객관적으로 측정할 수 있나? (테스트·lint·빌드)
작업이 greenfield(또는 명확히 격리된 모듈)인가?
한 iteration의 출력이 5~20줄 + 파일 수정 정도로 콤팩트한가?
max-iterations를 합리적으로(≤30) 설정할 수 있나?
사람의 디자인 판단이 필요한가?
레거시 컨텍스트가 무거운가?
한 번만 실행하면 끝나는 일인가?

3개 이상 ✅면 Ralph 시도. 1개라도 ❌면 일반 /-명령이나 다른 워크플로 권장.



조사 일자: 2026-05-19. 플러그인 버전: ralph-loop@1.0.0 (Anthropic 공식).