The Harness — AI Project Setup

명세와 하네스

가장 생산적인 시간에는 코드가 없다

속도의 함정

AI로 코딩하면 빨라진다는 건 대체로 느낌이다. 숙련 개발자를 대상으로 한 무작위 대조 실험에서, AI 도구를 허용하자 작업은 오히려 19% 느려졌다(METR, 2025). 정작 당사자들은 빨라졌다고 믿었다. 속도만 문제가 아니다 — AI 도입 후 코드 생산은 약 4배 빨라졌지만 보안 결함은 10배로 늘었다(Apiiro, 2025). 빠르게 뽑을수록 결함도 빠르게 쌓인다. 그래서 스펙을 먼저 잡고, 테스트로 검증하고, 하네스로 위험을 물리적으로 막는다. 가장 생산적인 시간에는, 화면에 코드가 한 줄도 없다.

속도의 함정 더 보기 — 「코드는 마지막이다」 →
핵심 요약

AI에게 코드를 맡기기 전에, 코드가 아닌 여섯 장의 문서를 먼저 만든다. 그 핵심은 하네스(harness) — AI가 위험한 명령을 아예 실행하지 못하도록 도구 실행 단계에서 물리적으로 막는 안전장치다.

  • 로드맵 — 무엇을 어디까지 만들지 한 장의 지도로. "이번에 안 만드는 것"(비범위)을 먼저 정한다.
  • RFP(작업 의뢰서) — "무엇을 원하는가"를 AI에게 발주서처럼 건넨다.
  • PRD(스펙) — 의뢰서를 "무엇을 만들 것인가" 설계도로 구체화한다(스펙주도 개발).
  • 테스트(TDD) — 코드보다 테스트를 먼저 쓴다. 테스트가 AI 결과물의 채점 기준이자 변치 않는 자산이 된다(Red-Green).
  • 하네스(hook) — "하지 마"라고 부탁하는 대신, hook과 permissions로 위험 명령은 물론 테스트·스펙 규율까지 물리적으로 강제한다.
  • settings.json — 그 규칙을 전역(모든 프로젝트)·프로젝트 공유·로컬(비밀) 중 어디에 둘지 정한다. deny는 어디에 있든 모든 allow를 이긴다.
Part I — The Map

먼저 지도를 그린다

채널톡의 AI 총괄(CAIO) 이경훈 이사는 한 문장으로 커리어를 바꿨다. "AI가 사람을 대체하는 게 아니라, AI를 잘 쓰는 사람이 못 쓰는 사람을 대체한다." 그의 회사가 토큰 무제한 정책을 도입한 뒤, 한 개발자는 수천만 원어치 토큰으로 혼자 10명분의 일을 해냈다. 마법이 아니다. 그 결과의 전제는 단 두 가지였다 — 명확한 지시, 그리고 결과물을 리뷰하는 능력.

AI는 지금 당신이 고용할 수 있는 가장 일 잘하는 새 직원이자 외주다. 그런데 우리는 새 직원에게 의뢰서도 없이 "알아서 잘 만들어줘"라고 말하지 않는다. 이 글은 코드를 한 줄도 치기 전에 깔아두는 여섯 장의 종이에 관한 것이다. 로드맵, 의뢰서(RFP), 설계도(PRD), 결과물을 검증할 시험지(테스트), 그리고 AI가 사고를 치지 못하게 막는 물리적 울타리(하네스)와 그 설정(settings.json).

Roadmap로드맵큰 그림
RFP의뢰서무엇을 원하나
PRD설계도무엇을 만드나
Test테스트제대로 되나
Harness가드레일하지 말 것
Code코드마지막
추상도: 높음 → 낮음 · 코드는 가장 마지막에 나오는 부산물이다

왜 로드맵부터인가. 인간의 워킹 메모리는 한 번에 3~4개의 정보 덩어리만 처리한다(Cowan, 2001). 처음부터 PRD를 쓰려고 하면 "왜 만드는지", "무엇을 만드는지", "어떻게 만드는지"를 동시에 결정해야 해서 뇌가 과부하된다. 로드맵은 그중 "왜·어디까지"만 떼어 한 장에 담는 고수준 지도다. 세부 할 일 목록이 아니다.

개인이나 소규모 프로젝트에서 정교한 로드맵은 과잉이다. 최소 구성은 세 가지뿐이다 — 범위, 비범위, 그리고 마일스톤 3~5개. 이 중 가장 중요한 것은 비범위다. "이번에 만들지 않는 것"을 적는 순간, 만들다 보면 끝없이 불어나는 범위 크리프(scope creep)가 막힌다.

01 — Scope

범위

이번에 반드시 만드는 것. 핵심 기능만 남긴다. 욕심이 들어오면 비범위로 넘긴다.

02 — Out of Scope

비범위

이번에 만들지 않는 것. 결제 연동, 다국어, 관리자 대시보드처럼 욕심나는 것을 여기 적어 방어선을 친다.

03 — Milestones

마일스톤

"이게 되면 완료"라는 달성 기준이 붙은 체크포인트 3~5개. 날짜가 아니라 순서로 묶는다.

로드맵에서 초보자가 하는 실수
  • 마일스톤을 할 일 목록으로 잘게 쪼갠다. 그러면 로드맵이 아니라 태스크 리스트가 된다. 로드맵은 한 화면에 들어오는 지도여야 한다
  • 비범위를 안 적는다. "이것도 되면 좋지"가 쌓이면 영원히 끝나지 않는다. 빼는 것을 먼저 정하라
  • 정확한 날짜로 못 박는다. 개인 프로젝트에서 중요한 건 날짜가 아니라 순서다. M1이 끝나야 M2다
내 프로젝트의 로드맵을 그리고 싶다면

