이전 글에서 ECC 규칙셋을 전역 레이어로 깔았다. 규칙 파일이 에이전트의 행동 표준을 잡아줬다면, 이번 글은 그 위에 구체적인 파이프라인을 얹은 이야기다. Claude Code를 프로젝트 단위로 오래 쓰다 보면 반복되는 고통이 하나 있다. 세션마다 “플래닝 먼저 해줘, 테스트 먼저 작성해줘, 스프린트 계획 짜줘”를 처음부터 다시 꺼내야 한다는 것이다. Ultra Harness는 이 반복을 명령 하나로 압축하는 구조다.
왜 이런 하네스가 필요한가
Claude Code를 혼자 쓰면 세션마다 동작이 달라진다. 같은 기능 요청을 넣어도 어떤 세션은 PRD부터 시작하고, 어떤 세션은 바로 코드를 짠다. 에이전트를 불러야 할 시점을 매번 명시적으로 지시해야 하고, 스프린트 계획이 무엇인지 매번 설명해야 한다.
ECC 규칙셋이 표준(what)을 정했다면, Ultra Harness는 실행 동선(how)을 정한다. 두 가지를 분리한 이유는 하나다. 표준이 흔들리면 실행도 흔들리지만, 실행 동선이 없으면 표준이 있어도 매 세션마다 처음부터 다시 시작한다.
구체적으로 해결하려고 한 문제는 세 가지다.
- 일관성 부재: 같은 지시를 세션마다 반복하는 것
- 컨텍스트 손실: 스프린트 상태, 진행 중인 기능, QA 결과를 세션 간에 이어받지 못하는 것
- 에이전트 호출 타이밍: 언제 어떤 에이전트를 불러야 하는지 매번 판단해야 하는 것
에이전트 계층 구조
전체 16개 에이전트를 기획 → 구현 → QA → 메타 파이프라인으로 계층화했다.
기획 레이어 (4개)
| 에이전트 | 역할 |
|---|---|
| prd-writer | Product Requirements Document 초안 작성 |
| storyboard-creator | 사용자 흐름과 UI 스토리보드 설계 |
| feature-spec-writer | 기능 단위의 상세 스펙 문서 작성 |
| sprint-planner | 스프린트 목표, 태스크 분해, 일정 계획 |
플랫폼 전문 레이어 (5개)
| 에이전트 | 역할 |
|---|---|
| unity-specialist | Unity C# 구현, 엔진 특화 패턴 |
| flutter-specialist | Flutter/Dart 구현, 위젯 아키텍처 |
| react-specialist | React/Next.js 구현, 상태 관리 |
| server-specialist | 백엔드 API 설계 및 구현 |
| ddd-architect | 도메인 주도 설계, 바운디드 컨텍스트 |
클라우드/백엔드 레이어 (3개)
| 에이전트 | 역할 |
|---|---|
| firebase-specialist | Firebase 서비스 연동 및 보안 규칙 |
| supabase-specialist | Supabase DB, Auth, Edge Function |
| aws-specialist | AWS 인프라, IAM, CDK/Terraform |
QA 레이어 (2개)
| 에이전트 | 역할 |
|---|---|
| qa-specialist | 테스트 전략 수립, 커버리지 검증 |
| bug-hunter | 버그 재현, 원인 분석, 회귀 방지 |
메타 레이어 (2개)
| 에이전트 | 역할 |
|---|---|
| progress-tracker | 스프린트 진행 상황 추적, 상태 리포트 |
| agile-coach | 개발 프로세스 피드백, 회고 진행 |
계층 설계의 핵심 원칙은 단방향 의존이다. 기획이 완료되지 않으면 구현이 시작되지 않고, 구현이 완료되지 않으면 QA가 시작되지 않는다. 메타 레이어는 어느 단계에서든 횡단 관심사(진행 상황, 프로세스 품질)를 처리한다.
플랫폼 레이어의 에이전트들이 평행으로 존재하는 것도 의도적이다. unity-specialist와 flutter-specialist는 같은 프로젝트에서 각자의 도메인 안에서 독립적으로 작동할 수 있다. ddd-architect가 도메인 경계를 정하면, 각 플랫폼 에이전트는 그 경계 안에서 구현 결정을 내린다.
가장 유용한 기능 3가지
1. 커스텀 커맨드
6개 슬래시 커맨드로 복잡한 다단계 작업을 단일 진입점으로 압축했다.
/plan-project → prd-writer + storyboard-creator + sprint-planner 순차 실행
/new-feature → feature-spec-writer → 플랫폼 에이전트 → qa-specialist 파이프라인
/sprint-start → 현재 스프린트 목표 로드 + 태스크 브리핑
/sprint-review → 완료 항목 집계 + 미완료 원인 분석 + 다음 스프린트 시드
/qa-check → qa-specialist + bug-hunter 병렬 실행
/dev-status → progress-tracker 리포트 생성
커맨드 파일은 ~/.claude/commands/ 아래에 마크다운으로 정의한다. 각 파일이 어떤 에이전트를 어떤 순서로 호출하는지, 어떤 입력을 받아서 어떤 출력을 기대하는지를 명시한다. 사용자는 프롬프트를 길게 쓰는 대신 커맨드 하나를 부른다.
실제로 가장 많이 쓰는 것은 /new-feature다. 기능 이름 하나만 던지면 feature-spec-writer가 상세 스펙을 잡고, 그 스펙을 바탕으로 해당 플랫폼 에이전트가 구현에 들어간다. 중간에 아키텍처 결정이 필요하면 ddd-architect가 개입한다. 이 흐름 전체가 커맨드 하나에 묶여 있다.
2. Hook 시스템
두 개의 Hook 스크립트가 개발 중 발생할 수 있는 문제를 자동으로 차단하거나 리마인드한다.
harness-file-guard.sh — PreToolUse Hook으로 작동한다. Write 도구가 파일을 쓰기 직전에 줄 수를 체크해서 800줄을 초과하면 쓰기를 차단하고, 모듈 분리를 권고하는 에러 메시지를 출력한다.
# 핵심 로직 (예시 구조)
line_count=$(echo "$file_content" | wc -l)
if [ "$line_count" -gt 800 ]; then
echo "[harness-guard] BLOCKED: $line_count lines exceeds 800-line limit."
echo "[harness-guard] Split into smaller modules before writing."
exit 2
fi
이 Hook이 없으면 에이전트는 빠른 구현을 위해 파일 하나에 모든 로직을 욱여넣는 경향이 있다. 차단 자체보다 “이 파일이 800줄이 됐다”는 신호가 더 중요하다. 분리 타이밍을 잡아주는 것이다.
harness-dev-reminder.sh — PostToolUse Hook으로 작동한다. 사용자의 입력에 feature, implement, build, create 같은 개발 키워드가 감지되면, 현재 스프린트 규칙과 테스트 우선 원칙을 간략히 리마인드한다. 개발이 시작되기 직전, 에이전트가 컨텍스트를 다시 로드하도록 유도하는 작은 트리거다.
3. 규칙 파일 레이어
ECC common 규칙 위에 Ultra Harness 전용 규칙 파일이 얹혀 있다. 에이전트별 책임 범위, 레이어 간 커뮤니케이션 형식, 스프린트 문서의 저장 위치와 포맷을 정의한다.
~/.claude/
├── rules/
│ ├── common/ # ECC 공통 규칙
│ └── harness/ # Ultra Harness 전용
│ ├── agents.md # 16개 에이전트 정의 및 호출 조건
│ ├── pipeline.md # 기획→구현→QA 파이프라인 규칙
│ └── sprint.md # 스프린트 문서 포맷 및 저장 규칙
├── agents/ # 에이전트 정의 파일 (16개)
├── commands/ # 커맨드 정의 파일 (6개)
└── hooks/ # Hook 스크립트 (2개)
구축하다 발견한 패턴과 인사이트
에이전트는 좁을수록 잘 작동한다
unity-specialist를 만들 때 처음에는 Unity C# 전체를 다루도록 넓게 잡았다. 실제로 굴려보면 에이전트가 어떤 Unity 버전 규칙을 따라야 하는지, 2D인지 3D인지, URP인지 HDRP인지 판단을 내려야 하는 시점이 너무 많았다. 결국 에이전트 파일에 “이 에이전트는 이 범위에서만 결정을 내린다”는 명시적인 경계를 추가했을 때 응답이 훨씬 일관성 있어졌다.
에이전트의 책임 범위는 설명보다 경계 명시가 효과적이다.
커맨드는 기대 출력 형식이 핵심이다
/sprint-review 커맨드를 처음 만들었을 때 “스프린트를 리뷰해줘”라고만 썼다. 실제로 부르면 서술형 텍스트가 나왔고, 다음 스프린트에 재사용할 수 없는 형태였다. 커맨드 파일에 기대 출력 포맷(완료 태스크 목록, 미완료 원인 분류, 다음 스프린트 시드 목록)을 구체적으로 정의한 다음에야 실제로 재활용 가능한 출력이 나오기 시작했다.
커맨드의 품질은 프롬프트 길이가 아니라 기대 출력 명세의 구체성에 달려 있다.
Hook은 차단보다 타이밍 신호로 쓸 때 더 강력하다
harness-file-guard.sh가 처음에는 단순한 차단 도구였다. 그런데 차단 자체가 목적이 아니라는 것을 금방 깨달았다. 에이전트가 이미 800줄짜리 파일을 기획하고 절반쯤 썼을 때 차단하면 작업을 버리고 다시 시작해야 한다. 유용한 것은 파일이 커지기 시작하는 초기에 “지금 분리를 고려할 타이밍”이라는 신호를 주는 것이다. 그래서 실제로는 600줄을 넘는 시점에 경고를 한 번 보내고, 800줄에서 차단하는 이단계 방식이 더 낫다는 결론에 이르렀다.
설치 스크립트가 없으면 구조가 기억에만 남는다
전체 구성을 수동으로 설치하면 디렉터리 구조가 머릿속에서 점차 흐릿해진다. install.ps1(Windows)과 install.sh(macOS/Linux)로 ~/.claude/ 아래에 에이전트, 커맨드, Hook, 규칙 파일을 한 번에 배치하도록 만든 것이 결과적으로 가장 중요한 선택이었다. 새 환경에서 15초 만에 동일한 하네스를 복원할 수 있다는 것이 심리적으로 큰 차이를 만든다.
한계와 다음 단계
현재 한계
세션 간 상태 지속성이 없다. 스프린트 상태, 태스크 완료 여부, 버그 목록은 모두 파일로 저장하게 되어 있지만, Claude Code가 세션을 넘어 이 파일들을 자동으로 로드하지는 않는다. /sprint-start를 부를 때마다 “직전 스프린트 파일을 읽어줘”를 같이 넣어야 한다. 세션 간 컨텍스트 복원이 자동화되지 않은 것이 가장 큰 구조적 공백이다.
에이전트가 16개라는 것 자체가 부담이다. 기획 레이어 에이전트를 불러야 하는 상황인지, 플랫폼 에이전트를 바로 불러야 하는 상황인지 판단이 항상 명확하지는 않다. 커맨드가 이 판단을 대신해주지만, 커맨드에 맞지 않는 비정형 요청이 들어오면 다시 수동 판단이 필요하다.
Hook 스크립트가 Windows/macOS에서 다르게 작동한다. bash 기반 스크립트를 PowerShell에서 실행하면 동일한 동작을 보장하기 어렵다. install.ps1에서 Windows 환경의 Hook을 별도로 처리하고 있지만, 유지 관리 포인트가 두 배가 된다.
다음 단계
우선순위 1은 세션 간 컨텍스트 복원 자동화다. /sprint-start가 실행될 때 자동으로 직전 스프린트 문서를 로드하고, 열린 버그 목록과 미완료 태스크를 컨텍스트로 주입하는 흐름을 만드는 것이 목표다.
우선순위 2는 에이전트 수를 줄이는 것이다. 16개 중 실제로 자주 쓰이는 에이전트는 절반 정도다. 사용 빈도가 낮은 에이전트를 통합하거나 제거해서 정예 에이전트 8~10개로 줄이는 방향을 검토 중이다.
우선순위 3은 Hook의 크로스플랫폼 통일이다. Node.js 스크립트로 재작성하면 Windows와 macOS에서 동일한 동작을 보장할 수 있다.
에이전트와 커맨드와 Hook이 하나의 설치 스크립트로 묶이는 순간, Claude Code는 도구에서 팀원처럼 작동하기 시작한다.
댓글