원칙
에이전트 설정 전체를 받치는 원칙 — 규칙은 부탁 대신 구조로 강제하고, 검증할 수 있는 기준을 먼저 주고, 모델은 판정 칸만 채우고, 실수는 그 실수를 낳은 층에서 고쳐요.
다른 가이드는 무엇을 어떻게 설정했는지 다뤄요. 이 문서는 왜 그렇게 했는지 다뤄요. 원칙은 에이전트 설정 레포의 설계 문서(claude/docs/SKILL-PHILOSOPHY.md·HARNESS-ENGINEERING.md·MODEL-ERA-AUDIT.md)와 작업 원칙(claude/skills/_shared/principles/), 규칙마다 남긴 사고 기록(claude/docs/RULES-EVIDENCE.md)에서 가져왔어요.
부탁하지 않고 구조로 강제해요
"절대 하지 마세요" 같은 문장은 컨텍스트가 길어지면 잊혀요. 구조는 잊히지 않아요. 그래서 규칙을 어느 층에 둘지부터 정해요. 위층일수록 어길 수 없어요.
| 층 | 방법 | 예 |
|---|---|---|
| 권한 없음 | 도구를 아예 주지 않아요 | 탐색 에이전트(claude/agents/explorer.md)에는 Edit·Write 가 없어요 |
| 하드 차단 | settings.json 의 deny·ask | CLAUDE.md·RULES.md·CONTEXT.md·AGENTS.md 편집은 승인을 거쳐요 |
| 조건부 차단 | 훅이 exit 2 로 막아요 | 위험한 명령, 보호 브랜치 force push, --no-verify, Conventional Commits 위반 |
| 판정 소유 | 게이트와 결정적 verifier | 슬라이스 통과 = 테스트 green + 리뷰 PASS |
| 주입·격리 | SessionStart 훅, fork 컨텍스트 | compact 뒤에 커밋·브랜치를 다시 넣고, 리뷰는 분리된 컨텍스트에서 돌아요 |
| 부탁 | CLAUDE.md | 가이드일 뿐이에요. 꼭 지켜야 하면 위층으로 올려요 |
권한으로 못 막는 곳은 사후 verifier 로 막아요. 쓰기 권한을 준 서브에이전트에는 허용 경로 목록을 주고, 돌아오면 git diff --name-only 로 목록 밖 파일을 되돌려요. "자기 폴더만 건드려라"라는 문장은 verifier 가 아니에요.
Bash 차단은 가드 훅 하나에 모았어요. 이유는 두 가지예요.
settings.json의 deny 는 앞부분 일치라서cd x && <명령>처럼 이어 붙인 명령을 못 잡아요.- 라이브
~/.claude/settings.json은 레포 사본에 심링크된 파일이 아니에요. 레포에만 넣은 deny 는 라이브에 없어서 실제로는 아무것도 막지 못했고, 막은 건 훅이었어요.
"끝났어요" 대신 명령 한 줄
"잘 동작해요"는 기준이 아니에요. 작업을 맡길 때 첫 줄에, 끝났을 때 참이어야 할 결과와 그것을 재는 명령을 같이 적어요.
완료: draft PR 이 열려 있다 · check: `pnpm check` · expect: check: ok큰 작업은 플랜 파일의 Acceptance Contract 가 이 줄을 늘려요. 기준 하나에 관측 조건(WHEN … THE … SHALL …)과 그것을 재는 명령이 한 줄로 묶여요. 이 계약은 세 단계를 거쳐요.
- 반증 — 구현 전에 명령을 돌려 red 가 나오는지 봐요. 이미 green 인 기준은 아무것도 가르지 못하니 기준을 고쳐요.
- 동결 — 구현이 시작되면 기준을 해시로 고정해요. 기준을 바꾸려면 사유를 남기고 다시 동결해야 하고, 리뷰가 그 사유를 봐요.
- 자기평가 — 구현하는 모델은 판정 칸(status·evidence)만 채워요. evidence 는 실제로 돌린 명령과, 출력에서 판정을 떠받치는 한 줄이에요. "확인했어요"·"구현되어 있어요"는 통과가 아니라 미검증이에요. 돌았지만 대상을 타지 않은 check(0 tests collected, 필터에 걸린 skip)도 PASS 가 아니에요.
그 자기신고는 스크립트가 검증 원장과 다시 대조해요. 이 형식 전에는 플랜에 - [ ] 로 성공 기준을 적었는데, 그 줄은 아무도 실행하지 않아서 "done"이 모델의 주장으로 끝났어요. 그래서 2026-10-15 에 바꿨어요. 이 장치가 막는 것은 기준이 슬그머니 옮겨 가는 드리프트예요. 위조까지 막지는 못해요.
통과선은 리뷰어에게 보여주지 않아요
리뷰어가 통과선을 알면 그 선에 맞춰요. Critical 을 한 단계 내려서 "통과"를 만들어요. 같은 파일에 "통과선은 무시하라"고 적는 것은 분리가 아니에요. 그래서 통과선을 리뷰어의 컨텍스트에서 물리적으로 뺐어요.
- 통과선은 별도 파일(
GATE.md)에 두고, finding 이 다 나온 뒤 메인 세션만 읽어요. 파인더의 스폰 프롬프트에는 그 파일 이름도 넣지 않아요. - finding 을 내는 파인더는 대화를 모르는 서브에이전트예요. 플랜과 diff, 레포 관례만 받고, 이전 finding 이나 판정은 받지 않아요. 하네스가 끝난 서브에이전트를 다시 부를 수 있으면 파인더 하나가 슬라이스 셋과 그 재리뷰까지 맡고, 그다음 슬라이스에서 새로 띄워요.
리뷰는 두 축으로 봐요. 레포 관례를 따랐는지(Standards), 플랜이 요구한 것을 만들었는지(Spec fidelity)예요. 관례가 완벽해도 엉뚱한 것을 만들었으면 실패예요.
루프는 결정적 체크로 끝내고, 약한 기준은 사람이 봐요
고치고 다시 확인하는 루프는 테스트·lint·typecheck 같은 결정적 체크로만 끝나요. 모델이 "된 것 같아요"라고 말해서 끝나는 루프는 없어요. 같은 이슈가 두 번 연속 나오거나, 한 슬라이스에서 세 번 안에 통과하지 못하면 멈추고 보고해요.
설계와 스코프는 기준이 약해서 루프로 돌리지 않아요. 사람이 정해요. 다만 매번 묻지 않고 권장안으로 정한 뒤 draft PR 본문의 "Auto-decided"에 적어요. 거기서 제가 보고 고쳐요. 머지는 제가 해요.
실수는 그 실수를 낳은 층에서 고쳐요
에이전트가 피할 수 있었던 실수는 나쁜 diff 이기 전에, diff 주변 시스템에 대한 피드백이에요. 코드만 고치면 다음 런도 같은 실수를 해요. 그래서 실수를 낳은 층(spec, 도메인 용어, 레포 지침, 검증, 구조)을 고쳐요. diff 는 한 번 쓰이지만 그 층은 다음 런마다 쓰여요. 신호가 없으면 규칙을 미리 만들지 않아요.
규칙마다 왜 생겼는지를 날짜와 함께 사고 기록에 남겨요. 규칙 파일에는 짧은 명령형만 두고, 근거는 사고 기록에 둬요.
더하기 전에 빼요
판정 도구는 줄 수가 아니라 deletion test 예요. 지워도 결과가 같으면 중복이고, 다르면 고유해요.
- 계획 리뷰 렌즈 셋(제품·디자인·엔지니어링)을 하나로 합쳤다가 되돌렸어요. 페르소나·체크 항목·판정 축이 전부 달라서, 하나를 지우면 결과가 달라졌어요. 합친 쪽은 실측 중앙값이 46턴·출력 22.4k 로, 렌즈 하나(26턴·9.8k)보다 무거웠어요.
- 스킬을 지울지 정할 때 호출 수는 근거로 약했어요. 대부분의 스킬은 사용자가 부르지 않고, 다른 스킬이 본문에서 가리켜서 실행돼요. 그래서 참조 그래프를 봐요. 살아 있는 실행 경로가 가리키면 남기고, 카탈로그 문서만 가리키면 지워요.
package.json스크립트, 설정 파일,--help출력은 그 자체가 정본이에요. 문서가 그것을 다시 적으면 캐시가 되고, 캐시는 낡아요. 문서에는 에이전트가 찾아볼 수 없는 것만 적어요. 안 적힌 관례, 그 선택을 한 이유, 어떤 설정도 알려주지 않는 함정이에요.
정본은 하나
같은 내용이 두 곳에 있으면 언젠가 갈라져요. 정본을 하나 두고 나머지는 차이만 적어요.
- 파이프라인 모양은 공통 계약(base)에 두고, 언어별 차이는 팩(react·ts·nodejs)에, 호출은 라우터에 둬요.
- Claude Code·pi·opencode 가 같이 쓰는 스킬은 영어 정본 하나예요(
agent-skills/). Claude Code 쪽 파일에는 도구 이름과 가용성처럼 하네스마다 다른 것만 표로 적어요. 정책이 다르면 델타가 아니라 정본을 고쳐요. 두 벌을 맞추던 parity 검사는 2026-10-30 에 지웠어요. 맞출 두 벌이 없어서예요. - 두 문서가 서로를 정본으로 가리키면 정본이 없는 거예요.
- 스킬 본문은 작게 두고 세부는 필요할 때 읽는 참조로 빼요. 참조는 한 단계까지만 둬요. 참조가 참조를 다시 가리키면 에이전트가 앞쪽만 읽고 지나가요.
모델이 좋아지면 절차를 지워요
예전 모델을 위해 넣은 절차는 모델이 좋아지면 비용만 남아요. 절차를 다섯 부류로 나눠 판정해요.
| 부류 | 예 | 판정 |
|---|---|---|
| 모델 한계 보완 | "패스당 관심사 하나", 역할 쪼개기 | 지우거나 합쳐요 |
| 이중 평가 | 같은 것을 두 번 채점 | 하나만 남겨요 |
| 안 쓰이는 분해 | 실행 경로가 가리키지만 한 번도 호출되지 않는 모드·역할 | 참조 그래프를 따라 지워요 |
| 결정적 verifier·구조 분리 | 테스트, 훅, 리뷰어 분리 | 모델 능력과 무관하니 남겨요 |
| 약한 구현자용 명세 | 싼 모델 워커가 읽는 문서 | 읽는 쪽이 약하면 남겨요 |
지우기 전에 세 가지를 물어요. 무엇을 막으려고 넣었나요? 지금도 발화하나요(최근 로그)? 지우면 결과가 달라지나요? 달라지는 것이 결함을 잡는 일이면, 그 절차는 verifier 로 다시 분류해요.
작업 원칙
상황마다 읽는 짧은 원칙 파일이 19개 있어요. 규칙 파일에는 언제 읽는지만 적고, 본문은 그때 읽어요. 흔한 조언과 겹치는 것은 빼고, 트리거가 구체적인 것만 옮겨요.
| 원칙 | 언제 | 내용 |
|---|---|---|
| verify-primary-source | 사실·수치를 문서에 적기 전 | 1차 출처를 직접 읽었는지 봐요. 들은 것이면 "미검증"으로 적어요 |
| attack-the-premise | 같은 전제의 수정 두 번이 같은 체크에 실패했을 때 | 세 번째 수정 전에 공유된 전제를 한 문장으로 쓰고 직접 검증해요 |
| explain-the-number | 측정 결과를 보고할 때 | "왜 두 배가 아닌가"를 묻고 병목을 이름으로 대요. 실행 횟수와 편차를 같이 적어요 |
| subtract-before-you-add | 시스템·프롬프트·규칙을 늘릴 때 | 먼저 복잡도를 빼요. 추측한 엣지 케이스가 아니라 관측된 사용에 맞춰 설계해요 |
출처
설계 문서(SKILL-PHILOSOPHY.md)는 mattpocock/skills(MIT)의 엔지니어링 규율에서 출발했어요. 작업 원칙 19개 중 15개는 cursor/plugins 의 pstack principle(MIT)을 옮겨 고친 것이에요. Acceptance Contract 의 동결·hard threshold·evidence 는 Anthropic 의 장시간 에이전트 하네스 글 두 편과 Claude Code best practices("show evidence rather than asserting success")에서 왔어요.
확인
제 하네스에 같은 원칙이 서 있는지는 이렇게 봐요.
- 다음 작업의 완료 기준을 명령 한 줄로 써요. 구현 전에 돌려서 red 가 나오는지 봐요. green 이면 그 기준은 아무것도 재지 않는 거예요.
- 리뷰를 맡기는 프롬프트에 통과 점수나 판정 기준이 들어 있는지 봐요. 들어 있으면 리뷰어가 그 선에 맞춰요.
- 최근에 추가한 규칙 하나를 골라, 왜 생겼는지 적힌 곳을 찾아요. 없으면 다음 사람은 그 규칙을 지워도 되는지 판정할 수 없어요.