대괄호 [ ] 안의 내용을 자신의 프로젝트에 맞게 수정한 뒤, Claude나 ChatGPT에 붙여넣으세요.

당신은 소규모 프로젝트 기획을 돕는 시니어 PM이다. 아래 정보를 바탕으로 1페이지 프로젝트 로드맵을 작성해줘. 프로젝트: [한 줄 설명, 예: 동네 카페 주문/적립 웹앱] 만드는 이유: [왜 필요한지, 예: 카운터 줄 서는 시간을 줄이고 싶다] 사용자: [누가 쓰는지, 예: 단골 손님 + 사장님 1명] 가용 시간/예산: [예: 주말마다 / 월 5만원 이하 / 무료 티어만] 기술 경험: [예: 코딩 비전문가, AI 도구로만 개발] 작성 규칙: - 마일스톤은 3~5개만. 각 마일스톤에 "이게 되면 완료"라는 달성 기준을 한 줄로. - "범위(이번에 만드는 것)"와 "비범위(이번에 만들지 않는 것)"를 반드시 분리해서 나열. - 마일스톤은 정확한 날짜가 아니라 "순서"로 표현(M1 다음 M2). - 비범위에는 흔히 욕심내다 망하는 기능(결제 연동, 다국어, 관리자 대시보드 등) 중 이번에 뺄 것을 구체적으로. 주의: - 할 일 단위로 잘게 쪼개지 마. 로드맵은 고수준 지도다. - 모호한 목표("좋은 UX") 대신 측정 가능한 기준("주문 3번 클릭 이내")을 써라. 출력: 마크다운. 섹션 = 범위 / 비범위 / 마일스톤(M1~). 한 화면에 들어오게.
Part II — The Brief

의뢰서를 쓴다

로드맵이 지도라면, RFP는 그 지도를 들고 새 직원에게 건네는 발주서다. RFP(Request for Proposal, 제안요구사항서)는 원래 발주자가 외부 업체에 "이런 게 필요하다"고 보내는 공식 문서다. 표준 구성은 배경·범위·요구사항·제약·평가기준·타임라인. AI 개발로 번역하면 RFP는 "AI에게 건네는 작업 의뢰서"가 된다.

여기서 많은 사람이 헷갈리는 구분이 있다. RFP와 PRD는 다르다. RFP는 "무엇을 원하는가"(요구)이고, PRD는 "무엇을 만들 것인가"(제품 정의)다. RFP가 먼저 나오고, PRD는 그 의뢰서를 받은 사람이 "그럼 이렇게 만들겠다"고 답한 설계도다. RFP는 질문, PRD는 답이다.

RFP — The Request
무엇을 원하는가
  • 관점: 발주자
  • 내용: 요구 명세
  • 문장: "이런 결과물이 필요하다"
  • 추상도: 높음
PRD — The Answer
무엇을 만들 것인가
  • 관점: 제작자
  • 내용: 제품 정의
  • 문장: "이렇게 만들겠다"
  • 추상도: 낮음
RFP는 질문, PRD는 답.

전통적인 RFP의 여섯 요소를 AI 작업 의뢰서로 다시 매핑하면 다섯 가지로 압축된다. 비범위는 로드맵에서 이미 정의했으니, 여기서는 제약과 성공기준에 흡수시킨다.

Why배경
+
Goal목표
+
Needs요구사항
+
Limits제약
+
Done성공기준
AI 작업 의뢰서
나쁜 의뢰 vs 좋은 의뢰
  • 나쁜 의뢰: "로그인 기능 만들어줘". AI는 가장 흔한 패턴을 가장 빠르게 생성한다. 보안, 에지 케이스, 아키텍처 일관성은 시키지 않았으니 하지 않는다. 결과는 예측 불가능하다
  • 좋은 의뢰: 배경·목표·제약·성공기준이 붙은 의뢰서. "단골 손님이 비밀번호 없이 휴대폰 번호로만 로그인, 개인정보는 번호만 저장, 세션 1주일 유지"처럼 적으면 결과가 좁혀진다
  • 핵심: 토큰으로 10명분을 해낸 그 개발자의 전제가 여기 산다. "명확한 지시"가 곧 RFP다. 의뢰가 명확할수록 결과가 예측 가능해진다
AI에게 건넬 작업 의뢰서(RFP)를 쓰고 싶다면

Part I에서 만든 로드맵을 먼저 붙여넣고, 그 아래에 이 프롬프트를 이어 붙이세요. 대괄호 [ ]만 수정하면 됩니다.

당신은 발주자를 대신해 외주 개발자에게 보낼 작업 의뢰서(RFP)를 작성하는 전문가다. 위에 붙여넣은 로드맵을 입력으로, AI 개발 에이전트가 그대로 착수할 수 있는 작업 의뢰서를 작성해줘. 프로젝트: [로드맵의 한 줄 설명 재기입] 선호 기술 스택: [예: 웹 = Next.js + Supabase / 미정이면 "추천해줘"] 절대 제약: [예: 무료·저비용 티어만, 개인정보 최소 수집, 외부 결제 연동 없음] 작성할 5개 섹션: 1. 배경 — 왜 만드는가 (1~2문장) 2. 목표 — 무엇을 달성하면 성공인가 (측정 가능한 지표) 3. 요구사항 — 반드시 필요한 기능 목록 (각 기능에 한 줄 설명) 4. 제약 — 기술/시간/예산/보안 한계 5. 성공기준 — "이것이 되면 완성"인 체크 항목 (3~5개) 주의: - "적절한", "좋은", "빠른" 같은 모호한 표현 금지. 숫자나 관찰 가능한 결과로. - 기능을 어떻게 구현할지(how)는 쓰지 마. 무엇이 필요한지(what/why)만. - 로드맵의 비범위는 "제약" 섹션에 명시적으로 다시 적어, AI가 멋대로 기능을 추가하지 못하게 막아라. 출력: 마크다운, 5개 섹션 헤더로 구분. 그대로 다음 단계(PRD 작성)의 입력으로 쓸 수 있게.
Part III — The Spec

