Claude Code TDD 서브에이전트와 하네스 구축기 — 7개 에이전트, 18종 회귀 평가
들어가며
안녕하세요. 비브로스에서 백엔드 개발을 담당하고 있는 김예림입니다.
TDD 실무에서 사용한 경험이 있으신가요? 저는 거의 없습니다. 일정압박과 일단 처음의 요구사항이 그대로 유지된적이 거의 드물고 기획과 같이 개발을 하는 방향으로 많이 일했어서 그런지 TDD를 많이 써보지는 못했습니다.
AI와 함께 하는 지금, AI가 만든 결과물이 내가 요구한 테스트에 확실히 통과하는지에 대한 의문에 대한 해답과 테스트가 개발을 이끄는 구조는 분명 필요했고, 그 방식을 AI와 함께 일하는 환경에 맞게 다시 만들어보고 싶었습니다.
이 글은 Claude Code에 TDD를 붙여보겠다는 질문에서 시작해, 7개의 서브에이전트와 그 에이전트들을 검증·통제하는 하네스를 만든 기록입니다. CLAUDE.md 규칙과 Plan Mode를 보다가 서브에이전트로 넘어간 과정, refactorer와 orchestrator가 생긴 이유, 18종 회귀 평가·권한 훅·사이클 메타데이터로 만든 하네스, 그리고 YAML 파일을 import하여 가시성을 높인 대시보드 제작까지 제가 고민한 순서대로 정리했습니다.
1. 왜 TDD였나
왜 하필 TDD 였나에 대해서 얘기해보고자 합니다.
첫 번째는 AI를 실무에 적용하면서 반복해서 본 문제였습니다. Claude Code로 신규 기능을 개발하다 보면 비슷한 일이 자주 생겼습니다. "이거 구현해줘"라고 던지면 빠르게 코드가 나오긴 하는데, 막상 받아보면 엣지 케이스를 빠뜨려서 다시 요청하거나, 테스트가 코드를 따라가거나, "이참에 같이" 하면서 요청하지 않은 부분까지 손대기도 했습니다.
두 번째는 AI 시대에도 기존 방법론을 사용할 수 있는 방법이 있지않을지 고민이 많았습니다. 기존 방법론이 완전히 사라지는 게 아니라, AI와 함께 일하는 방식의 뿌리가 될 거라고 생각했습니다. TDD는 저의 게으름으로 방법론만 알고있었고 실무에서는 거의 써보지 못했었고 AI와 함께라면 쉽게 시작할 수 있을것같다고 생각이 들었습니다. 그래서 그 출발점으로 TDD를 도입해보고싶었습니다.
마지막은 QA를 통과한 기능에서 터진 엣지 케이스 버그였습니다. 분명 검증을 거쳤는데도, 운영에 올라가니 누구도 떠올리지 못한 조건 조합에서 문제가 터졌습니다. QA 이전, 개발 단계에서 최대한 촘촘하게 검증할 수 있는 구조가 필요하다는 생각이 강해졌습니다.
이런 고민을 안고 5월 초, Claude에게 질문을 던졌습니다.

