자기개선·반복 루프 — 횡단분석

한 줄 요약

“스스로 고쳐가며 반복한다”는 대부분 `Stop을 막고 프롬프트를 다시 던지는’ 한 점으로 수렴하지만, 산출물 자체를 진화시키는 진짜 자기개선은 ouroboros와 OMC self-improve 둘뿐이다. 왜 배우나: 내 스택(Claude+Codex+OMC)에 무엇이 이미 충분하고 무엇이 빠졌는지를 알아야, 베낄 조각을 정확히 떼어다 끼울 수 있기 때문.

그림

아래 mermaid는 위 개념도를 흐름으로 한 번 더 풀어 본 것이다. 모든 반복 루프는 “한 단위 실행 → 멈출지 판정 → 못 멈추면 반성을 입혀 재주입”의 사이클을 돈다. 다른 점은 반성을 얼마나 깊게 입히느냐다.

flowchart TD
    A["한 단위 실행<br/>turn · story · generation · gate-retry"] --> B{"멈춰도 되나?<br/>수렴/완료 신호 검사"}
    B -->|"완료"| Z["종료 · 영수증 기록"]
    B -->|"미완"| C{"무한루프 가드<br/>N회 상한 초과?"}
    C -->|"초과"| Y["강제 종료 · 격리/에스컬레이션"]
    C -->|"여유 있음"| D[반성 주입]
    D --> D1["얕음: 도구결과를 히스토리에 재주입<br/>(CC · Codex · gajae)"]
    D --> D2["중간: 같은/보강 프롬프트 재주입<br/>(ralph-loop · OMC ralph)"]
    D --> D3["깊음: 사양/온톨로지 자체를 다시 씀<br/>(ouroboros · self-improve 토너먼트)"]
    D1 --> A
    D2 --> A
    D3 --> A

쉽게 풀기

이 주제는 “AI가 한 번 답하고 끝나지 않고, 스스로 더 돌게 만드는 장치”에 대한 이야기다. 단계별로 풀어 보자.

  1. 반복의 최소 단위를 정한다. “한 번 더 호출”이 아니라 상태가 쌓이는 한 묶음을 한 바퀴로 본다. 누구는 대화 한 턴(turn), 누구는 사용자 스토리 하나(story), 누구는 한 세대(generation), 누구는 게이트 재시도(gate-retry)를 한 바퀴로 친다.
  2. 멈출 때를 정한다. 다 했다는 신호가 와야 멈춘다. 약한 버전은 “약속 문구를 출력하면 완료”이고, 강한 버전은 “여러 조건이 동시에 충족돼야 완료”다.
  3. 반성을 다음 입력에 끼워 넣는다. 비유하면, 시험을 보고 채점 결과(틀린 이유)를 받아 다음 회차 답안에 반영하는 것이다. 얕게 반영하면 “방금 결과만 보고 한 번 더”, 깊게 반영하면 “문제 자체를 다시 출제”한다.

핵심 트릭 하나만 기억하면 된다. Claude Code가 외부에 열어 준 “루프를 더 돌리는” 유일한 문은 Stop 훅이다. 모델이 끝내려 할 때 훅이 block을 외치고 이유(reason)를 돌려주면, Claude Code는 그 이유를 다음 턴의 사용자 입력처럼 모델에게 보여준다. 모델은 “어, 새 지시가 왔네?” 하고 다시 일한다. Claude 위에 사는 거의 모든 하네스가 이 한 문으로 몰린다.

무한 핑퐁 주의

자기참조 루프의 1번 실패는 “끝없이 서로 부르기”다. 그래서 모두 가드를 둔다. Claude Code는 8연속 block이면 훅을 무시하고 강제 종료, ralph-loop는 MAX_ITERATIONS, ouroboros는 max_generations, 내 akh2 패턴은 2번 실패하면 격리(quarantine)한다.

핵심 정리

반복 단위 · 종료 신호 · 반성 주입의 세 질문으로 본 요약 (자세한 행별 메커니즘은 아래 콜아웃으로 분산):

진영대표반복 단위 → 종료 신호
Stop-hook persistenceCC native · ralph-loop턴 → 약속문구/상한
evaluator-backed persistenceOMC ralph · autoresearch스토리 → PRD pass+리뷰 / max-runtime
robust runtime (자기개선 없음)Codex · gajae-code턴 → end_turn
진짜 진화self-improve · ouroboros세대 → 다중 AND 게이트
artifact admission gate내 akh2 패턴gate-retry → 결정적 pass

persistence 진영 — "완료 보장"이 목표 (산출물은 안 진화)

  • CC native: Stopdecision:"block"+reason 재주입이 유일한 루프 확장점. 자기개선 메커는 없음. 8연속 block 가드.
  • CC /goal: 세션 스코프 내장 persistence loop. 작은 evaluator가 매 턴 목표 충족을 판정해 다음 턴 유도.
  • ralph-loop plugin: stop-hook.shjq -n '{decision:"block", reason:$prompt}'같은 프롬프트(SAME PROMPT) 통째 재주입. 완료=프롬프트 속 약속문구, 종료=MAX_ITERATIONS.
  • OMC ralph: prd.json(story별 passes:bool+AC). 키워드→CC UserPromptSubmit 훅 주입으로 발동(자체 루프 없음). 완료=모든 story pass AND 별도 reviewer(architect/critic/codex) 검증 AND deslop+회귀 재실행. writer≠reviewer.
  • fable-ish: ledger(changed_files_seen/verification_results/stop_blocks)를 보고 Stop 차단. MAX_STOP_BLOCKS=2, “말만 하고 tool_use 없이 끝낸 턴” 정규식 탐지, fail-open.
  • 내 akh2 패턴: admit.mjs 결정적 게이트. FAIL 사유 JSON을 워커가 읽고 재시도, 2-fail→quarantine/ 격리→Claude 에스컬레이션. 경계는 fail-closed.

robust runtime 진영 — 의도적으로 자기개선을 안 넣음

  • Codex: run_turn loop, 도구결과(FunctionCallOutput)를 히스토리에 실어 재샘플링. end_turn==Some(false)면 follow-up 강제. mid-turn auto-compact, depth 가드. (단 Codex에도 Stop 훅의 decision:"block" reason 재주입은 있다 — 코어 run_turn만 보면 없다고 좁혀야 정확.)
  • gajae-code: 두 겹 루프(바깥 while + 안쪽 도구). Harmony-leak truncate/온도+0.05 재시도(2회 후 escalate), abort race, 영수증. 자기개선은 상위 워크플로(ultragoal/ralplan/deep-interview) 계층에 분리.

evolution 진영 — 사양/코드 자체를 진화

  • OMC self-improve: Research→Plan→리뷰→N executor 병렬→Tournament(승자 1개 머지). no-regression(승자도 best_score 이상), 회귀 시 git reset --hard HEAD~1 롤백. 종료 4종(target/plateau/max-iter/circuit-breaker), sealed_files로 평가기 자기수정 차단. 고정된 goal/benchmark 아래 “구현 개선” 탐색.
  • ouroboros: wonder→reflect→seed→execute→evaluate. 이전 세대 평가요약을 Wonder(공백 질문)→Reflect(온톨로지 변이)에 입력해 사양 자체를 다시 씀(뱀이 꼬리 뭄). 드리프트 게이트(goal0.5/constraint0.3/ontology0.2 ≤0.3), 정상 수렴 경로에서만 다중 AND 게이트, stagnation/oscillation은 별도 종료. spec/ontology/lineage까지 진화.

모두가 공유하는 설계 원칙 (체크리스트):

  • Stop 차단 + 프롬프트 재주입이 CC 위 하네스의 사실상 표준 (단, 재주입 내용은 같지 않음 — 같은 프롬프트/구체 사유/상태 지시로 갈림)
  • 무한루프 가드 필수 (N회 상한 또는 “두 번 알리고 양보”)
  • 반복 단위 = 상태가 쌓이는 묶음, 외부 파일/이벤트에 영속화해 세션 넘어 재개 (CC native·Codex 코어는 예외 — 상태 강제 안 함)
  • 자율 모드는 “사람에게 안 묻는다”를 명시 정책으로 (self-improve “NEVER stop to ask”)
  • fail-open (안전장치가 작업을 죽이면 안 됨 — 단 artifact 경계는 fail-closed)

실제 예시

가장 단순한 ralph 원형. Stop 훅이 같은 프롬프트를 통째로 다시 던진다.

# ralph-loop/hooks/stop-hook.sh (원형)
# 완료조건 미달이면 SAME PROMPT를 reason으로 재주입 → CC가 다음 턴 입력처럼 노출
jq -n --arg prompt "$PROMPT" '{decision:"block", reason:$prompt}'
# 종료: MAX_ITERATIONS 도달 시 RALPH_STATE_FILE 삭제 후 exit 0

OMC self-improve의 진화 설정 — 점수만 보는 게 아니라 회귀·정체·차단기를 함께 본다.

// oh-my-claudecode/skills/self-improve/settings.json (핵심 키)
{
  "max_iterations": 20,
  "plateau_threshold": 0.01,      // 개선폭이 이보다 작으면 정체로 카운트
  "plateau_window": 3,
  "target_value": 0.95,           // 도달 시 종료
  "regression_threshold": 0.0,    // 승자도 best_score 이상이어야 머지
  "circuit_breaker_threshold": 3, // 연속 악화 N회 시 차단
  "sealed_files": ["benchmark/**", "eval/**"]  // 평가기 자기수정 차단
}

ouroboros 드리프트 게이트 — 점수가 올라도 원래 목표에서 이탈하면 잡는다.

# ouroboros/src/ouroboros/observability/drift.py (구조)
combined_drift = 0.5 * goal_drift + 0.3 * constraint_drift + 0.2 * ontology_drift
DRIFT_THRESHOLD = 0.3   # 초과 시 한 라운드 강제 중단·재정렬

요약 & 셀프체크

3줄 요약:

  1. 모든 반복 루프는 “한 단위 실행 → 종료 판정 → 반성 주입 후 재주입”을 돌고, CC 위에서는 Stop 훅이 유일한 확장점이라 다들 거기로 수렴한다.
  2. 최대 분기선은 persistence(완료 보장, 산출물 불변) vs **evolution(사양/코드 진화)**이고, 진화 진영만 드리프트·no-regression 같은 안전장치를 추가로 짊어진다.
  3. 내 스택에 빠진 건 (a) 결정적 비용계단 게이트 (b) score 외 drift 측정 (c) 실패 격리·학습 — 셋 다 ouroboros+akh2에 완성형이 있다.

스스로 답해 보기:

  • Stop 훅이 돌려주는 reason이 모델 입장에서 무엇으로 보이며, 왜 그게 “루프 연장” 트릭인가?
  • “변화 없음 = 수렴”이 왜 자기개선 루프에서 위험한 오판인가? ouroboros는 이걸 어떻게 막나?
  • 검증을 항상 LLM reviewer로 돌리지 않으려면 어떤 “비용 계단”을 두는가? (Stage1/2/3)

연결

_분석축_루브릭 · HOME

기능노트 근거:

소스/문서:

  • /home/seunghyeong/harness-work/oh-my-claudecode/skills/ralph/SKILL.md — PRD-driven persistence, reviewer 선택, mandatory deslop+회귀
  • /home/seunghyeong/harness-work/oh-my-claudecode/skills/self-improve/SKILL.md — tournament selection, no-regression+git reset --hard, 종료 4종, sealed_files
  • /home/seunghyeong/harness-work/oh-my-claudecode/skills/autoresearch/SKILL.md — evaluator JSON(pass+score), max-runtime 정지, decision-log.md
  • /home/seunghyeong/harness-work/ouroboros/src/ouroboros/evolution/loop.py · convergence.py · observability/drift.py · ralph_loop.py · evaluation/pipeline.py · auto/ledger.py
  • /home/seunghyeong/harness-work/codex/codex-rs/core/src/session/turn.rsrun_turn, auto-compact, depth (+hooks/src/events/stop.rs)
  • /home/seunghyeong/harness-work/gajae-code/packages/agent/src/agent-loop.ts — 두 겹 루프, Harmony 처리
  • /home/seunghyeong/harness-work/fable-ish/hooks/stop_gate.py · scripts/verify_state.py — should_block_stop
  • /mnt/d/akh2/pipeline/admit.mjs · gate.mjs · golden-queries.json — 결정적 게이트·물리 거부·회귀검증
  • /home/seunghyeong/.claude/plugins/marketplaces/claude-plugins-official/plugins/ralph-loop/hooks/stop-hook.sh — SAME PROMPT 재주입 원형
  • 공식문서: /mnt/d/6study/10_프레임워크분석/_원문아카이브/claude-code/hooks.md(Stop 결정 제어·8연속 block), cli-reference.md(--max-turns/--max-budget-usd)

내 스택에 차용할 구체안

내 스택은 CC(native Stop)+OMC(ralph/self-improve/autoresearch)를 이미 갖췄다. 빈 곳은 “진짜 진화”와 “결정적 게이트 비용계단”. ouroboros·akh2에서 떼어 온다.

  1. OMC ralph 완료조건에 다중 AND 게이트 이식.changed_count>0을 항상 요구하면 분석·설정확인 같은 합법 no-op 완료가 막힌다 → “AC별 증거 ledger + 검증 명령 + 변경 파일 매핑 + regression 결과”를 reviewer 직전에 강제하는 형태가 낫다. fable-ish ledger를 PostToolUse 훅으로 채운다.
  2. self-improve 위에 드리프트 측정 추가. score만 보면 점수는 오르는데 goal에서 이탈하는 사례를 못 잡는다. ouroboros combined_drift ≤0.3을 측정하되, hard stop보다 critic 에스컬레이션/quarantine 트리거가 낫다(단어 Jaccard만으로 판정하면 좋은 개선도 오탐 — goal.md/sealed files/changed-file scope/benchmark category를 같이 본다).
  3. 비용 계단 평가. 항상 LLM reviewer로 검증하지 말고 Stage1 결정적 코드 게이트(lint/test, $0, 실패 즉시 종료) → Stage2 단일 reviewer → Stage3 고위험 diff만 multi-model 합의. 단 admit.mjs는 wiki artifact 전용이라 그대로 못 옮기고 일반화해야 한다.
  4. 실패 후보 bundle 격리. self-improve가 실패 원문을 안 남기는 건 아니다(failure_analysis/iteration history/merge report 존재). 부족한 건 “사람이 바로 읽을 수 있는 실패 후보 bundle” — akh2 quarantine + autoresearch decision-log.md 결합.
  5. stated-but-unstarted 정규식 가드를 공통 Stop 훅으로. fable-ish의 “말만 하고 끝낸 턴” 탐지를 OMC context-guard-stop.mjs에 합치되, user input/권한/context-limit/auth 대기와 충돌 금지 — 기존 가드 앞단에 1~2회 제한 counter로 넣는다.

핵심 한 줄: persistence는 OMC ralph로 충분, 부족한 건 (a) 결정적 비용계단 게이트 (b) score 외 drift 측정 (c) 실패 격리·학습.

Codex 교차검증 (gpt-5.5, xhigh)

본 문서를 /home/seunghyeong/harness-work/ 소스와 대조한 결과, 방향은 맞지만 “반복 지속·검증 게이트·자기개선·사양 진화”를 한 표에 섞으면서 몇 군데 과장됨. 핵심 수정점만:

  • 하네스 개수: 본문이 “7개”라 했으나 표엔 9개. fable-ish는 독립 행으로 넣어야 함.
  • Codex/CC: Codex에도 Stop 훅 reason 재주입이 있다(hooks/src/events/stop.rs) → “코어 run_turn만 보면 없음”으로 좁혀야. CC /goal도 별도 persistence loop로 누락.
  • “표준 ABI”·“모든 상태 영속”·“fail-open 공통”은 과한 일반화: 재주입 내용이 제각각이고, CC native/Codex 코어는 상태 강제 안 하며, akh2 admit.mjs는 fail-closed.
  • 진화 진영 구분: self-improve=고정 goal 아래 구현 개선, ouroboros=spec/ontology/lineage 진화 — 같은 것으로 묶으면 안 됨.
  • ouroboros 수렴: 다중 AND 게이트는 “유사도 기반 정상 수렴 경로”에서만. stagnation은 CONVERGED가 아니라 STAGNATED로 별도 처리.
  • 종합: 비교 축을 Stop-hook persistence · evaluator-backed persistence · workflow/receipt gate · benchmark tournament · spec/ontology evolution · artifact admission gate로 다시 나누면 강해진다.