의뢰서를 설계도

의뢰서(RFP)를 받은 팀은 "그럼 이렇게 만들겠습니다"라는 설계도를 쓴다. 그게 PRD(Product Requirements Document, 제품 요구사항 문서)다. 2025년 9월, GitHub과 Microsoft가 Spec Kit이라는 도구를 공개하면서 한 가지 원칙이 공식화됐다 — "스펙이 진실의 원천이고, 코드는 거기서 파생되는 이차 산출물이다." 이것이 스펙 주도 개발(SDD, Spec-Driven Development)이다.

SDD의 흐름은 추상도가 한 단계씩 낮아지는 구체화다. 원칙을 정하고(constitution), 무엇을·왜를 정의하고(specify), 기술 아키텍처를 짜고(plan), 원자적 태스크로 쪼갠 뒤(tasks), 마지막에 코드를 생성한다(implement). RFP에서 PRD로, PRD에서 태스크로 — 같은 사다리를 계속 내려가는 것이다.

constitution원칙비협상 규칙
specify스펙무엇을 / 왜
plan계획기술 아키텍처
tasks태스크원자 단위
implement코드생성
GitHub Spec Kit의 5단계 — 각 단계의 산출물은 다음 단계의 입력이 된다

데이터는 이 방식이 단순한 형식주의가 아님을 보여준다. 스펙을 먼저 잡으면 재작업과 해명 루프가 줄어 오류가 감소한다(초기 연구에서 최대 50%). 반대로 스펙도 검증도 없이 코드부터 뽑으면, 그 코드의 절반 가까이가 OWASP Top 10 취약점을 안고 나온다.

45%
검증 없이 뽑은 AI 코드가 OWASP Top 10 취약점을 포함한 비율
Veracode, 2025
29%
AI 정확성을 신뢰하는 개발자 (쓰는 사람은 84%)
Stack Overflow, 2025
50%
사람이 다듬은 스펙으로 AI 생성 시 오류 감소 (초기 연구)
arXiv, 2026
8x
AI 도입 후 복사·붙여넣기 코드 증가
GitClear, 2025

PRD의 핵심은 모호함을 없애는 것이다. "주문 기능"이라고 쓰면 AI가 상상으로 채운다. 대신 Given-When-Then 형식으로 관찰 가능한 결과를 못 박는다.

Given 로그인한 손님이
When 메뉴를 담고 주문하면
Then 사장님 화면에 주문이 표시된다

그리고 우선순위를 P0/P1/P2로 나눈다. 가장 흔한 실수는 모든 것을 P0로 지정하는 것이다. 진짜 MVP에 필요한 것만 P0다.

P0 — Blocker

런치 차단

없으면 MVP가 성립하지 않는 것. 이것만으로 출시 가능해야 한다.

P1 — Important

중요하나 비차단

있으면 훨씬 좋지만, 없어도 출시는 된다. 두 번째 마일스톤으로.

P2 — Nice to have

있으면 좋음

미래 개선 후보. 지금은 비범위에 가깝게 다룬다.

스펙 주도 개발의 함정
  • 과설계(over-specification). 스펙을 의사코드 수준으로 너무 자세히 쓰면, AI는 명세에 없는 가상의 시나리오(언급한 적 없는 소셜 로그인, 일어날 수 없는 에러)까지 구현한다. 스펙이 상세할수록 이 경향이 강해진다. 스펙은 "무엇을·왜"까지, "어떻게"는 AI에게 맡겨라
  • 거짓 자신감. 스펙 검증을 통과해도 스펙 자체가 틀렸다면 소프트웨어도 틀린다. SDD는 스펙의 품질을 보장하지 않는다 — 품질은 사람의 책임이다
  • 스펙 부패(spec rot). 코드를 고치고 스펙을 안 고치면 둘이 어긋나 신뢰가 무너진다는 지적도 있다. 스펙을 살아있는 문서로 유지해야 한다

스펙을 쓰는 행위 자체가 "명확한 지시" 능력을 단련시킨다. 채널톡의 이경훈 이사가 말한 "AI를 잘 쓰는 사람 = 명확히 지시하고 결과물을 리뷰할 수 있는 사람"의 그 지시력은, PRD를 한 번 써보면 눈에 띄게 자란다.

의뢰서를 PRD(설계도)로 바꾸고 싶다면

Part II의 작업 의뢰서를 먼저 붙여넣고, 그 아래 이 프롬프트를 이어 붙이세요. 두 단계로 나눠 실행하면 더 정확합니다.