Claude의 답변은 꽤 구체적이었습니다. 테크스펙 → 시나리오 설계 → (사람 검토) → 테스트 작성(Red) → 구현(Green → Refactor)이라는 4단계 흐름과 함께, 지금 돌아보면 세 가지 조언이 특히 남았습니다.
- 단계마다 멈추게 할 것 — 한 번에 다 시키면 시나리오가 얕아지고, 구현 편의 위주로 테스트가 맞춰진다.
- 가장 흔한 실패 모드는 테스트 수정 — Claude가 테스트를 통과 못 하면 종종 테스트 자체를 고치려 든다. "테스트 수정 금지"를 강하게 박고, git diff로 테스트 파일 변경 여부를 매 사이클 체크하라.
- 서브에이전트로 역할을 분리할 것 — 구현자가 테스트를 못 보게 하거나, 시나리오 단계에서 구현 디테일에 휘둘리지 않게 하는 효과가 있다.
저는 각 단계에 대한 서브에이전트를 제작하는 걸 먼저 시작했습니다. 왜 서브 에이전트 제작을 먼저 시작하게 되었는지 그 배경에 대해서 설명하고자 합니다.
2. 준비
Claude가 첫 답변에서 제안한 출발점은 다음 조합이었습니다.
- CLAUDE.md에 TDD 규칙 박아두기 — "테스트 작성 단계에서는 프로덕션 코드 수정 금지", "구현 단계에서는 테스트 코드 수정 금지", "커밋은 Red/Green/Refactor 단위로 분리" 같은 규칙을 프로젝트 루트에 명시해 매번 반복하지 않기
- Plan Mode 활용 — Shift+Tab으로 Plan Mode에 들어가 시나리오 설계를 하면 파일 수정 없이 계획만 세우니, 시나리오 검토 단계에 딱 맞음
- 한 사이클 예시 명령어 — "1단계: 시나리오 작성 후 멈춤 → (검토 후) 2단계: 테스트 작성, 모두 fail 확인 → 3단계: 구현" 식으로 단계 끝마다 멈추게 하는 프롬프 트
결론부터 말하면, 저는 이 조합을 채택하지 않았습니다. 규칙과 Plan Mode가 쓸모없어서가 아니라, 제가 만들고 싶은 컨셉과는 달랐기 때문입니다. 제가 원한 건 사용자가 매번 규칙을 기억하고 Plan Mode로 경계를 잡아주는 방식이 아니라, 역할과 권한이 구조적으로 분리되고 간섭하지 못하는 실행 환경이었습니다.
- CLAUDE.md 규칙은 약속이지 강제가 아닙니다. "구현 단계에서는 테스트 코드 수정 금지"라고 적을 수는 있지만, 실제로 수정 도구를 빼앗는 것은 아닙니다. 세션이 길어지거나 작업이 막히면 규칙은 쉽게 흐려질 수 있습니다.
- Plan Mode는 계획 단계의 경계만 만들어줍니다. "구현 전 계획"이라는 경계는 만들 수 있지만, 테스트 작성·구현·리뷰 단계 사이의 권한 분리는 해주지 못합니다. 모든 단계가 같은 컨텍스트에서 같은 도구를 쥐고 돌아갑니다.
- 사용자의 운영 부담이 남습니다. 단계 규칙·멈춤 지점·금지 사항을 사용자가 계속 기억하고, 매 사이클 프롬프트나 검토로 보완해야 합니다.
규칙을 "더 강하게 써붙이는" 방식은 제가 생각한 해결책이 아니었습니다. 다른 방법을 찾다가 Claude Code의 서브에이전트에 도달했습니다. 서브에이전트는 역할마다 격리된 컨텍스트에서 돌고, frontmatter의 tools:로 도구 자체를 제한합니다. "이 단계에서는 테스트를 수정하지 마"라고 채팅으로 부탁하는 대신, 수정 도구를 아예 주지 않는 구조를 만들었습니다.
컨텍스트가 격리되니 구현자가 시나리오 작성자의 고민에 끌려가는 일도 줄었습니다. 단계 규칙은 에이전트 정의 파일에 한 번 넣어두면 매 사이클 적용됩니다. CLAUDE.md+Plan Mode에서 아쉬웠던 부분이 이 방식으로 꽤 줄었고, 첫 대화에서 받아둔 역할별 md 파일을 .claude/agents/에 올려 본격적으로 다듬기 시작했습니다.
처음 만든 에이전트 정의는 그럴듯해 보였지만 실전에서는 곳곳에서 샜습니다. 한 달간 실제 기능 구현에 투입하면서 test-writer가 assertion을 빼먹고 끝내거나, 막히면 as any로 도망가거나, implementer가 요청하지 않은 마이그레이션을 자발적으로 만드는 식의 실패 패턴을 하나씩 만났습니다. 그때마다 해당 에이전트 정의 파일에 금지 규칙과 자가 점검을 넣었습니다. 운영하면서 발견한 실패 패턴을 정의 파일에 누적시키는 것, 이게 이 시기에 자리 잡은 핵심 운영 방식이었어요.
정의 파일이 어느 정도 안정되자 팀원들도 같은 흐름을 쓰면 좋겠다고 생각했습니다. 그래서 팀에서 같은 방식으로 설치하고 업데이트할 수 있도록 사내 플러그인에 적용하기로 했고, 결국 역할은 서브에이전트, 진입점·절차는 플러그인 스킬로 나눴습니다.
- 에이전트 (플러그인 네이티브) — 파이프라인의 실행 주체들. 플러그인을 설치하면 어느 프로젝트에서든 바로 호출되고, 정의 개선은
/plugin update로 전 프로젝트에 자동 전파됩니다. - 스킬 —
/tdd-pipeline:install(하네스 설치)과/tdd-pipeline:run(파이프라인 진행) 두 개. 사용자 진입점이자 절차 안내 역할입니다.
사실 첫 버전은 이 결론이 아니었습니다. 처음에는 인스톨러 스킬이 에이전트 정의를 각 프로젝트의 .claude/agents/로 복사하는 구조였어요. 그런데 운영해보니 비효율적이다고 생 각이 들었어요.
거의 보통 에이전트 파일을 프로젝트별로 커스텀하며 수정하진 않을거라 생각이 들었습니다. 그리고 플러그인에서 정의를 개선해도 이미 설치된 프로젝트에는 전파되지 않고, 프로젝트마다 서로 다른 버전의 에이전트가 돌게 됐습니다. 그래서 에이전트를 플러그인 루트 agents/로 옮겨 네이티브 로드되게 바꿨고, 인스톨러는 "프로젝트별 측정 상태"인 하네스만 설치하도록 역할을 좁혔습니다.
전역으로 관리해야 하는 것(에이전트 정의)과 프로젝트에 누적되어야 하는 것(평가 결과·사이클 데이터)을 분리한다는 구분이 이 플러그인 구조의 뼈대가 됐습니다.
| 구분 | 정리 |
|---|---|
| 플러그인 네이티브(전역) | 에이전트 7개와 /tdd-pipeline:install, /tdd-pipeline:run 스킬을 둡니다. 정의 개선이 모든 프로젝트에 전파되어야 하므로, 에이전트 정의는 복사하지 않고 플러그인에서 직접 로드합니다. |
| 프로젝트별 하네스(로컬) | 회귀 평가, 권한 정책, 훅 설정, 사이클 메타데이터, 대시보드를 둡니다. 테스트 명령, 실패 이력, 누적 사이클은 프로젝트마다 다르므로 로컬 상태로 누적합니다. |
라우팅도 같은 원리로 정리했습니다. 예전에는 자동 발동을 막으려고 각 프로젝트 CLAUDE.md에 라우팅 규칙을 박아 넣었는데, 이제는 각 에이전트의 description frontmatter에 부정 지시문을 내장해 CLAUDE.md를 건드리지 않게 했습니다.
아직은 모든 프로젝트 진행 시 필수로 TDD를 사용할게 아니라서요.
description: MUST ONLY be invoked when the user explicitly requests TDD
workflow or directly mentions this agent by name. DO NOT auto-invoke for
general implementation, bug fixes, or refactoring tasks.
3. TDD 파이프라인 구성
한 달 동안 굴려보 며 파이프라인은 5단계로 굳어졌습니다.
| 단계 | 역할과 산출물 |
|---|---|
1. test-scenario-designer | 테크스펙을 TC ID, Given-When-Then, Priority가 있는 시나리오 명세로 나눕니다. 산출물은 tests/scenarios/*.md입니다. |
2. test-writer | 시나리오를 실패 테스트(Red)로 옮기고, 필요한 경우 최소 스텁만 만듭니다. |
3. implementer | 테스트를 통과시키는 프로덕션 코드(Green)를 작성합니다. |
4. code-reviewer | 시나리오 기준 준수 여부와 코드 품질을 검증하고 리뷰 보고서를 남깁니다. |
5*. refactorer | 외부 동작을 유지하면서 구조를 정리합니다. 선택 호출 단계입니다. |
*5단계는 선택 호출입니다.
| 전환 지점 | 확인 기준 |
|---|---|
| 시나리오 → 테스트 | 사람은 요구사항이 충분히 쪼개졌는지 보고, orchestrator는 시나리오 파일·필수 형식·미해결 질문 여부를 확인합니다. |
| 테스트 → 구현 | 사람은 실패가 의도한 Red인지 보고, orchestrator는 assertion 실패와 테스트 본문 존재를 확인합니다. |
| 구현 → 리뷰 | 사람은 구현 범위를 보고, orchestrator는 테스트 통과·테스트 파일 무결성·금지 경로 변경 여부를 확인합니다. |
| 리뷰 → 리팩터링 | 사람은 구조 개선 필요성을 보고, orchestrator는 Critical/High 지적·트리거 A-E 문서화·Green 상태를 확인합니다. |
시나리오는 TC ID + Given-When-Then + Priority를 필수 형식으로 잡았습니다.
초기에는 형식을 강제하지 않았더니 triggerDay=25, now=5/24 23:59 → endDate=5/31 같은 한 줄 화살표 압축 시나리오가 나왔습니다. 작성한 에이전트 본인에게만 명확한 노트일 뿐, test-writer는 의도를 추측해야 했고 사용자가 검토할때도 직관적이지 않았어요. 시나리오가 얕으면 그 뒤에 단계들이 제대로 동작하지 않을 것 같았습니다.
형식을 필수로 강제하자 후속 단계의 막힘이 거의 사라졌습니다. 각 단계 사이에는 사람의 검토 지점이 있습니다.
더 중요한 건 단계가 아니라 권한 매트릭스였습니다.
test-writer가 구현 코드를 못 만지니 테스트가 구현에 끌려가지 않고, implementer가 테스트를 못 만지니 "통과시키려고 테스트를 바꾸는" 안티패턴을 막을 수 있습니다. 모든 에이전트가 스키마/설정을 못 만지니 자발적 마이그레이션 같은 침습 변경도 막힙니다. 플러그인화하면서 이 격리는 두 층이 됐습니다.
- 에이전트 도구 권한 (
tools:frontmatter) — 에이전트와 함께 따라다니므로 어느 프로젝트에서든 유지 - 경로 기반 hard 차단 (
PreToolUse훅 +permissions.yaml) — 하네스를 설치한 프로젝트에서만 동작. 에이전트가 금지된 경로에 Edit/Write를 시도하면 훅이 호출 자체를 차단
자연어로 부르면("test-writer로 실패 테스트 작성해줘") description 트리거에 잡히고, 명시적으로 부를 때는 @agent-tdd-pipeline:test-writer 형식의 at-mention을 씁니다.
4. refactorer의 탄생 — 다섯 번째 에이전트
원래 파이프라인은 4단계였습니다.
사이클을 여러 번 돌리고 코드를 천천히 보니, 테스트는 다 통과하는데 코드가 어수선했습니다. 비슷한 검증 로직이 서너 곳에 복붙되어 있고, 데이터 클래스 필드가 외부에서 직접 조작되고, 한 클래스가 도메인 로직과 영속성과 알림을 다 들고 있었습니다. 원인은 명확했습니다. implementer의 목표는 "테스트 통과"라서 Green이 되면 거기서 멈춥니다. TDD의 정석은 Red → Green → Refactor인데 마지막이 생략되고 있던 거예요.
implementer에게 "Refactor도 해줘"라고 시켜봤지만 기능 구현에 정신이 팔려 변수명 정리 수준에 그쳤습니다. 한 에이전트가 두 역할을 겸하면 자기 편한 쪽으로 균형이 무너집니다. 그래서 분리했습니다.
refactorer에는 사용자가 원하는 리팩터링 범위를 잡아주는 역할도 넣었습니다. implementer는 테스트 통과에 최적화되어 있어서, "여기까지 구조를 정리하고 싶다"는 사용자의 리팩터링 범위를 잘 잡지 못했습니다. refactorer는 새 기능을 구현하는 에이전트가 아니라, 사용자가 원하는 구조 개선 범위를 제안하고 그 범위 안에서만 코드를 정리하는 역할로 만들었습니다.
- 핵심 작업: 캡슐화, 단일 책임 원칙(SRP), 관심사 분리 -> 이 구조적 개선이 0건이면 호출 자체를 거절
- 절대 금지: 새 기능 추가(implementer 영역), 외부 인터페이스 변경(회귀 위험), 테스트 파일 수정(test-writer 영역)
- 전제 조건: 테스트가 전부 Green인 상태에서만 시작, 작업 내내 Green 유지
다만 매 사이클 자동 실행하지는 않고, 다섯 가지 트리거 중 하나일 때만 명시적으로 호출합니다.
| 트리거 | 상황 |
|---|---|
| A | code-reviewer가 P3 이상 구조 개선 항목 지적 |
| B | 한 모듈에서 사이클 3회 이상 누적 |
| C | implementer가 구조 개선 후보를 보고 |
| D | 다음 기능 추가 전 사전 정지 작업 필요 |
| E | 사용자가 코드를 보고 정리 필요성 인지 |
리팩터링은 누적될 때 가치가 큽니다. 한 사이클로는 중복이 잘 안 보이고 3~5 사이클이 쌓여야 패턴이 보여요. 매번 호출하면 PR diff만 폭증합니다. 이 기준은 나중에 orchestrator를 설계할 때도 그대로 가져갔는데, 그 이야기는 8번 섹션에서 이어서 이야기해보겠습니다.
5. 에이전트 하네스 구성
에이전트 정의를 잘 쓰는 것까지 왔으니, 이번엔 그 정의가 실제로 지켜지는지 확인할 차례였습니다. 운영하며 발견한 실패 패턴들은 전부 에이전트 정의 보강으로 해결했는데, 한 가지 불안이 남았거든요. 정의 파일을 고칠 때마다, 이전에 잡은 문제가 재발생하는지 누가 확인해주지?
사람이 매번 확인할 수는 없어서 자동화했습니다. 플러그인의 /tdd-pipeline:install로 프로젝트에 깔리는 하네스에는 네 가지를 넣었습니다.
① 회귀 평가 세트 (.claude/harness/evals/) — 발견한 실패 패턴 하나하나를 grader.sh로 자동 채점되는 평가로 만들었습니다. 처음 9종으로 시작해 지금은 18종입니다. 몇 가지만 추리면:
| ID | 검출 대상 |
|---|---|
| eval-001 | test-writer가 assertion 누락한 테스트를 작성 |
| eval-002 | as any / @ts-ignore 타입 우회 |
| eval-004 | implementer의 자발적 마이그레이션 |
| eval-006 | implementer/refactorer의 테스트 파일 수정 |
| eval-007 | 시나리오의 화살표 압축 표현 |
| eval-009 | 메타 에이전 트가 자기 자신을 수정 가능하게 정의됨 |
| eval-010 | 라우팅 규칙의 오탐/미탐 (발화 코퍼스 기반) |
| eval-018 | orchestrator의 read-only/evidence-gated 원칙 위반 |
② 자동 실행 훅 (SubagentStop) — 평가 세트가 있어도 사람이 돌려야 하면 안 돌립니다. 그래서 TDD 에이전트가 한 단계를 끝낼 때마다 훅이 발동해, 그 단계에 매핑된 평가만 자동 실행합니다. test-writer가 끝나면 eval-001/002, implementer가 끝나면 eval-004/005/006이 도는 식이에요. 결과는 UI에 한 줄로 보고됩니다.
✅ implementer done — evals: 5 pass / 0 skip → cycle-current.yaml
③ 권한 정책 파일 (permissions.yaml) — 마크다운에 자연어로 흩어져 있던 권한을 구조화된 정책으로 분리하고, PreToolUse 훅이 이 정책 기준으로 금지 경로 쓰기를 차단합니다. 에이전트 정의는 "무엇을 하는지(intent)"에 집중하고, 정책 파일이 "할 수 있는 일(authority)"을 관리합니다.
④ 사이클 메타데이터 (cycles/*.yaml) — 매 사이클의 단계별 메트릭(assertion 커버리지, 1차 Green 여부, 범위 위반 수, 리뷰 Critical/High 건수…)을 훅이 YAML에 누적합니다. 이 데이터가 쌓이면 "정의 보강 전후 비교"를 감으로 하지 않아도 되고, refactorer 트리거 B(모듈 사이클 3회 누적) 같은 판단도 자동으로 잡아낼 수 있습니다.
| 자동화 | 하는 일 |
|---|---|
PreToolUse 훅 | 에이전트 작업 중 Edit/Write 호출마다 permissions.yaml을 검사하고 금지 경로 쓰기를 차단합니다. |
SubagentStop 훅 | 에이전트 종료 직후 방금 끝난 에이전트를 식별하고, 단계에 매핑된 회귀 평가만 실행합니다. |
cycle-current.yaml 갱신 | 평가 이후 메트릭, 평가 결과, 정책 위반 내역을 단계별로 누적합니다. |
| 대시보드 갱신 | 사이클 상태가 바뀌면 cycles/*.yaml을 읽어 data.js를 다시 만들고 대시보드 경로를 안내합니다. |
여기서 하나 더 정한 게 있습니다. 에이전트는 플러그인 네이티브로 전역화했지만 하네스는 프로젝트별 설치로 남겼습니다.
평가 결과와 사이클 데이터는 그 프로젝트의 측정 상태이기 때문입니다. 코드베이스마다 테스트 명령이 다르고(언어별 profile로 해소), 누적 사이클 수가 다르고, 실패 이력도 다릅니다. 전역으로 진화할 것과 로컬에 쌓일 것을 섞으면 둘 다 망가져요.
한계도 있습니다. PreToolUse 차단은 Edit/Write 계열 도구만 매치하므로, 테스트 실행을 위해 Bash를 쥔 에이전트가 sed -i 같은 셸 경유로 쓰는 경로는 막지 못합니다. 이 부분은 의도적으로 받아들인 트레이드오프이고, 위반 여부는 사후 검증(eval-006의 테스트 무결성 검사)으로 잡습니다.
6. 참고한 글 — 하네스 엔지니어링을 접목하기로 하다
회귀 평가와 훅을 만들던 무렵, 이 방향이 맞는지 확신이 없어서 관련 자료를 찾아 읽었습니다. 에이전트 정의에 규칙을 누적시키는 것까지는 경험으로 왔는데, 그걸 검증/자동화하는 건 어디까지 갖춰야 하는지 기준이 없었거든요. 그러다 Anthropic이 정리한 에이전트 하네스(Agent Harness) 와 하네스 엔지니어링 자료를 만났습니다. 특히 이 문장이 우리가 반복해서 만나면서도 한 문장으로 정리하지 못했던 문제를 정확히 짚고 있었어요.
"단일 에이전트 시스템의 핵심 실패 모드는 객관적 자기 인식의 결여이다. 자기 작업을 평가하라고 하면 AI 모델은 병적인 낙관론자가 된다." — Anthropic, Harness design for long-running application development (2026)
implementer가 Green에 만족해버린 것도, test-writer가 자기 assertion 누락을 못 보는 것도, 시나리오 작성자가 자기 압축 표현이 명확하다고 착각한 것도 — 전부 이 실패 모드의 사례였습니다. 글에서 제시한 원칙들을 우리 상황에 하나씩 대보니, 충분히 가져와볼 만하겠다 싶었습니다. 그래서 이 글을 기준 삼아 파이프라인을 점검·보강했습니다.
| 하네스 엔지니어링 원칙 | 어떻게 접목했나 |
|---|---|
| 평가자/생성자 분리 | implementer ↔ code-reviewer 분리를 유지하고, 단계 전환 판정의 분리는 이후 orchestrator로 확장 (8장) |
| 작업자 ≠ 판단자 | refactorer ↔ code-reviewer 분리 |
| 구조화된 권한 시스템 | 마크다운에 자연어로 흩어져 있던 권한을 permissions.yaml 정책 파일로 분리 |
| 결정론적 검증 | grader.sh 자동 채점, grep 자가 점검을 평가 세트의 표준으로 |
| 회복 디시플린 | "막혔을 때 보고 형식"을 전 에이전트 공통 규칙으로 |
일부는 이미 비슷한 방향으로 가고 있던 항목이라 기준을 맞추는 정도였고, 일부는 이 글을 읽지 않았다면 시도하지 않았을 일입니다. 가장 크게 달라진 건 누적 데이터를 분석해 에이전트 정의 개선을 제안하는 메타 역할이었어요. 정성적으로 "이 정의 좀 고쳐야겠는데"라고 느끼던 일을 체계로 만들 수 있겠다 싶어, 여섯 번째 에이전트인 harness-optimizer를 만들었습니다. 사이클 메타데이터·리뷰 보고서·평가 실행 결과·에이전트 정의 본문 4종을 읽고, 반복 실패 패턴을 찾아 정의 보강·신규 평가·메트릭 조정·정의 정리(비대해진 규칙 다이어트)를 제안합니다.
단, 이 메타 에이전트에는 다른 에이전트보다 강한 규칙을 채웠습니다.
- 제안 우선: 기본 산출물은 제안서 보고서이고, 사용자가 항목 ID를 지정해 승인할 때만 적용. 묶음 승인("다 적용")도 거절하고 항목별로 재확인
- 자기 수정 금지:
harness-optimizer.md자신에 대한 Edit/Write는 어떤 경우에도 금지 (메타 루프 방지 — eval-009가 이 원칙 자체를 검증) - 표본 기반 일반화: 단일 사이클 실패를 정의 변경 근거로 쓰지 않음. 같은 패턴 3회 이상 반복일 때만 후보
사이클 바깥에서 사이클을 개선하는 에이전트까지 생기자, "운영 중 발견한 실패 패턴을 정의에 누적시킨다"는 초기 운영 방식도 시스템 안에서 돌아가기 시작했습니다.
7. 대시보드의 탄생
하네스가 돌기 시작하니 새로운 불편이 생겼습니다. 사이클이 끝날 때마다 cycles/cycle-001-payment.yaml 같은 파일이 쌓이는데, 그 안에는 단계별 메트릭, 평가 결과, 정책 위반, 리뷰 검출 건수까지 다 들어 있습니다. 문제는 그걸 보려면 YAML을 눈으로 파싱해야 한다는 점이었습니다. 들여쓰기 속에서 first_attempt_green: true를 찾고, 사이클끼리 비교하려면 파일 두 개를 나란히 열어 스크롤하고… 데이터는 쌓이는데 가시성이 없으니 아무도 안 보게 됩니다. 쌓아놓고 안 열어보면 안 쌓은 것과 다를 게 없었습니다.
그래서 단일 HTML 대시보드를 만들었습니다.
- 서버 없음 —
index.html하나를 브라우저로 열면 끝. - 자동 로드 — 에이전트가 단계를 끝낼 때마다
SubagentStop훅이 사이클 스냅샷을data.js로 구워 넣고, 상태 메시지에 대시보드 경로를 함께 출력
✅ implementer done — evals: 5 pass / 1 skip → cycle-current.yaml
— 📊 대시보드: file://.../dashboard/index.html
화면은 두 축으로 나눴습니다.
사이클 상세에서는 scenario → test → implement → review → refactor 5단계 흐름을 단계 상태별 색으로 보여주고, 단계를 클릭하면 메트릭 표(목표 대비 자동 색상 채점 — 충족 🟢 / 미달 🔴), 평가 배지, 정책 위반, 산출물 링크가 나옵니다.
리뷰 보고서 마크다운은 대시보드 안에서 바로 렌더링해서 검출 내용을 읽을 수 있게 했습니다.
누적 대시보드에서는 총 사이클·성공률·1차 Green율·평가 통과율 같은 KPI와 추세 차트를 보여주고, 모듈별 누적 사이클이 임계값 3에 도달하면 해당 모듈을 임계값 도달로 강조합니다.


샘플 사이클 4개를 넣고 캡처한 실제 화면입니다. 누적 뷰에서 src/coupon/issue 모듈이 사이클 3회에 도달해 빨갛게 표시된 것이 refactorer 트리거 B입니다.
만들어놓고 보니 대시보드는 단순 시각화 도구가 아니라 제가 운영 판단을 할 때 먼저 여는 화면이었습니다. "이 모듈 리팩터링 들어갈 때가 됐나?"를 YAML을 뒤져 판단하던 일이, 빨간 배지를 보고 판단하는 일로 바뀌었습니다.
8. orchestrator의 탄생 — TDD 모든 단계를 자동으로 돌리고 싶다
여기까지 갖추고 나니 이번엔 운영하는 제가 병목이 됐습니다. 시나리오가 끝나면 제가 test-writer를 호출하고, Red를 확인하면 제가 implementer를 호출하고… 단계 전환마다 사람이 다음 호출을 직접 타이핑해야 했어요. 단계 산출물이 명확하니 판단 자체는 어렵지 않은데, 그 반복이 번거로웠습니다. 그래서 욕심이 생겼습니다. "시나리오부터 리뷰까지, TDD의 모든 단계를 알아서 돌게 할 수 없을까?"
orchestrator를 만들기 전에, 훅이나 스킬만으로 자동 루프를 돌리는 방식도 생각해봤습니다. 하지만 그렇게 만들면 각 에이전트의 자기 보고를 그대로 믿고 다음 단계로 넘기게 됩니다. 그 순간 시스템 전체가 병적인 낙관론자처럼 동작할 수 있다는 점이 가장 걱정됐습니다.
자동으로 돌리려면 전제가 하나 필요합니다. "이 단계가 진짜 끝났는가"를 사람 대신 누군가 판정해야 해요.
그 판정을 각 에이전트의 자기 보고에 맡기면 어떻게 될까요.
test-writer가 "Red 확인했습니다"라고 보고했는데 그 Red가 assertion 실패가 아니라 컴파일 에러였다면? implementer가 "전부 Green입니다"라고 했는데 사실 테스트 파일이 살짝 수정되어 있었다면? 6장의 인용을 다시 떠올리면, 에이전트는 병적인 낙관론자입니다. 자기 보고만 믿고 단계를 자동 전환하는 순간, 권한 분리로 막아놓은 자기 평가 문제가 단계 전환 지점에서 되살아납니다. 잘못된 보고 하나가 검증 없이 다음 단계로 흘러가는 컨베이어 벨트가 되고 맙니다.
그래서 자동화의 기준을 바꿨습니다. "다음 단계로 그냥 넘기는 자동화"가 아니라, 증거를 검증한 다음에만 넘기는 자동화입니다. 그 판정을 맡길 일곱 번째 에이전트로 orchestrator를 추가했습니다. 이름과 달리 이 에이전트는 파이프라인 단계를 직접 실행하지 않습니다. 정확히는 실행하지 못하게 했습니다.
- read-only — 도구가 Read/Glob/Grep/Bash뿐. 보고서조차 파일로 쓰지 않음
- 자기 보고 불신 — 다른 에이전트의 요약은 "주장"으로 취급하고, 파일·명령 실행 결과·사이클 메타데이터로 직접 검증
- 자동 연쇄 금지 — 다음
@agent-tdd-pipeline:<name>호출을 딱 하나 추천하고 게이트에서 멈춤
orchestrator는 6개의 evidence gate로 판정합니다.
- Scenario gate(TC ID·Given/When/Then 존재)
- Red gate(assertion 실패로 인한 fail인지: 컴파일 에러는 차단)
- Green gate(테스트 통과 + 테스트 파일 무결성)
- Review gate(추적 매트릭스와 판정 존재: "looks good"만 있는 리뷰는 차단)
- Refactor gate(Green 상태 + 트리거 A~E 문서화)
- Completion gate
증거가 없거나 자기 보고뿐이면 다음 단계로 넘기지 않고 이렇게 보고합니다.
## Orchestrator Verdict
State: needs_implementation
Gate status: pass
Evidence:
- tests/scenarios/payment-scenarios.md: TC ID 42건, Given/When/Then 완비
- `npm test` 출력: 42 failed (assertion failure, not compile error)
Next action:
@agent-tdd-pipeline:implementer
Make the verified failing tests pass with the minimum production-code change. ...
| Gate | 확인 기준 |
|---|---|
| Scenario | TC ID, Given/When/Then, Priority가 갖춰진 시나리오 파일이 있어야 합니다. 모호한 Then 절, 미해결 질문, 누락된 테스트 대상이 있으면 차단합니다. |
| Red | 테스트 명령이 assertion 실패로 fail하고 assertion이 실제로 존재해야 합니다. 컴파일/설정 오류로 인한 fail이나 assertion 없는 false green은 차단합니다. |
| Green | 테스트 통과와 테스트 파일 무결성이 함께 확인되어야 합니다. implementer의 테스트 변경이나 스펙 밖 스키마/설정 변경은 차단합니다. |
| Review | 스펙·시나리오·구현 추적 매트릭스와 명시적 판정이 있어야 합니다. "looks good" 수준의 리뷰나 Critical/High 미해결은 차단합니다. |
| Refactor | Green 상태와 트리거 A-E 중 하나가 문서화되어야 합니다. 구조 개선 근거가 없거나 외부 동작 변경 위험이 있으면 차단합니다. |
| Completion | 모든 이전 gate 증거와 refactor 결정 기록이 있어야 합니다. 자기 보고에만 근거한 완료 주장은 차단합니다. |
사용자 진입점은 /tdd-pipeline:run docs/specs/<기능명>.md 스킬입니다.
테크스펙 경로 하나를 주면 orchestrator가 현재 상태를 판정하고, 게이트를 통과한 다음 단계를 이어갑니다. 다만 무조건 끝까지 달리는 루프는 아닙니다. 게이트마다 증거를 검증하고, 증거가 부족하면 거기서 멈춰 사람에게 돌아옵니다.
사이클 완료 시점에도 조용히 닫지 않고 "refactor 단계를 실행할까요?"를 사용자에게 묻습니다. 4번 섹션에서 본 "선택적 5단계"의 결정권은 끝까지 사람에게 남겨둡니다. 결정은 사이클 파일에 기록해(user_decision: approved_by_user / skipped_by_user) 재실행 시 같은 질문을 반복하지 않습니다. 이제 사람이 매 단계 호출을 타이핑하지 않아도 됩니다. 대신 증거 없는 전환도 끼어들지 못합니다.
orchestrator 자신도 검증 대상입니다. eval-018이 "orchestrator가 read-only/evidence-gated 원칙을 지키는지"를 채점합니다. 게이트 지킴이도 예외로 두지 않는 쪽을 택했습니다.
이렇게 해서 에이전트는 총 7개가 됐습니다. 실행자 5(scenario/test/implement/review/refactor) + 판정자 1(orchestrator) + 메타 1(harness-optimizer).
9. 앞으로 남은 일
여기까지가 질문 하나에서 출발해 한 달여 만에 플러그인이 된 과정입니다. 아직 숙제도 남아 있습니다.
정의 경량화. 실패 패턴을 누적시키다 보면 정의 파일이 계속 커집니다. refactorer 정의는 이미 600줄에 육박해요. 규칙이 늘수록 토큰 비용이 늘고, 모델이 정작 중요한 규칙을 놓칠 위험도 커집니다. 다행히 해법의 절반은 이미 시스템 안에 있습니다. harness-optimizer의 "정의 정리" 카테고리가 위반 사례 없는 묵은 규칙과 중복 규칙을 식별해줍니다. 사이클 데이터가 더 쌓이면 "이 규칙은 최근 N사이클 동안 한 번도 위반되지 않았으니 빼자"를 데이터 기반으로 결정할 수 있을 거예요.
Bash 우회 경로 보완. 경로 기반 차 단이 셸 경유 쓰기를 막지 못하는 한계는 현재 사후 탐지로 메우고 있는데, 훅 레벨에서 더 촘촘하게 막을 방법을 찾는 중입니다.
데이터가 쌓인 뒤의 자동화. 메트릭 임계값 조정, refactorer 트리거의 자동 권장, harness-optimizer 정기 점검(사이클 10건 누적 시) 같은 항목은 설계해뒀지만 아직 표본이 더 필요합니다.
팀 확산과 다언어 검증. TypeScript/Jest 중심으로 다듬어진 프로파일을 Kotlin/JUnit, Python/pytest, Go 프로젝트에서 검증하는 일,
그리고 팀원들의 사이클 데이터가 쌓이면서 나올 새로운 실패 패턴을 받아내는 일이 남아 있습니다. 어쩌면 그게 다음 남은 과제가 되겠네요.
마무리
이 과정에서 가장 먼저 자리 잡은 건 실패 패턴을 정의 파일에 누적하고 다시 반영하는 방식이었습니다. 나머지는 그 위에서 하나씩 생겼습니다. 대시보드는 제가 편하게 보고 싶어서, 하네스는 이 방식에 접목할 수 있을 것 같아서, orchestrator는 자동 루프를 관할할 리더 에이전트가 필요해서요. 결국 필요해서 하나씩 만든 것들이었습니다.
뒤돌아보니 한 문장으로 정리됩니다. 에이전트의 자기 보고를 믿지 말 것. 권한 매트릭스도, 회귀 평가도, evidence gate도, 자기 수정이 금지된 메타 에이전트도 결국 이 원칙의 다른 표현이었습니다.
참고 자료
- Harness design for long-running application development — Anthropic Engineering. 6장에서 인용한 글. planner/generator/evaluator 3-agent 하네스와 "자기 작업을 평가하는 에이전트는 낙관론자가 된다"는 통찰의 출처
- Effective harnesses for long-running agents — Anthropic Engineering. 장시간 자율 에이전트를 위한 하네스 설계 일반론
- Claude Code 공식 문서 — Subagents — 격리 컨텍스트·
tools:제한 등 2~3장에서 활용한 서브에이전트 메커니즘 - Claude Code 공식 문서 — Plugins — 플러그인 구조(
agents/,skills/,hooks/)와 배포 방식 - Claude Code 공식 문서 — Skills —
/tdd-pipeline:install·run같은 스킬 작성 방법 - Claude Code 공식 문서 — Hooks reference — 5장 하네스 자동화에 사용한
SubagentStop·PreToolUse훅 명세
