start-harness.sh를 시작점으로 삼는 코딩 AI Codex의 자가개선(스스로 고칠 곳을 찾아 고치는 것) 하네스(harness — 사람이 매번 다시 확인하는 대신, 그 확인을 자동으로 강제하는 장치)를 통째로 뜯어본 글입니다.
문제는 이것이었습니다. AI에게 코드를 맡기면 "다 됐다"고 말은 하는데, 정말 됐는지는 사람이 매번 다시 확인해야 했습니다.
결론부터 말하면, 이 하네스의 종합 구현 수준은 87%로 실제 서비스에 써도 될 만큼입니다.
이 하네스는 AI가 스스로 코드를 고치고, 말 대신 실제 증거로 검증하게 만듭니다.
이 구성에는 Loopy-Era라는 이름이 붙어 있습니다(Codex 쪽 자율 실행 환경을 부르는 이름).
이 글은 그 전체 구조를 정리합니다.
순서대로 이어지는 14단계 작업, 고칠 곳을 알려주는 단서 5종을 모으는 방법,
핵심 기능이 최소한 돌아가는지 빠르게 확인하는 8가지 기본 점검,
그리고 AI가 사람 없이 스스로 수정안을 만들어 적용하는 방식까지 살펴봅니다.
L6결론부터 말하면, 이 시스템은 사람이 시키지 않아도 스스로 굴러가는 자동 개선 루프(loop — 같은 과정을 되풀이하는 반복 구조)입니다. AI가 "여기 고칠 게 있다"는 단서를 직접 찾아냅니다. 그다음 언어 모델(문장을 이해하고 만들어내는 AI)을 불러 수정안을 만듭니다. 그 수정안이 정말 맞는지 검증한 뒤에 적용합니다. 이 과정을 사람 개입 없이 반복합니다. 관련 파일은 모두 ~/.codex/ 폴더 아래에 모여 있고, cc-sync라는 동기화용 프로젝트를 거쳐 여러 컴퓨터에 똑같이 맞춰집니다.
start-harness.shloop-era-supervisor.sh / loop-era-supervisor.pyprocess_project() — 14단계 자동 실행 순서를 도는 함수l6_blocker_count입니다. 통과를 막는 결함이 몇 개 남았는지 센 값으로, 목표는 0개입니다. 지표 이름 앞의 l6은 검증 깊이 등급 6단계라는 뜻입니다. 이 등급을 줄여 쓴 표기가 L6.self-improve-trigger.sh + self-improve-worker.pyverify-l6.sh + adversarial-review-l6.pystart-harness.sh — 시작 명령어의 흐름이 시작 스크립트(script — 명령을 순서대로 적어 둔 실행 파일)가 할 수 있는 일은 크게 5개의 하위 명령으로 나뉩니다. 각 명령이 무엇을 하는지는 스킬(skill — Codex가 불러 쓰는 작업 절차 묶음) 설명서 파일 .codex/skills/start-harness/SKILL.md에 정의돼 있습니다.
# start — 하네스 전체를 켬 (가장 많이 쓰는 명령) bash start-harness.sh start --project-root "$PWD" loop-era-supervisor.sh ensure ← 감시 프로그램이 떠 있도록 보장 ralph-loop.sh start [args] ← 이 프로젝트를 관리 목록에 등록 ralph-loop.sh tick --force ← 기다리지 않고 즉시 1회 실행 pretty_status() ← 감시 프로그램과 작업 프로세스 상태 출력 # smoke — 환경이 제대로 갖춰졌는지 빠르게 점검 bash start-harness.sh smoke --project-root "$PWD" self-improve-smoke.sh ← 8가지 통합 테스트 loop-era-smoke.sh ← 반복 루프 전용 기본 점검 verify-l6.sh ← 통과를 막는 결함 개수 측정 adversarial-review-l6.py ← 트집 잡듯 파고드는 코드 리뷰 # stop — 중지 (--global-supervisor를 붙이면 감시 프로그램까지 끔) bash start-harness.sh stop --project-root "$PWD" [--global-supervisor]
ralph-loop.sh — 반복 실행 루프ralph-loop.sh는 실제 관리 프로그램인 loop-era-supervisor.py를 명령줄에서 간편하게 부르도록 감싼 껍데기(래퍼)입니다. start 명령을 실행하면, 저장소 안에 자가개선 실험에 필요한 기본 파일들을 자동으로 깔아 둡니다.
ralph-loop.sh start seed_repo_artifacts() cp ~/.codex/autoresearch/{verify-l6.sh, adversarial-review-l6.py} → .codex/autoresearch/ (없으면 자동 복사) python3 loop-era-supervisor.py register [args] loop-era-supervisor.sh start ralph-loop.sh tick → python3 loop-era-supervisor.py run-once ralph-loop.sh stop → python3 loop-era-supervisor.py cancel ralph-loop.sh status → python3 loop-era-supervisor.py status
loop-era-supervisor.py안에 정해 둔 순서표 PHASE_ORDER대로 14단계가 차례차례 실행됩니다. 각 단계의 결과는 진행 기록 phase_history에 남고, 지표가 어떻게 변해 왔는지는 results.tsv라는 표 파일에 저장됩니다.
init_project→ init-project-runtime.py → .codex/loopy-era/init-project.jsonself_improve_trigger→ self-improve-trigger.shself_improve_worker_initial→ self-improve-worker.py runverify_initial→ .codex/autoresearch/verify-l6.shadversarial_review_initial→ .codex/autoresearch/adversarial-review-l6.pyteam_plan→ team-runtime.py --jsonteam_execute→ team-runtime.py --execute --jsonqa_cycle→ qa-cycle-runtime.py --max-rounds Nqa_fix_retry→ team-runtime.py --execute → qa-cycle-runtime.py (반복)inject → self_improve_adversarial → verify_final→ merge_adversarial_findings() → self-improve-worker.py → verify-l6.shadversarial_review_final→ adversarial-review-l6.pycloseout→ results.tsv + loop-era-metrics.jsonl + action-log.shself-improve-trigger.sh는 여러 곳에서 "고칠 게 있다"는 단서를 모아 처리 대기 파일 ~/.codex/pending/self-improve-{key}.json에 저장합니다. 이미 처리한 단서는 "처리 완료" 표시(ack) 파일로 걸러내, 같은 일을 두 번 하지 않습니다.
| 단서 종류 | 어디서 모으나 | 무엇을 뜻하나 |
|---|---|---|
fix_commit |
git log --grep='^fix:' |
작업 중 만든 버그 수정 커밋입니다. 어떤 실수가 반복되는지 배우는 재료가 됩니다. |
bug_fixer_retry |
.codex/logs/*.jsonl |
버그 수정 담당 AI가 몇 번이나 다시 시도했는지 남긴 기록입니다. 자동 수정이 반복된 패턴을 잡아냅니다. |
recurrence |
check-recurrence.py |
과거 자가개선 이력과 버그 수정 커밋을 겹쳐 봅니다. 같은 키워드가 2번 이상 나오면 신호로 잡습니다. |
telemetry |
self-improve-telemetry.py |
사용자가 불만을 드러낸 표현을 분석합니다. 한국어 표현도 잡습니다("아니요", "안 보이", "중복" 등). |
adversarial_finding |
adversarial-review-l6.py |
P1/P2는 결함 등급 표기입니다. 앞의 1등급이 중대 결함, 뒤의 2등급이 주요 결함입니다. 비판적 리뷰가 이 등급의 결함을 찾으면 다음 반복 회차에 자동으로 다시 처리 목록에 넣습니다. |
# self-improve-trigger.sh 흐름 project-scope.py → 프로젝트 고유 키 결정 # 단서 수집 git log --since=$SESSION_START --grep='^fix:' → fix_commit[] .codex/logs/*.jsonl | grep "bug-fixer" → bug_fixer_retry[] check-recurrence.py $PROJECT_ROOT → recurrence[] self-improve-telemetry.py --project-root $ROOT → telemetry[] # 처리 완료(ack) 걸러내기 (중복 제거) ~/.codex/state/self-improve-acks/{key}.json # 단서가 있으면 처리 대기 파일에 저장 ~/.codex/pending/self-improve-{key}.json # 후처리 (있으면 실행) rule-effectiveness-check.sh ← 규칙 효율성 검증 soft-to-hard-promoter.sh ← 권고(SOFT) 규칙을 강제(HARD) 규칙으로 승격
self-improve-worker.py — 수정을 실행하는 엔진이 시스템의 심장 격인 부분입니다. 실제로 언어 모델(AI)을 불러 개선 수정안을 만들고 적용합니다. 작업은 git worktree(원본 저장소를 건드리지 않도록 복제한 별도 폴더)에서 진행하므로 원본이 망가질 걱정이 없고, 실패하면 백업에서 자동으로 되돌립니다.
self-improve-worker.py run --project-root $ROOT │ ├── [재실행 대기] CODEX_SELF_IMPROVE_COOLDOWN_SECONDS=900 (15분) ├── [lock] ~/.codex/state/self-improve-workers/{key}.lock │ ├── load_pending() + unacked_signals() 아직 처리 안 한 단서만 걸러내기 │ ├── [격리된 작업 폴더] │ git worktree add --detach HEAD │ backup_codex() → temp/codex-backup/ │ ├── [언어 모델 호출] │ build_prompt(root, signals[:10], team_context) │ write_schema(output_schema.json) │ codex --model gpt-5.4 -o output.json < prompt │ ├── [결과 검증] │ patch_scope: ["project"] | ["codex"] | ["project","codex"] │ verification_checks: │ file_contains → 파일 내용 포함 여부 │ repo_script → .codex/autoresearch/*.sh 실행 │ codex_smoke → self-improve-smoke.sh │ git_diff_check → 바뀐 내용(diff) 확인 │ ├── [수정안 적용] │ patch_scope=["codex"] → ~/.codex/ 직접 수정 ✅ │ patch_scope=["project"] → 대기열에 저장 (저장소가 깨끗해야 적용) ⚠️ │ ├── self-improve-ack.sh ← 처리한 단서에 완료 표시(ack) ├── self-improve-smoke.sh ← 적용 후 기본 동작 점검 └── self-improve-log.sh ← 이력 기록
patch_scope=["project"]는 저장소가 깨끗한 상태, 즉 git status --porcelain 명령 결과가 비어 있어 아직 커밋하지 않은 변경이 하나도 없을 때만 곧바로 적용됩니다. 저장 안 된 변경이 남아 있으면 ~/.codex/state/self-improve-queues/{key}/ 폴더에 수정안 파일(.patch)로 대기시킵니다.
verify-l6.sh + adversarial-review-l6.py — 검증은 이 두 스크립트가 두 겹으로 맡습니다. 앞의 것은 숫자로 세는 검증입니다. 통과를 막는 결함이 몇 개 남았는지 셉니다. 뒤의 것은 내용을 트집 잡듯 따지는 비판적 리뷰(adversarial review)입니다. 두 검증 모두 결과를 사람도 프로그램도 읽을 수 있는 글자 기반 자료 형식으로 출력합니다. 감시 프로그램은 그 결과를 읽어 다음 단계로 넘어갈지 결정합니다. 그 자료 형식이 바로 JSON.
# verify-l6.sh — 통과를 막는 결함 개수 측정 필수 파일 17개 존재 확인: .codex/autoresearch/verify-l6.sh .codex/autoresearch/adversarial-review-l6.py .codex/scripts/session-start.sh .codex/scripts/memory-bank-session-end.sh .codex/scripts/self-improve-trigger.sh .codex/scripts/self-improve-check.sh .codex/scripts/self-improve-worker.py .codex/scripts/team-runtime.py .codex/scripts/loop-era-supervisor.py .codex/scripts/init-project-runtime.py .codex/scripts/qa-cycle-runtime.py .codex/scripts/check-recurrence.py .codex/scripts/install-git-hooks.sh .codex/skills/self-improve/SKILL.md .codex/skills/ralph-loop/SKILL.md .codex/skills/team/SKILL.md ... (+1 more) python3 -m py_compile × 10개 ← 파이썬 코드 문법 검사 bash -n × 4개 ← 배시 코드 문법 검사 self-improve-smoke.sh ← 통합 기본 점검 (건너뛸 수 있음) → {"metric": "l6_blocker_count", "value": N, "status": "pass/fail"} # adversarial-review-l6.py — 내용을 따지는 리뷰 필수 산출물이 있고 비어 있지 않은지 (10개) apply.sh / sync.sh에 자가개선 파일 동기화가 들어 있는지 self-improve-trigger.sh가 특정 AI(Claude)에 강하게 묶여 있는지 탐지 self-improve 설명서의 알림 경로가 올바른지 확인 self-improve-smoke.sh의 set +e / STATUS=$? / [STATUS -eq 1] 패턴 git 훅이 Codex 실행 단계로 이어지는지 여부 → {"blocker_count": N, "findings": [...], "status": "pass/fail"}
self-improve-smoke.sh는 코드 문법만 훑고 끝나지 않습니다. 진짜 임시 git 저장소를 하나 만들어, 전체 과정을 처음부터 끝까지 돌려 보는 통합 테스트까지 포함합니다.
TEST 01TEST 02codex-pre-submit-gate.py는 제출(submit) 직전에 금지된 지시가 섞였는지 검사해 막는 스크립트입니다. 임시 git 저장소에 "금지된 지시" 규칙을 넣고 이 스크립트를 돌려, 실제로 막히는지 확인합니다. "차단됨"을 뜻하는 STATUS=1이 나와야 통과입니다. 아래 결과 줄에서 앞 단어는 차단됨(blocked), 등호 뒤의 단어는 통과(pass)를 뜻합니다.→ blocked = PASSTEST 03TEST 04JSON 형식의 결과를 내는 검증·리뷰·상태, 세 구성요소를 동시에 실행해 봅니다. 그 결과에 꼭 필요한 항목이 들어 있는지 검사합니다. 상태 출력에 '[self-improve]'와 '[ralph-loop]' 표시가 제대로 붙는지도 확인합니다.TEST 05state.json은 반복 루프의 현재 상태와 단계 이력을 담는 상태 파일입니다. 임시 저장소를 만들어 반복 루프를 시작하고, 이 파일이 생기는지 확인한 뒤 중지합니다. 등록부터 취소까지 전체 흐름을 점검합니다.→ state.json createdTEST 06status=stale_running 즉 "멈춘 채 방치됨" 상태로 잡히는지 확인합니다. 이어서 되살리기를 시험 실행하면 running=False 상태로 정리됩니다.TEST 07status=backoff, last_result=escalation_required, disabled_until 같은 값이 설정돼, 잠시 물러나 쉬는 상태로 바뀌는지 확인합니다.TEST 08patch_scope=["codex"])은 곧바로 적용됩니다. 섞인 수정(["project","codex"])은 Codex 부분만 즉시 적용하고, 프로젝트 부분은 대기열에서 기다립니다.~/.codex/
├── state/
│ ├── loop-era-registry.json # 등록된 프로젝트 목록
│ ├── loop-era-projects/ # 프로젝트별 기록 파일 (.json)
│ ├── loop-era-locks/ # 프로세스 잠금 파일
│ ├── self-improve-workers/ # 작업 프로세스 상태 + 잠금
│ ├── self-improve-acks/ # 처리 완료(ack) 표시 상태
│ ├── self-improve-queues/ # 프로젝트 수정안 대기열
│ ├── loop-era-supervisor.pid # 감시 프로그램 프로세스 번호
│ └── loop-era-supervisor-heartbeat.json
├── pending/
│ └── self-improve-{key}.json # 아직 처리 안 한 단서 대기열
└── logs/
├── loop-era-supervisor.jsonl # 감시 프로그램 이벤트 기록
└── self-improve-runs.jsonl # 작업 프로세스 실행 이력
.codex/ (저장소 내부)
├── autoresearch/
│ ├── results.tsv # 채택/폐기 실험 결과
│ ├── verify-l6.sh # 통과를 막는 결함 측정
│ └── adversarial-review-l6.py # 내용을 따지는 리뷰
├── ralph-loop/
│ ├── state.json # 현재 루프 상태 + 단계 이력
│ └── team-execution-latest.json # 최근 팀 실행 결과
└── logs/
└── loop-era-metrics.jsonl # 지표 변화 기록
| 구성요소 | 완성도 | 비고 |
|---|---|---|
| 단서 수집 과정 | ✅ 100% | 단서 5종, 한국어 표현까지 인식 |
| 자동 수정 실행 | ✅ 100% | 격리 폴더, 백업·복구, 4종 검증 |
결함 개수 지표 (L6) | ✅ 100% | 숫자 기준으로 채택·폐기 판정 |
| 기본 동작 점검 장치 | ✅ 100% | 8가지 통합 테스트 자동화 |
| 감시 프로그램(상시) | ✅ 100% | 프로세스 번호, 자동 실행, 생존 신호, 멈춘 작업 복구 |
| 14단계 실행 순서 | ✅ 100% | 순서표대로 완전 구현 |
| git worktree 격리 | ✅ 100% | 복제(clone) 대체 경로 포함 |
| 처리 완료·실패 표시 체계 | ✅ 100% | 같은 단서를 두 번 처리하지 않음 |
| 프로젝트 파일 수정 적용 | ⚠️ 70% | 저장소가 깨끗해야 적용, 아니면 대기열 |
| 도구 간 동기화 | ⚠️ 60% | 동기화 도구 cc-sync의 두 스크립트에 의존 (적용용·동기화용: apply.sh · sync.sh) |
| 강제 규칙 자동 승격 | ⚠️ 70% | 승격 스크립트는 있지만 처리 깊이에 한계 |
start-harness.sh로 켜는 순간부터 14단계 실행 순서, 8가지 기본 동작 점검, 단서 5종 수집, 격리 폴더, 중복 처리 방지까지 매우 정교하게 짜여 있습니다.