Step 1 — PRD 생성 (입문)
당신은 스펙 주도 개발(SDD)에 익숙한 시니어 제품 엔지니어다. 위에 붙여넣은 작업 의뢰서(RFP)를 입력으로, AI 코딩 에이전트가 바로 구현에 착수할 수 있는 PRD(제품 요구사항 문서)를 작성해줘. 기술 스택: [RFP에서 확정했거나 추천받은 스택] PRD에 포함할 섹션: 1. 개요 — 한 문단 2. 목표와 성공 지표 — 측정 가능한 기준 3. 사용자 스토리 — 최소 5개, 반드시 Given-When-Then 형식 (예: "Given 로그인한 손님이 / When 메뉴를 담고 주문하면 / Then 사장님 화면에 주문이 표시된다") 4. 기술 스택과 선택 근거 5. 아키텍처 개요 — 주요 컴포넌트와 데이터 흐름 6. 데이터 모델 — 엔티티와 관계 7. 비기능 요구사항 — 성능 / 보안 / 접근성 8. 구현 우선순위 — P0(런치 차단) / P1(중요하나 비차단) / P2(있으면 좋음) 9. 제외 범위 — RFP의 비범위를 그대로 명시 주의(흔한 실수 방지): - 과설계 금지: RFP에 없는 기능(언급 없는 소셜 로그인, 발생 불가능한 에러 케이스)을 멋대로 추가하지 마. - P0를 남발하지 마. 진짜 MVP에 필요한 것만 P0. - 구현 코드는 쓰지 마. "무엇을 / 왜"까지만. "어떻게"는 다음 단계에서. 출력: 마크다운, 섹션별 헤더 구분. 한 파일로.
Step 2 — 태스크 분해 + 스펙 자기검증 (실전)
위에서 만든 PRD를 다음 두 가지로 처리해줘. (1) 태스크 분해 - 사용자 스토리별로 구현 태스크를 원자 단위로 쪼개라. - 각 태스크에 의존성(먼저 끝나야 하는 태스크)과 우선순위(P0/P1/P2)를 붙여라. - 서로 독립이라 병렬로 해도 되는 태스크에는 [병렬] 표시. (2) 스펙 자기검증 — 코드를 쓰기 전에 PRD 자체의 결함을 찾아라 - 모순되는 요구사항이 있는가? - 측정 불가능한("좋은", "빠른") 성공 기준이 남아 있는가? - P0인데 사실 P1/P2여야 하는 항목은 없는가? - 보안/개인정보 관점에서 빠진 요구사항은? 주의: "스펙을 통과했다"가 "스펙이 옳다"를 보장하지 않는다. 의심스러운 가정은 질문으로 되물어라. 출력: tasks 목록(체크박스) + 검증 결과(발견한 문제 + 수정 제안).
Part IV — The Tests

테스트가 자산이다

PRD가 "무엇을 만들지"를 정했다. 그런데 AI가 그걸 제대로 만들었는지는 어떻게 아는가. 눈으로 코드를 읽어서? AI가 하루에 쏟아내는 코드를 전부 읽을 수는 없다. 답은 테스트다. 그리고 순서가 핵심이다 — 코드보다 테스트를 먼저 쓴다.

테스트 주도 개발(TDD)의 창시자 Kent Beck이 AI 코딩을 두고 남긴 말이 정곡을 찌른다.

AI라는 지니는 TDD를 하기 싫어한다.
코드를 먼저 쓰고, 그 코드에 맞춰 통과하는 테스트를 짜고 싶어한다.

Kent Beck

"그냥 만들어 줘"라고 하면, AI는 자기가 짠 코드에 맞춰 통과하는 테스트를 슬쩍 끼워 넣거나, 잘 되는 경우(해피 패스)만 통과시키고 예외는 환각으로 넘긴다. 심하면 실패하는 테스트를 지워서 초록불을 만든다. 그래서 사람이 테스트를 먼저 못 박고, AI에게는 "이 빨간 테스트를 초록으로 만들어"라고 시킨다. 그 순간 테스트는 AI의 채점 기준이자 결승선이 된다.

Red실패테스트 먼저
Green통과최소 코드
Refactor정리동작 보존
Red → Green → Refactor — 작은 단위로 이 사이클을 반복한다

TDD는 세 박자로 돈다. Red — 코드를 짜기 전에 "이렇게 동작해야 한다"는 테스트를 먼저 쓴다. 기능이 없으니 당연히 실패한다(빨강). 이 빨강은 "내가 뭘 만들지 정확히 정했다"는 신호다. Green — 그 테스트를 통과시키는 가장 단순한 코드를 짠다. 멋지게 말고, 일단 초록불이 켜지게만. Refactor — 초록불 상태에서 코드를 다듬는다. 테스트가 지켜보고 있으니, 잘못 건드리면 즉시 빨강으로 알려준다.

여기서 핵심 통찰. 코드는 AI가 언제든 다시 써주는 초안이지만, 테스트는 "이 소프트웨어는 이렇게 동작한다"를 못 박은 계약이다. 초안은 찢고 다시 써도, 계약서가 그대로면 결과물은 바뀌지 않는다. 그래서 AI 시대에는 코드보다 테스트가 더 오래 살아남는 자산이다.

코드 — The Draft
초안
  • AI가 다시 생성 가능
  • 리팩토링하면 바뀐다
  • 버려도 된다
  • 수명: 짧다
테스트 — The Contract
자산 · 계약
  • 동작을 고정한다
  • 코드가 바뀌어도 그대로
  • AI의 결승선이 된다
  • 수명: 길다
SDD가 "무엇을", TDD가 "제대로 동작하는가", 하네스가 "위험 차단"을 맡는다.

국내 개발자 커뮤니티(GeekNews)에서도 AI 시대의 방법론으로 SDD와 TDD의 결합이 논의된다. 스펙으로 "무엇을"을 정의하고(Red 단계의 테스트로 옮긴 뒤), AI가 통과시킬 때까지 구현하고(Green), 사람이 설계를 다듬는(Refactor) 선순환이다. 둘은 경쟁이 아니라 보완이다.

AI에게 TDD를 시킬 때의 함정
  • AI가 테스트를 고쳐서 통과시킨다. 실패한 테스트를 지우거나 느슨하게 바꿔 초록불을 만든다. "테스트는 건드리지 말고 구현을 고쳐 통과시켜라"를 명시하라
  • 해피 패스만 테스트한다. 정상 경로만 검증하고 경계값·예외는 빠뜨린다. 테스트에 "경계값 + 예외 케이스 포함"을 요구하라
  • mock 남용. 테스트 대상 로직까지 mock해서 사실상 아무것도 검증하지 않는다. mock은 외부 의존성(DB, 외부 API) 경계에서만 쓴다
테스트를 먼저 쓰고 AI에게 통과시키게 하고 싶다면

