에이전트에게 일을 맡겨 본 사람은 비슷한 순간을 겪습니다. "완료했습니다"라는 말을 듣고 열어 보면, 반쯤 된 상태입니다.
에이전트가 거짓말을 한 걸까요. Anthropic의 Claude Code 모범 사례 문서는 다르게 봅니다. 확인할 방법이 없으니 '끝나 보이는' 상태에서 멈춘 것이라고요.
이 문서는 세션이 기대와 다르게 흘러가는 이유를 네 가지로 나눕니다. 이 글은 그중 두 가지를 따라갑니다. 확인 수단이 없는 문제, 그리고 프롬프트로는 보장되지 않는 규칙의 문제입니다.
두 종류의 지시
문서는 먼저 지시를 둘로 나눕니다.
하나는 비결정적 지시입니다. 프롬프트, CLAUDE.md, 스킬처럼 모델이 읽고 판단하는 것들입니다. 대개 따르지만 반드시 따른다는 보장은 없습니다.
다른 하나는 결정적 지시입니다. 훅, 거부 규칙, 관리형 설정처럼 하네스(Claude Code 자체)가 매번 실행하는 것들입니다. 모델이 무엇을 결정했든 적용됩니다.
문서의 태도는 의외로 모델 쪽에 너그럽습니다. 대부분의 경우에는 모델이 판단하게 두라고 합니다. 앞에 놓인 실제 코드를 보고 지침이 맞는지 판단하는 일은, 미리 써 둔 규칙보다 모델이 더 잘하는 경우가 많다는 이유입니다.
결정적 장치는 반드시 일어나야 하거나 절대 일어나면 안 되는 일에만 씁니다. 예시가 구체적입니다. "src/gen/의 생성된 클라이언트는 절대 고치지 말 것", "파일을 만든 뒤에는 항상 라이선스 헤더 스크립트를 돌릴 것" 같은 것들입니다.
판별법도 하나 줍니다. CLAUDE.md의 한 줄에 강조를 계속 덧붙이는데도 놓친다면, 그 줄은 훅으로 옮길 신호라고요.
끝났는지를 무엇으로 아나
문서에서 가장 날카로운 문장은 이것입니다. 확인할 수단이 없으면 사람이 테스트 스위트가 된다는 것. 실수는 누군가 우연히 발견할 때까지 그대로 남습니다.
해법은 통과·실패가 나오는 무언가를 쥐여 주는 것입니다. 테스트 파일, 빌드 종료 코드, 린터, 결과를 기준 파일과 비교하는 스크립트, 목업 옆에 놓은 브라우저 스크린샷 모두 됩니다. 저장소에 이미 그런 게 있다면, CLAUDE.md에서 가장 쓸모 있는 한 줄은 그것을 돌리는 명령어라고 문서는 말합니다.
엄격함은 단계로 고를 수 있습니다.
- 프롬프트로: "끝나면 auth 테스트를 돌리고 통과할 때까지 계속해." 설정이 필요 없지만 만족 여부는 모델이 판단합니다.
- 목표로:
/goal로 조건을 걸면 별도의 모델이 매 턴마다 대화를 보고 조건 충족 여부를 판단합니다. 오래 도는 백그라운드 작업에서 의미가 큽니다. - Stop 훅으로: 모델이 턴을 끝내려 할 때마다 스크립트를 돌리고, 종료 코드 2가 나오면 다시 일하게 돌려보냅니다. 하네스가 강제합니다.
- 코드를 쓰지 않은 리뷰어로:
/code-review는 대화를 본 적 없는 새 하위 에이전트가 변경분을 봅니다. 코드를 만든 추론에 휩쓸리지 않습니다.
Stop 훅 예시는 몇 줄이면 됩니다. 타입 검사가 실패하면 컴파일러 출력을 표준 오류로 보내고 종료 코드 2로 멈춤을 막습니다.
{
"hooks": {
"Stop": [
{ "hooks": [ { "type": "command", "command": "pnpm tsc --noEmit 1>&2 || exit 2" } ] }
]
}
}
어느 방법을 쓰든 문서는 한 가지를 덧붙입니다. 증거를 달라고 하라. 돌린 명령과 그 출력, 또는 스크린샷입니다. "모든 테스트 통과"라는 말만으로는 아는 게 거의 없고, 출력을 읽는 편이 다시 돌려 보는 것보다 빠릅니다.
리뷰어는 무언가를 꼭 찾아낸다
리뷰 단계에 붙은 주석 하나가 오래 남습니다.
문서는 스펙 대비 리뷰를 맡길 때 프롬프트 끝에 skip style을 붙이라고 하고, 그 부분을 빼지 말라고 강조합니다. 문제를 찾으라는 요청을 받은 리뷰어는 언제나 무언가를 찾아내기 때문입니다. 지적을 전부 고치다 보면 쓸데없는 추상화 층과 일어날 수 없는 경우에 대한 테스트가 쌓인다고 합니다.
리뷰 자동화를 해 본 사람이라면 고개를 끄덕일 대목입니다. 리뷰의 범위를 정하는 것도 사람의 몫입니다.
시작은 질문에서
확인 수단은 '끝'의 정의가 있어야 만들 수 있습니다. 그런데 무엇을 원하는지 아직 모를 때가 많습니다.
문서는 그럴 때 Claude에게 인터뷰를 시키라고 권합니다. 예시 프롬프트는 이렇습니다. "공개 API에 레이트 리밋을 넣고 싶은데 아직 덜 생각했어. 스펙을 쓸 수 있을 때까지 나를 인터뷰하고, 그 결과를 SPEC.md에 써 줘."
그러면 사용자별·키별 제한, 한도를 넘은 요청의 처리, 범위 밖의 것들에 대해 객관식 질문이 돌아옵니다. SPEC.md가 생기면 새 세션에서 그 파일로 만들기 시작하라고 합니다. 깨끗한 컨텍스트와 글로 적힌 '완료의 정의'를 가지고 출발하는 셈이고, 나중에 리뷰어에게 들이밀 기준도 그 파일이 됩니다.
바이브 코딩이 '감'으로 시작한다고 해서 '감'으로 끝나야 하는 건 아닙니다. 끝을 판정하는 무언가를 하나만 쥐여 줘도, "다 했어요"라는 말의 무게가 달라집니다.