코드 한 줄 짜는 데 AI를 쓰는 시대는 지났다. 이제는 에이전트가 스스로 테스트를 실행하고, 실패 로그를 읽고, 수정안을 제시하는 단계까지 왔다. 이 글은 Claude Code를 단순 채팅 도구가 아니라 자율 검증 엔진으로 전환하는 과정을 직접 구축한 경험 기반으로 정리한다. CI/CD 연동까지 실제 작동하는 파이프라인을 만들고 싶은 개발자라면 바로 적용 가능한 내용이다.
1. CLAUDE.md — 에이전트의 판단 기준을 심는 파일
처음 Claude Code를 프로젝트에 붙였을 때 가장 먼저 경험한 문제는 컨텍스트 오해였다. 같은 함수명이 다른 모듈에서 다른 의미로 쓰이는 상황에서 에이전트가 잘못된 구현을 반복해서 제안했다. 수동으로 매번 설명을 추가하는 건 한계가 있었다.
해결책은 CLAUDE.md 파일을 프로젝트 루트에 두는 것이었다. 이 파일은 에이전트가 프로젝트를 시작할 때 가장 먼저 읽는 설계도 역할을 한다.
# 프로젝트 컨텍스트
## 아키텍처 원칙
- 모든 비즈니스 로직은 `src/domain/` 하위에만 작성
- `src/api/`는 라우팅과 직렬화만 담당, 로직 포함 금지
- 외부 의존성은 반드시 인터페이스로 추상화
## 테스트 실행
- 단위 테스트: `npm test -- --testPathPattern=unit`
- 통합 테스트: `npm test -- --testPathPattern=integration`
- 커버리지 확인: `npm run test:coverage`
## 코딩 컨벤션
- 함수명: camelCase, 동사 시작 (fetchUser, validateOrder)
- 에러 처리: try-catch 금지, Result 타입 사용
- 주석: 왜(why)만 작성, 무엇(what)은 코드로 표현
이 파일 하나로 에이전트의 엉뚱한 제안 빈도가 눈에 띄게 줄었다. 특히 아키텍처 제약을 명시한 뒤로는 Claude가 src/api/ 안에 비즈니스 로직을 섞는 실수를 스스로 피하기 시작했다.
2. Plan-Execute-Verify 루프 — 스스로 고치는 에이전트
단순히 "이 기능 만들어줘"라고 시키는 건 가장 낮은 단계의 활용이다. 진짜 자동화는 에이전트가 테스트를 먼저 작성하고, 실패 로그를 읽고, 스스로 수정하는 루프를 도는 구조다.
내가 실제로 사용하는 프롬프트 패턴은 다음과 같다.
역할: 너는 TDD 방식으로 개발하는 시니어 엔지니어다.
작업 순서:
1. 요구사항을 분석하고 테스트 케이스를 먼저 작성해라
2. `npm test` 를 실행하고 결과를 확인해라
3. 테스트가 실패하면 에러 메시지를 분석하고 구현 코드를 수정해라
4. 모든 테스트가 통과할 때까지 2-3을 반복해라
5. 통과 후 커버리지 리포트를 확인하고 미달 영역을 보완해라
요구사항: [여기에 기능 명세]
실제 실패 케이스를 보면 이런 식이다.
# Claude가 실행한 첫 번째 테스트 결과
$ npm test -- --testPathPattern=unit
FAIL src/domain/order/orderService.test.ts
● createOrder › 재고 부족 시 에러 반환
expect(received).toEqual(expected)
Expected: {"ok": false, "error": "INSUFFICIENT_STOCK"}
Received: {"ok": false, "error": "STOCK_ERROR"}
at Object.<anonymous> (src/domain/order/orderService.test.ts:42:5)
이 로그를 받은 Claude는 다음 사이클에서 에러 코드 불일치를 찾아내고 구현 코드의 상수값을 수정한다. 사람이 직접 찾으면 5분 걸릴 작업이 30초 안에 해결된다.
3. CI/CD와의 결합 — Git Hook으로 자동 트리거
수동으로 프롬프트를 입력하는 단계에서 한 발 더 나아가면, Git 이벤트에 연동해 파이프라인이 자동으로 돌아가게 만들 수 있다.
.git/hooks/pre-push 파일을 작성한다.
#!/bin/bash
echo "🔍 변경 파일 분석 중..."
# 변경된 파일 목록 추출
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD | grep -E '\.(ts|tsx|js|jsx|py)$')
if [ -z "$CHANGED_FILES" ]; then
echo "변경된 소스 파일 없음. 훅 종료."
exit 0
fi
echo "분석 대상: $CHANGED_FILES"
# Claude Code CLI로 테스트 생성 및 실행 트리거
claude --print "다음 파일들의 변경사항을 분석하고 관련 테스트를 실행해라: $CHANGED_FILES" \
--allowedTools "Bash,Read,Write,Edit" \
| tee /tmp/claude-review.log
# 테스트 결과 확인
if grep -q "FAIL" /tmp/claude-review.log; then
echo "테스트 실패 감지. 푸시 차단."
exit 1
fi
echo "모든 테스트 통과. 푸시 진행."
exit 0
권한 설정을 빠뜨리면 훅이 실행되지 않는다.
chmod +x .git/hooks/pre-push
실제로 이 훅을 적용한 뒤 가장 큰 변화는 엣지 케이스 조기 발견이었다. null 입력값이나 빈 배열 처리 같은 부분을 사람이 놓치는 경우가 많은데, Claude가 변경 코드를 보고 자동으로 경계 조건 테스트를 생성해서 실행한다.
4. 운영 팁과 주의할 함정
실제 운영하면서 마주친 문제들을 정리했다.
| 상황 | 문제 | 해결책 |
|---|---|---|
| 테스트 파일이 없는 레거시 코드 | Claude가 테스트 대상을 찾지 못함 | CLAUDE.md에 테스트 디렉터리 명시 |
| 통합 테스트가 외부 DB에 의존 | 로컬 훅에서 실패 | 훅에서 단위 테스트만 실행, 통합은 CI에 위임 |
| Claude 응답이 너무 길어서 로그 파싱 어려움 | 결과 판별 실패 | --print 출력을 구조화된 포맷으로 요청 |
| Mac vs Linux 줄바꿈 차이 | 훅 스크립트 오작동 | #!/bin/bash + set -euo pipefail 명시 |
Docker 환경에서는 훅 경로 문제가 생길 수 있다. 볼륨 마운트 시 .git/hooks/가 컨테이너 안에서 실행 권한을 잃는 경우가 있으니 Dockerfile에 아래 라인을 추가한다.
RUN git config core.hooksPath .githooks
그리고 .githooks/ 디렉터리를 버전 관리에 포함시키면 팀 전체가 같은 훅을 공유할 수 있다.
마무리
Claude Code를 자율 검증 엔진으로 전환하는 핵심은 세 가지다. CLAUDE.md로 컨텍스트를 주입하고, Plan-Execute-Verify 루프로 에이전트가 스스로 수정하게 만들고, Git Hook으로 사람 개입 없이 파이프라인을 트리거한다. 이 구조가 작동하기 시작하면 개발자의 역할은 코드 한 줄 한 줄에서 설계와 검증 기준 수립으로 이동한다.
다음 글에서는 이 파이프라인에 n8n을 연결해서 Slack 알림과 자동 PR 생성까지 붙이는 과정을 다룬다.
🐦 X에서 더 빠르게: @baegseungh7061
📚 이 시리즈 더 보기: Code 실전
💌 새 글 알림: X 팔로우 또는 블로그 RSS 구독
'Code 실전' 카테고리의 다른 글
| Claude Code Pre/Post 훅을 이벤트 버스로 연결해 비동기 파이프라인 구성하기 (0) | 2026.05.09 |
|---|---|
| Claude Code 실행 이력을 JSON으로 수집해 이상 탐지 자동화하기 (0) | 2026.05.08 |
| MCP 서버 내부 상태를 실시간으로 들여다보는 법 — 스냅샷 엔드포인트로 툴 호출 흐름 시각화하기 (0) | 2026.05.07 |
| Claude Code Hooks 완전 분석 — 8종 이벤트로 AI 실행을 통제하는 법 (0) | 2026.05.01 |
| Mac Mini 클러스터에 자가 치유 시스템 심기 — n8n으로 만드는 로컬 AI 면역 체계 (0) | 2026.04.30 |