Part III의 PRD(사용자 스토리)를 먼저 붙여넣고, 그 아래 이 프롬프트를 이어 붙이세요. 대괄호 [ ]만 수정하면 됩니다.

당신은 테스트 주도 개발(TDD)을 엄격히 지키는 시니어 개발자다. 위에 붙여넣은 PRD의 사용자 스토리를 입력으로, 아래 규칙에 따라 한 기능을 구현한다. 기술 스택: [예: TypeScript + Jest / Python + pytest] 구현할 기능: [PRD의 사용자 스토리 1개, 예: "주문 금액이 5만 원 이상이면 배송비를 0원으로 계산한다"] 필수 규칙: 1. 절대 구현 코드를 먼저 쓰지 마라. 실패하는 테스트(Red)를 가장 먼저 작성하고, 내가 "go"라고 하기 전엔 구현하지 마라. 2. 테스트는 Given-When-Then으로 의도를 적고, 해피 패스 1개 + 경계값 + 예외 케이스를 모두 포함하라. 3. 내가 "go"라고 하면, 그제야 테스트를 통과시키는 "최소한의" 구현(Green)만 작성하라. 미래 대비용 기능은 넣지 마라. 4. 모든 테스트가 통과한 뒤에만 리팩토링(Refactor)을 제안하라. 동작은 바뀌면 안 된다. 주의(위반 시 다시 작성): - 한 번에 기능 하나, 테스트 하나씩. 여러 개를 동시에 하지 마라. - 실패 테스트를 삭제·수정해서 통과시키지 마라. 구현을 고쳐서 통과시켜라. - mock은 외부 의존성([DB, 외부 API]) 경계에서만. 테스트 대상 로직 자체는 mock하지 마라. - 존재하지 않는 라이브러리·메서드를 임의로 호출하지 마라. 불확실하면 먼저 확인을 요청하라. 출력: 1) Red: 테스트 파일 전체 + 이 테스트가 왜 실패하는지 한 줄 2) (내 "go" 이후) Green: 구현 파일 + 통과 확인 3) Refactor: 개선 제안과 근거 (테스트는 그대로 통과해야 함)

그런데 위 프롬프트도 결국 부탁이다. AI가 규칙을 어기고 실패하는 테스트를 지워버릴 수도 있다. 그래서 이 규율은 hook으로 강제해야 진짜가 된다 — 그 방법은 다음 Part에서 다룬다.

Part V — The Guardrails

말로 막지 말고 물리적으로 막아라

여기까지 우리는 AI에게 로드맵·의뢰서·스펙·테스트를 "써 달라"고 했다. 그런데 그건 전부 부탁이다. 스펙대로 만들지, 테스트를 먼저 쓸지, 위험한 명령을 피할지 — 결국 AI의 선의에 달렸다. 하네스(harness)는 이 부탁을 강제로 바꾸는 층이다. 위험 명령 차단만이 아니라, 스펙과 테스트 규율까지 도구가 실행되기 전에 강제한다.

명세 — SDD
부탁"스펙대로 만들어줘"
강제PreToolUse hook으로 spec.md가 비면 구현 차단 · SessionStart hook으로 스펙을 매 세션 자동 주입
테스트 — TDD
부탁"테스트 먼저 써줘"
강제Stop hook으로 테스트 실패 시 종료 차단 · 테스트 파일을 deny로 보호(AI가 못 지움)
안전 — 위험 명령
부탁CLAUDE.md에 "rm -rf 하지 마"
강제permissions deny · PreToolUse hook으로 실행 직전 차단(exit 2)

원리는 하나다 — 말이 아니라, 도구가 실행되기 직전에 막는다. 아래부터는 가장 흔한 "안전" 차단으로 그 원리를 보고, 같은 방식이 테스트와 스펙에도 그대로 적용된다.

새 직원에게 "저 빨간 버튼은 누르지 마세요"라고 말하는 것과, 그 버튼에 안전 덮개를 씌우는 것은 다르다. 전자는 직원의 기억과 선의에 의존하고, 후자는 누를 수 없게 만든다. AI 가드레일도 똑같다.

CLAUDE.md에 "rm -rf 하지 마"라고 쓰는 것은 이다. AI는 그것을 읽지만, 맥락에 따라 무시할 수도 있고, 프롬프트 인젝션으로 우회될 수도 있다 — 모델의 선의에 의존한다. 앞서 봤듯 AI가 생성한 코드의 절반 가까이가 OWASP Top 10 보안 취약점을 안고 나온다(Veracode, 2025). AI가 위험을 "선택"한 게 아니다 — 시키지 않으면 보안을 챙기지 않을 뿐이다. 그러니 부탁만으로는 부족하다. 하네스(harness) 차원에서 물리적으로 막아야 한다. 도구가 실행되기 전에 차단되면, 모델은 애초에 선택할 수조차 없다.

말로 막기 — Prompt
부탁
  • 위치: CLAUDE.md "~하지 마"
  • AI가 거부할 수 있다
  • 인젝션으로 우회 가능
  • 모델의 선의에 의존
  • 결과: 비결정적
물리적으로 막기 — Harness
잠금
  • 위치: settings.json deny + hook
  • 실행 자체가 차단된다
  • 모델이 선택할 수 없다
  • 하네스가 강제한다
  • 결과: 결정론적
프롬프트는 부탁, 하네스는 잠금.

Claude Code에는 물리적 차단을 위한 두 가지 도구가 있다. 하나는 settings.json의 권한(permissions) deny 규칙, 다른 하나는 PreToolUse hook이다.

먼저 권한. permissions는 allow(자동 허용), ask(매번 확인), deny(차단) 세 배열로 나뉜다. 평가는 deny → ask → allow 순으로, 가장 먼저 매칭되는 규칙이 이긴다. 위험한 것을 deny에 넣으면 그걸로 잠긴다.

.claude/settings.json — permissions 예시
{
  "permissions": {
    "deny":  ["Bash(rm -rf *)", "Read(.env)"],
    "ask":   ["Bash(git push *)"],
    "allow": ["Bash(npm run *)"]
  }
}

다음은 hook. hook은 세션의 특정 순간(도구 실행 전후, 세션 시작·종료 등)에 자동으로 실행되는 명령이다. 그중 PreToolUse는 도구가 실행되기 직전에 끼어들어 차단할 수 있는 핵심 이벤트다. 차단하는 방법은 두 가지다 — 검사 스크립트가 exit code 2로 종료하면 그 도구 호출이 막히고 이유가 Claude에게 전달된다. 또는 hook이 JSON으로 permissionDecision을 "deny"로 반환해도 된다.

.claude/settings.json — PreToolUse hook 골격
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{ "type": "command", "command": "~/.claude/hooks/block.sh" }]
    }]
  }
}

matcher는 어떤 도구에 hook을 걸지 정하는 필터다("Bash", "Edit|Write" 같은 패턴, 정규식도 된다). 검사 스크립트는 표준 입력으로 도구 정보가 담긴 JSON을 받아 명령어를 들여다보고, 위험하면 차단하고 아니면 통과시킨다.

그런데 이 모든 규칙을 어디에 둘 것인가. settings.json은 놓이는 위치가 곧 적용 범위(스코프)다. 그리고 위치마다 우선순위가 다르다.

전역 — User
~/.claude/settings.json

나의 모든 프로젝트

개인 선호, 그리고 어디서도 일어나면 안 되는 위험 명령의 deny. 모든 프로젝트에 적용된다.

프로젝트 공유 — Shared
.claude/settings.json

팀과 공유

팀 코딩 표준, 금지 명령, 프로젝트 hook. git에 체크인되어 팀원 모두에게 적용된다.

프로젝트 로컬 — Local
.claude/settings.local.json

내 머신 전용

민감한 토큰, 개인 테스트 오버라이드. git에 올라가지 않는다. 비밀은 반드시 여기에.

설정 우선순위 — 위가 아래를 덮어쓴다
1
Managed 정책조직 MDM — 개인이 풀 수 없다
2
CLI 플래그--model 등 세션 한정
3
프로젝트 로컬.claude/settings.local.json
4
프로젝트 공유.claude/settings.json
5
전역(User)~/.claude/settings.json
단, deny는 이 사다리를 무시한다. 어느 위치에 있든 deny는 모든 allow를 관통해 차단한다. 그래서 설계 원칙은 단순하다 — 절대 일어나면 안 되는 것은 전역에 deny. "전역에 deny하면 프로젝트 allow로 풀 수 있겠지"는 정확히 반대다. 전역 deny가 프로젝트 allow를 이긴다.
초보자가 가장 자주 틀리는 것
  • deny를 풀 수 있다고 착각한다. deny는 deny-first다. 상위 스코프의 allow로도 못 푼다. 위험한 건 전역 deny로 봉인하라
  • hook의 allow로 deny를 뚫으려 한다. hook이 "allow"를 반환해도 settings의 deny 규칙은 못 이긴다. deny가 항상 우선이다
  • 비밀을 공유 파일에 넣는다. .claude/settings.json은 git에 올라가 팀 전체가 본다. 토큰·API 키는 반드시 .claude/settings.local.json에
  • hook이 그냥 종료하면 통과로 안다. exit 0에 아무 판단도 없으면 "통과"가 아니라 "기본 권한 흐름을 따른다"는 뜻이다. 차단하려면 명시적으로 exit 2 또는 deny여야 한다
내 settings.json 가드레일을 짜고 싶다면

대괄호 [ ]만 자신의 환경에 맞게 바꾸세요. 생성된 JSON은 검토한 뒤 적용하세요.

Step 1 — 권한 가드레일 생성 (입문)
당신은 Claude Code 설정 전문가다. 코딩 비전문가가 안전하게 쓸 수 있는 settings.json 가드레일을 만들어줘. 내 환경: - OS: [macOS / Windows / Linux] - 주 기술 스택: [예: Node.js + Next.js / Python] - 절대 실행되면 안 되는 명령: [예: 파일 대량 삭제, 강제 푸시, 프로덕션 DB 접근] - 자동 허용해도 되는 명령: [예: 테스트 실행, 빌드, lint] 설계 규칙(반드시 지켜라): - permissions를 allow / ask / deny 세 개로 나눠라. - 위험 명령(rm -rf, git push --force 등)은 deny에. deny는 모든 allow보다 우선해 물리적으로 막힌다는 점을 활용해라. - .env 등 비밀 파일은 Read/Edit deny로 막아라. - 위험 명령 deny를 "전역(~/.claude/settings.json)"에 두는 게 좋은 이유를 한 줄로 설명해줘. - defaultMode는 초보자용으로 default 또는 acceptEdits 중 추천하고 이유를 적어줘. 추가로: - 전역(~/.claude/settings.json) / 프로젝트 공유(.claude/settings.json) / 프로젝트 로컬(.claude/settings.local.json) 중 어떤 규칙을 어디에 둬야 하는지 표로 정리해줘. 주의: - 토큰·API 키 같은 민감 정보는 절대 git에 올라가는 .claude/settings.json에 넣지 마. .local.json에 넣어라. - 매처 문법 주의: 공백이 있는 'Bash(rm *)'는 단어 경계를 강제한다는 점을 반영해라. 출력: (1) 전역용 JSON, (2) 프로젝트 공유용 JSON, (3) 어디에 무엇을 둘지 표.
Step 2 — PreToolUse hook 물리적 차단 (실전)
당신은 Claude Code의 hooks에 익숙한 보안 엔지니어다. 위험한 명령을 "프롬프트로 부탁"하는 게 아니라 PreToolUse hook으로 물리적으로 차단하는 설정을 만들어줘. 차단하고 싶은 행동: [예: rm -rf, 프로덕션 환경변수 접근, 외부로 데이터 전송하는 curl] 허용하고 싶은 행동: [예: 로컬 테스트, 빌드] 요구사항: - settings.json의 hooks.PreToolUse 블록을 만들어라. matcher는 "Bash"로. - 실제 차단을 수행하는 별도 스크립트의 동작을 설명해줘: · 표준 입력으로 JSON을 받고 tool_input.command를 검사 · 위험 패턴이면 stderr에 이유를 출력하고 exit code 2로 종료해 차단 · 그 외에는 exit 0으로 통과 - 또는 스크립트 없이 hook이 JSON으로 permissionDecision을 "deny"로 반환하는 방식도 같이 설명해줘. 주의(정확성): - exit 0이고 아무 판단도 없으면 차단이 아니라 기본 권한 흐름을 따른다. "통과"와 헷갈리지 마. - hook의 allow는 settings의 deny 규칙을 뚫지 못한다. deny rule이 항상 우선이다. - 여러 hook이 매칭되면 가장 제한적인 답(deny)이 이긴다. 출력: (1) settings.json hooks 블록, (2) 차단 스크립트가 무엇을 검사하고 어떻게 exit code를 반환하는지 단계별 설명, (3) 이 방식이 CLAUDE.md에 "하지 마"라고 쓰는 것보다 안전한 이유 3줄.

같은 원리를 테스트와 스펙에도 적용한다. 테스트는 Stop hook으로 강제한다 — Claude가 응답을 끝내려는 순간 hook이 테스트를 돌리고, 실패하면 종료를 막아(무엇이 실패했는지 이유로 전달) green이 될 때까지 고치게 만든다. 그리고 AI가 실패하는 테스트를 지우지 못하도록 테스트 파일을 deny로 잠근다. 스펙은 PreToolUse hook이 spec.md가 비어 있으면 구현 편집을 막고, SessionStart hook이 매 세션 스펙을 자동으로 물려준다.

.claude/settings.json — Stop hook (테스트 게이트)
{
  "hooks": {
    "Stop": [{
      "hooks": [{ "type": "command", "command": "~/.claude/hooks/run-tests.sh" }]
    }]
  }
}
테스트·스펙을 hook으로 강제하고 싶다면

대괄호 [ ]만 자신의 환경에 맞게 바꾸세요. 생성된 설정은 검토한 뒤 적용하세요.

당신은 Claude Code hooks 전문가다. 테스트(TDD)와 스펙(SDD) 규율을 "부탁"이 아니라 hook으로 강제하는 settings.json을 만들어줘. 기술 스택 / 테스트 명령: [예: npm test / pytest -q / go test ./...] 테스트 파일 위치: [예: tests/ 디렉토리, *.test.ts] 스펙 파일: [예: spec.md 또는 PRD.md] 강제할 규칙: 1. 테스트 게이트 — Stop hook으로, Claude가 응답을 끝내기 전에 테스트를 자동 실행하고 실패하면 종료를 막는다(exit code 2 또는 decision "block"). 무엇이 몇 개 실패했는지 사람이 읽을 수 있게 이유로 출력한다. 2. 테스트 보호 — permissions.deny에 테스트 경로(예: Edit(tests/**), Edit(**/*.test.*))를 넣어 AI가 테스트를 지우거나 약화시키지 못하게 한다. 3. 편집 직후 검증 — PostToolUse hook(matcher "Edit|Write")으로 린트·테스트를 돌려 결과를 Claude에게 보여준다. 4. 스펙 강제 — PreToolUse hook(matcher "Edit|Write")이 스펙 파일이 비었거나 없으면 구현 편집을 차단(exit 2)한다. SessionStart hook으로 스펙 내용을 매 세션 컨텍스트에 주입한다(명령형이 아니라 사실 서술로). 주의(정확성): - Stop·PostToolUse hook의 "이유(reason)"는 Claude에게 그대로 보여줄 텍스트다. 자동 채점이 아니므로, 무엇이 실패했는지 스크립트가 정리해 출력해야 한다. - permissions deny는 Claude의 편집 도구에만 적용된다. Claude가 실행하는 하위 프로세스까지는 막지 못하니, 강한 격리가 필요하면 샌드박스를 함께 써라. - hook은 "테스트가 의미 있는지", "코드가 스펙 의도에 맞는지"는 판단하지 못한다. 그건 사람 리뷰의 몫이다. 출력: (1) settings.json의 hooks(Stop·PostToolUse·PreToolUse·SessionStart)와 permissions.deny, (2) 각 스크립트가 무엇을 검사하고 어떤 exit code/이유를 반환하는지 단계별 설명, (3) 이 방식이 "테스트 먼저 써"·"스펙대로 만들어"라는 프롬프트보다 강력한 이유 2줄.
하네스가 잠그는 것 vs 사람 몫
  • 잠근다 (결정론). 테스트 통과 여부, 테스트·비밀 파일 편집, 스펙 파일 존재, 위험 명령 — 이런 "구조"는 command hook이 명령을 돌려 exit code로 막아 결정론적으로 강제한다
  • 못 잠근다 (의미). "이 테스트가 의미 있나(동어반복 아닌가)", "코드가 스펙의 의도에 맞나"는 hook이 판단하지 못한다. command hook은 의미를 모른다
  • 중간 지대. prompt·agent 타입 hook으로 LLM에게 판단을 시킬 수는 있지만 그건 다시 확률적이다. 품질 점검엔 쓰되, 절대 차단(안전)에는 결정론적 command hook을 쓴다
The Master Prompt

전부 한 번에

여기까지의 여섯 장을 한 번의 프롬프트로 받고 싶다면, 아래를 쓴다. 로드맵부터 가드레일까지 골격을 순서대로 생성한다. 받은 뒤에는 반드시 직접 읽고, 어색한 곳을 고쳐 당신의 언어로 만든다 — 결과물을 리뷰하는 그 능력이, AI를 잘 쓰는 사람의 마지막 조건이다.

전체를 한 번에 세팅하고 싶다면

이 프롬프트 하나면 로드맵부터 가드레일까지 골격을 받습니다. 대괄호 [ ]만 채우세요.

당신은 코딩 비전문가가 AI에게 프로젝트를 안전하게 맡길 수 있도록 돕는 시니어 엔지니어 겸 PM이다. 아래 정보를 입력으로, "코드를 치기 전에 필요한 여섯 장의 문서"를 순서대로 한 번에 생성해줘. 프로젝트: [한 줄 설명, 예: 동네 카페 주문/적립 웹앱] 만드는 이유: [예: 카운터 대기 시간 단축] 사용자: [예: 단골 손님 + 사장님 1명] 선호 기술 스택: [예: Next.js + Supabase / 미정이면 추천] OS: [macOS / Windows / Linux] 절대 제약: [예: 무료·저비용 티어만, 결제 연동 없음, 개인정보 최소 수집] 다음 6개를 이 순서로, 각각 명확히 구분된 섹션으로 만들어줘: 1. 프로젝트 로드맵 - 마일스톤 3~5개(각 달성 기준 한 줄) + 범위 + 비범위. - 할 일 단위로 잘게 쪼개지 말 것. 고수준 지도. 2. 작업 의뢰서(RFP) - 배경 / 목표(측정 가능) / 요구사항 / 제약 / 성공기준. - 비범위를 "제약"에 명시해 AI가 기능을 멋대로 추가하지 못하게. 3. PRD (스펙 주도 개발 형식) - 개요 / 목표·성공지표 / 사용자 스토리(Given-When-Then 최소 5개) / 기술스택+근거 / 아키텍처 / 데이터모델 / 비기능요구(성능·보안) / 우선순위(P0/P1/P2) / 제외범위. - 과설계 금지: RFP에 없는 기능을 추가하지 말 것. P0 남발 금지. 4. 테스트 계획 (TDD, Red-Green) - 사용자 스토리별로 "먼저 작성할 실패 테스트(Red)"를 Given-When-Then으로. 해피 패스 + 경계값 + 예외 케이스 포함. - 규칙 명시: 구현 전에 테스트 먼저, AI는 테스트를 고치지 말고 구현을 고쳐 통과(Green)시킨다, mock은 외부 의존성 경계에서만. 5. PreToolUse hook 골격 (물리적 차단) - settings.json의 hooks.PreToolUse 블록(matcher "Bash"). - 위험 명령(rm -rf, 강제 푸시 등)을 차단하는 스크립트의 동작 설명: 표준 입력 JSON에서 command 검사 → 위험하면 stderr 출력 후 exit code 2로 차단, 아니면 exit 0. - 이것은 "말로 부탁"이 아니라 하네스 차원의 결정론적 차단임을 한 줄로 명시. 6. settings.json (전역 / 프로젝트 공유 / 로컬 스코프 분리) - permissions를 allow / ask / deny로. 위험 명령은 deny(모든 allow보다 우선). - 전역(~/.claude/settings.json) = 위험 명령 deny + 개인 선호 프로젝트 공유(.claude/settings.json) = 팀 표준·hook (git 체크인) 프로젝트 로컬(.claude/settings.local.json) = 민감 토큰 (git 미체크인) - defaultMode는 초보자용으로 추천하고 이유를 적어라. 전체 주의사항: - 코드는 마지막에 나오는 부산물이다. 이 단계에서 실제 구현 코드는 쓰지 마. - 모호한 표현 금지, 측정 가능한 기준으로. - 민감 정보(토큰/키)는 git에 올라가는 파일에 절대 넣지 마. - 각 문서는 바로 다음 문서의 입력이 되도록 일관되게 연결해라. 출력: 위 5개를 순서대로, 각각 마크다운 헤더(## 1. 로드맵 …)로 구분. 마지막에 "다음에 할 일" 체크리스트 5줄.

코드는 마지막이다
먼저 여섯 장의 종이를 깔아라

LLM은 주어진 맥락 안에 갇힌다. 새 결정과 방향, 그리고 결과물을 리뷰하는 일은 — 가드레일을 다 깔아둔 뒤에도 — 여전히 당신의 몫이다.

Sources: 채널톡 CAIO 이경훈 인터뷰 (2026) · Claude Code Settings & Permissions & Hooks, code.claude.com/docs (2026) · GitHub Spec Kit, github.com/github/spec-kit (2025) · Thoughtworks, Spec-Driven Development (2025) · arXiv, Spec-Driven Development in the Age of AI Coding Assistants (2026) · OX Security, Why Spec-Driven Development Breaks Down (2025) · Veracode, GenAI Code Security Report (2025) · METR, Measuring the Impact of AI on Experienced Developer Productivity (2025) · Apiiro, 4x Velocity 10x Vulnerabilities (2025) · Stack Overflow Developer Survey (2025) · GitClear, AI Code Quality (2025) · Atlassian & Asana, Project Roadmap Guides · Wikipedia, Request for Proposal / Product Requirements Document · Addy Osmani, Agentic Engineering (2026) · Kent Beck, Test-Driven Development by Example (2003) · GeekNews(긱뉴스), AI 시대 개발 방법론 SDD+TDD (2025) · Nelson Cowan, The Magical Mystery Four (2001)

Research assisted by Claude · 2026