10회차: 모든 내용을 읽은 후, 자신의 리포지토리에 가장 먼저 가져와야 할 3가지는 무엇인가
요약
이 글은 Claude Code를 활용한 자율 운영 기반 구축 시리즈의 10번째 회차로, 독자들이 자신의 리포지토리에 가장 먼저 도입해야 할 핵심 요소들을 정리합니다. 기존 9회에 걸쳐 다룬 복잡한 시스템을 한 번에 적용하기보다, 우선순위를 정해 단계적으로 가져와야 함을 강조하며 실질적인 가이드를 제공합니다.
핵심 포인트
- Claude Code 기반의 자율 운영 리포지토리 구축 방법을 제시함.
- 시스템 도입 시 모든 기능을 한 번에 넣기보다 우선순위가 중요함.
- 각 회차별 핵심 기능(프레임워크, 후크 등)을 정리하여 적용 가이드를 제공함.
이 글은 시리즈 「자율 운영의 기반을 한 권으로 통째로 읽기: claude-code-repository-base 전격 해부」의 제10회(총 10회)입니다. Claude Code에 매번 같은 지시를 할 필요가 없도록, 규칙(Rule), 후크(Hook), 스킬(Skill), 도구(Tool)를 한 세트로 모아 공개한 자작 리포지토리 kai-kou/claude-code-repository-base (MIT)를 만든 본인이 해설하는 연재입니다. 설계 의도뿐만 아니라, 실제로 작동시켜 확인한 결과(본인조차 알지 못했던 허점 포함)를 그대로 담았습니다. 게재되는 실행 결과와 수치는 모두 각 회 작성 시점에서 다시 취합하고 검증한 커밋 SHA를 매회 서두에 기재합니다.
자신의 리포지토리에서 재현하고 싶은 분들을 위해: 같은 리포지토리를 「어떻게 넣고, 어떻게 돌리고, 어떻게 추종할 것인가」의 절차서로 작성한 Zenn Book을 공개했습니다(유료 500엔・체험판 있음).
시리즈 전체 목차
- 제1회 Claude Code에 매번 같은 지시를 할 필요가 없도록, 운영 기반을 리포지토리 한 권으로 정리함
- 제2회 git push origin main | tee log로 보호 기능이 통과되어 있었으므로, 명령어 분할로 막음
- 제3회 베이스를 별도의 리포지토리로 배포하는 2가지 경로를 dry-run으로 구동함 (apply-to-repo.sh와 bootstrap.sh)
- 제4회 Stop 후크를 5개 나열했더니 첫 번째 것만 읽혔으므로, 라우터 1개에 통합함
- 제5회 컨텍스트 압축으로 작업이 사라지는 것을, 압축 전후의 2단계 WIP 커밋으로 방지함
- 제6회 sandbox.enabled를 true로 해도 클라우드에서는 bwrap이 없어 허용 목록을 벗어남
- 제7회 「확인해도 될까요?」를 6가지 종류로 한정하자, 그 외는 전부 자율 실행이 되었음
- 제8회 규칙과 교훈을 계속 늘리지 않기 위해, 상주 바이트 예산과 「승격 = 물리 삭제」를 기계적으로 강제함
- 제9회 복수 에이전트가 동시에 작성하는 화이트보드를, 개별 파일 + 단일 집약자로 파괴되지 않게 함
- 제10회 10회분을 읽은 후, 자신의 리포지토리에 가장 먼저 가져와야 할 3가지는 무엇인가 (본문)
이번 회차는 제1회(입구)와 대칭되는 출구의 회입니다. 제1회에서 「모두 읽을 필요는 없다」고 했지만, 그것은 읽는 사람의 관점이었습니다. 가져오는 측면에서도 마찬가지로, 9회의 시스템을 모두 모아서 자신의 리포지토리에 넣으면, 어떤 것이 효과가 있고 어떤 것이 방해가 되는지 알 수 없게 됩니다. 그렇다면, 우선 무엇부터 넣어야 할까요?
대상 독자는 연재를 통독하거나 발췌해서 읽은 후, 자신의 리포지토리에 도입할 우선순위를 정하고 싶은 분입니다.
우선 말씀드립니다. 이번 회차에서는 새로운 명령어 실행이나 수치 취합을 하지 않습니다. 각 회의 결론과 수치는 해당 회 본문에 담긴 값을 「제N회에서 확인했듯이」라는 형식으로 출처(기사 링크)와 함께 재게시합니다. 수치의 검증 시점 커밋은 매회 서두에 작성되어 있습니다.
| 회 | 제목 | 가져갈 수 있는 것 | 보장 수준 | 도입 비용 |
|---|---|---|---|---|
| 1 | 운영 기반을 리포지토리 한 권으로 정리함 | 🔒와 📋를 나누어 읽는 틀 | 프레임워크 | 없음 (읽기만 함) |
| ... | 🔒 | 중 (최초 227건 배치) | ||
| 4 | Stop 후크를 라우터 1개에 통합함 | 등록구와 메시지의 집약점을 하나로 하는 형태 | 🔒 | 중 (서브후크 5개) |
| 5 | 압축 전후의 2단계 WIP 커밋 | 사라질 수 있는 이벤트의 앞뒤 양쪽에 보존을 두는 형태 | 🔒(클라우드만) | 중 (57행 + 75행・발화 조건 있음) |
| ... | ||||
| 보장 수준 열은 README의 구분에 따라 본 회차에서 제가 할당한 것입니다. 도입 비용은 각 회 본문에 나오는 파일 수/행수/전제조건으로부터 상대적으로 매긴 대략적인 기준으로, 작업 시간을 측정한 것은 아닙니다. |
제1회에서 소개했듯이, README에서는 도입하여 얻을 수 있는 것을 2단계로 나누어 작성하고 있습니다.
🔒 기계적으로 강제되는 것: 후크나 스크립트가 실제로 블록하는 것. 지시를 잊어도 사고가 일어나지 않음 -
📋 운영 규칙으로 정의되는 것: Claude가 규칙을 읽고 따르는 전제적인 것. 코드는 강제하지 않음
표를 보면, 10회 중 📋가 주역인 것은 제7회뿐이며, 나머지는 🔒의 메커니즘입니다. 다만, 🔒 회도 조건부인 경우가 많아, 제5회는 클라우드 실행 환경에서만 발화하고, 제6회는 설정에 적혀 있어도 작동하지 않는 계층이 있었습니다. 🔒 이라는 기호는 '기계가 판정한다'는 것을 보여줄 뿐, 어떤 환경에서도 작동한다는 것까지는 의미하지 않습니다.
선택하는 기준은 3가지로 삼았습니다.
- 의존하는 주변 도구가 적다: 다른 후크나 도구가 갖춰져 있지 않으면 작동하지 않는 상태가 되지 않음 -
1 파일(또는 몇 개의 파일)로 완결된다: 넣은 것과 효과를 본 것이 대응할 수 있음 -
효과가 그 자리에서 확인 가능하다: 넣자마자, 작동하고 있는지 자신의 눈으로 볼 수 있음
이 3가지를 우선한 것은, 첫 번째 항목에서 '넣었는데 작동하는지 알 수 없는' 상태를 만들면, 다음을 넣을 판단 근거가 사라지기 때문입니다. 표의 도입 코스트가 '낮음(低)'인 행부터 이 기준에 맞는 것을 3가지 골랐습니다.
3점에 순위를 매기지는 않았습니다. 자신의 리포지토리에서 어려움을 겪는 것에 가까운 것부터 1개를 선택해 주세요.
.claude/hooks/pre-git-push-check.sh
은 커맨드 문자열을 ||
&&
;
|
또는 do
/ done`
등으로 세그먼트로 나누고, 세그먼트별로 push 대상을 판정합니다. 변수 전개나 eval을 포함하여 정적으로 읽을 수 없는 것은 block 쪽에 배치합니다(제2회). base에서는 settings.json의 PreToolUse에 pre-tool-use-router.sh를 단 하나만 등록하고, git과 push가 모두 단어로 나타난 커맨드를 이 후크로 보냅니다.
3점 중 1번째를 선택한 것은, 기준 3을 가장 명확하게 충족하기 때문입니다. --self-test를 붙여 실행하면 50개의 케이스를 돌려 기대값과 비교하므로, 넣자마자 작동하는지 확인할 수 있습니다. 제2회에서 확인했듯이, 작업 브랜치에서는 50건 모두 통과하고, main에서는 git push --tags의 1건만 실패하여 49건이 통과합니다. clone 직후에는 main에 있으므로, 작업 브랜치로 전환한 후에 실행해 주세요.
주의할 점이 하나 있습니다. 라우터에는 제6회에서 본 민감 파일 접근 검사(_sensitive_file_access)도 함께 존재합니다. 라우터 전체를 가져가면 push 가드 외의 검사도 유효해지므로, 어떤 검사가 작동하는지는 가져가는 쪽에서 확인한 후에 사용해야 합니다.
docs/rules/user-confirmation-minimization.md는 사용자에게 확인받을 수 있는 경우를 A-1부터 A-6까지 6줄로 제한한 규칙 문서입니다. main으로의 직접 push, 취소하기 어려운 공개 즉시 수동 실행, 품질 게이트 치명적 NG 시 계속 진행, 서킷 브레이커 발동 후 계속 진행, 신규 마일스톤 추가, 계정/결제 설정 변경 6가지에 한해서는 자율 실행합니다(제7회).
파일 1개로 완결되며, 다른 도구에 의존하지 않는 점에서 기준 1과 2를 충족합니다. base에서는 이 파일을 모든 세션 상주 Hot 계층에 넣었습니다(제8회에서 인용한 ESSENTIAL_RULES의 13개 중 하나). 가져올 때 수정이 필요한 것은 A-2이며, 제7회에서 작성했듯이, 이 줄은 배포처의 공개 수단에 맞춰 구체화한다는 전제가 있습니다.
3점 중, 기준 3을 가장 약하게만 충족하는 것이 이 항목입니다. 📋 이므로, 작동 여부를 기계가 판정해주지 않습니다. 확인할 수 있는 것은, 확인이 요청된 그 자리에서 '이 확인이 6줄 중 어디에 해당하는지'를 스스로 대조해 보는 것뿐입니다. 알림의 @mention까지 제한하고 싶다면, 제7회에서 다룬 분류기 tools/triage_notification.py를 함께 넣으면, --self-test (제7회 시점에서는 28개 케이스 모두 통과)로 동작을 확인할 수 있습니다.
따라 할 가치가 있는 것은 6이라는 숫자가 아닙니다. 제7회의 결론대로, 후보를 '취소할 수 없는 결과로 진행하는지', '사용자 개인의 계정 권한이 필요한지'의 2축에 하나씩 대입하여 걸러내는 절차 쪽입니다.
3번째는 파일이 아니라, 확인 방법입니다. which bwrap와, 허용 목록 외 도메인으로의 curl
2행에서 자신의 실행 환경에 샌드박스 허가 목록이 적용되는지 알 수 있습니다 (제6회).
제6회에서 확인했듯이, base의 settings.json은 sandbox.enabled: true로 허가 목록은 12개 도메인이지만, 집필 세션의 클라우드 실행 환경에는 bwrap이 없어 허가 목록 외의 https://example.com에 HTTP_STATUS:200으로 도착했습니다. 클라우드에서 실제로 작동했던 방어는 세션 컨테이너의 격리・permissions.deny・PreToolUse 훅의 3단계입니다.
설치할 것이 없으므로 기준 1~3을 모두 충족합니다. 1과 2를 가져오기 전에 '지금 내 환경에서 무엇이 막고 있는지'를 알고 있으면, 어떤 단계를 추가해야 할지 판단하기 쉽습니다. 클라우드에서 허가 목록이 작동하지 않았더라도, 그것을 이유로 허가 목록에서 제외해서는 안 됩니다. 제6회에서 작성했듯이, 로컬이나 배포처 환경에서는 같은 설정이 방어로서 작용합니다.
나머지 회차를 제외한 이유도 적겠습니다. 모두 가치가 낮아서가 아니라, 기준 중 어느 하나에 걸렸기 때문입니다.
- Stop 훅의 라우터 (제4회): 서브 훅이 5개 있고, 제4회의 샌드박스에서는 한 번의 Stop으로 3개가 동시에 울리고 WIP 커밋이 1개 늘어났습니다. 부작용이 있으므로, 빈 리포지토리에서 한번 실행해 본 후 적용하는 것이 안전합니다 -
압축 전후 WIP 커밋 (제5회):CLAUDE_CODE_REMOTE=true이고main/master외의 브랜치에서만 작동합니다. 클라우드 운영이 아닌 분에게는 효과가 없습니다 -
상주 바이트 예산과 교훈 상한 (제8회): 기준값 86,683B나 상한 350행/15건은 base의 규모로 정한 값입니다. 제8회에서 작성했듯이, 자신의 상주 규칙을wc -c로 다시 측정하여 기준을 정하는 수고가 먼저 필요합니다 -
토론 화이트보드 (제9회): Python 1개로 완결되지만, 필요한 것은 여러 에이전트에게 서로의 의견을 읽게 하는 토론형을 사용할 경우뿐입니다.
3가지 이상 넣고 싶다면, 개별적으로 복사하기보다 제3회의 scripts/apply-to-repo.sh를 사용하세요. --dry-run은 1개 파일도 수정하지 않고 배치 플랜만 출력합니다. 제3회에서 확인했듯이, 첫 실행에는 227건의 배치가 필요했고, 한 번 적용하여 조상 SHA를 기록한 후에는, base 측이 움직이지 않은 214개 파일에 손대지 않았습니다 (제3회).
제2회에서는 pre-git-push-check.sh --self-test의 git push --tags 케이스가 체크아웃 중인 브랜치가 main일 때만 실패하는 것을 분리했습니다. 기대값은 allow이지만, 플래그만 푸시는 인자 없는 push와 같은 경로로 현재 브랜치를 보기 때문에, main에서는 block이 됩니다. 제2회의 본문에는 당시 상황을 이렇게 썼습니다.
지금 말할 수 있는 건 여기까지입니다. 동작은 재현하여 분리했지만, 자체 테스트 측의 전제 누락은 이 기사 시점에서는 아직 고치지 않았습니다. 발견했다는 단계입니다.
이번 회차의 집필 환경에서는 base 리포지토리의 Issue와 PR을 참조할 수 없었기 때문에, 수정 PR이 나와 있는지, 병합되었는지는 확인할 수 없습니다. 미확인이라서 '수정됨'이라고 쓰지 않습니다. 여기서 말하는 확인은 새로운 명령어 실행이 아니라 GitHub 상의 상태를 보는 것입니다. 현재 상태는 base 리포지토리의 Issue와 PR을 push --tags나 self-test로 검색하면 확인할 수 있습니다.
수정되지 않은 경우라도, 이것은 과잉 블록 측의 실패이지 보호가 우회된 것은 아닙니다. 제2회에서 작성했듯이, 태그를 보내고 싶을 때는 git push origin refs/tags/v1.0.0처럼 보낼 것을 명시하면 통과할 수 있습니다.
한 번씩 읽었을 때는 보이지 않았던 것이, 나열하니 1가지가 있습니다. 작동시켜 확인한 제2~9회 8회 중 7회에서, 문서・댓글・테스트와 실제 동작의 차이가 발견되었습니다. 제가 각 회차 본문에서 센 건 수량입니다.
| 회 | 발견된 불일치 |
|---|---|
| 2 | 자체 테스트의 tags 케이스만 브랜치 의존성 전제가 테스트 코드에 작성되어 있지 않음 |
| ... | security-posture-controls.md에서 bypassPermissions를 true로 적었으나, settings.json에서 해당 행을 찾을 수 없음 |
| 7 | 알림 분류기의 판정 순서가 문서 요약과 코드에서 역순임 |
| 8 | 예산 추이표의 최신 열이 #504에서 멈추고, #648 재교정은 로그에만 기록되어 있음 |
| 9 | 파일명 시각을 <ns>로 적었으나, 생성 코드는 초 단위임 |
위 내용들은 모두 저 자신이 작성한 것이라, 설계한 본인이 다시 읽어도 알아차리지 못하고 실행해 봐야 알 수 있었던 것입니다. 가져오는 분들께 전하고 싶은 것은, 기사나 문서에 '기계적으로 강제된다'고 쓰여 있더라도, 그 보장은 자신의 환경에서 1회 돌려보기 전까지는 가설로 취급해 달라는 것입니다. 3가지 항목을 고르는 기준에 '그 자리에서 효과가 확인될 수 있음'을 넣은 것도 이 때문입니다.
불일치 중에는 동작상의 불일치뿐만 아니라 언어적 불일치도 있습니다. base에서는 기약 경계 외 목록이라는 단어가 4가지 표기로 나뉘어 버린 적이 있어(#490), 그 대책으로 docs/CONTEXT.md라는 색인을 두고 있습니다.
이 색인은 정의를 가지고 있지 않습니다. 정의는 정본의 규칙 문서에 그대로 두고, 색인에는 정식 표기와 사용하지 않는 표기(_Avoid_)만 나열합니다. 새로운 운영 어휘를 쓰기 전에 grep으로 기존 표기에 맞추고, 실제로 분리된 표기만 추가하는 방식으로 운용하며, 오래 할수록 좋지 않다는 것을 lessons-management.md에 적어두었습니다. 정의까지 색인에 담으면, 색인과 정본의 2곳에서 정의가 어긋날 여지가 생기 때문에, 색인의 역할을 표기 통일로만 한정했습니다.
참고로 docs/CONTEXT.md는 base 측에만 두고 있는 색인이며, apply-to-repo.sh로는 하류(downstream)로 동기화되지 않습니다. 따라 할 경우에는 자신의 리포지토리에서 표기가 분리된 단어부터 작성해 보세요.
제4회에서 stop-pr-check.sh가 클라우드에서는 gh 대신 MCP에서의 확인을 안내한다고 적었을 때, gh가 클라우드에서 사용 불가능한 사정 자체는 다른 회차로 미뤘습니다. base에서는 웹 버전에서 제공되지 않는 기능을 다루기 위해 tools/native_fallback.py를 두고 있습니다. probe가 네이티브 기능의 가용성을 판별하여 종료 코드로 반환합니다(0이면 이용 가능, 3이면 세션 내 추가 확인 필요, 4이면 이용 불가능으로 폴백). 사용 가능하다면 스킬 → 워크플로우 → 세션 도구 → claude -p → 최종 수단 순서로 한 단계씩 하향 조정하는 설계입니다. 이번 연재에서 다루지 않은 것은 가부(可否)가 도구의 버전이나 프록시 허용 범위에 따라 변하는 이야기인데, 작성 시점의 결론이 금방 구식이 되기 때문에 그렇습니다. 자세한 내용은 다른 기사에서 다룰 예정입니다.
서두의 질문, 무엇을 먼저 하나 넣어야 하는지에 답하자면, 10회분 전부를 따라 할 필요는 없습니다. 표를 보고 자신의 리포지토리의 어려움과 비슷한 행을 하나 골라주세요. 취소할 수 없는 push가 두렵다면 제2회의 훅(hook)을, 확인 과정에서 무인 실행이 멈춘다면 제7회의 경계(boundary)를, 어떤 방어막이 작동하는지 알 수 없다면 제6회의 2행을 선택하면 됩니다.
어떤 것을 고르든, 넣자마자 자신의 환경에서 1회 돌려보는 것까지를 도입의 일부로 삼아주세요. 이 3가지를 넣는다고 해서 사고가 일어나지 않게 된다고는 말할 수 없습니다. 저 자신도 자신이 작성한 시스템의 불일치에 7번이나 깨달음을 얻었습니다. 말씀드릴 수 있는 것은, 이 3가지가 도입 비용이 낮은 순서로 나열했을 때 맨 앞에 오는 정도입니다.
10회 동안 함께해 주셔서 감사합니다.
-
규칙과 교훈을 계속 늘리지 않기 위해 상주 아르바이트 예산과 '승격 = 물리 삭제'를 기계적으로 강제함 (연재 제8회)
-
'확인해도 될까요?'를 6종류로 한정하자, 그 외는 전부 자율 실행이 됨 (연재 제7회)
-
Stop 훅을 5개 나열했더니 첫 번째 것만 읽혔기 때문에, 라우터 1개로 통합함 (연재 제4회)
-
kai-kou/claude-code-repository-base (MIT)
-
제1회: Claude Code에 매번 같은 지시를 할 필요가 없도록, 운영의 기반을 리포지토리 1개로 통합했습니다
-
제2회: git push origin main | tee log에서 보호(protection)가 무사히 지나갔기 때문에, 명령어 분할로 막았습니다
-
제3회: 베이스를 별도의 리포지토리에 배포하는 두 경로를 dry-run으로 실행합니다 (apply-to-repo.sh와 bootstrap.sh)
-
제4회: Stop 훅(hook)을 5개 나열했더니 첫 번째 것만 읽혔기 때문에, 라우터 1개로 통합했습니다
-
제5회: 컨텍스트 압축으로 작업이 사라지는 것을, 압축 전후의 2단계 WIP 커밋으로 방지했습니다
-
제6회: sandbox.enabled를 true로 설정해도 클라우드에는 bwrap이 없어 허용 목록 외로 지나갔습니다
-
제7회: '확인해 주시겠어요?'를 6가지 유형으로 제한했더니, 그 외의 것은 모두 자율 실행되었습니다
-
제8회: 규칙과 교훈을 계속 늘어나지 않도록, 상주 바이트 예산과 '승격 = 물리 삭제'를 기계적으로 강제했습니다
-
제9회: 여러 에이전트가 동시에 작성하는 화이트보드를, 개별 파일 + 단일 집약자로 고장 나지 않게 했습니다
-
⬅️ 이전 글: 제9회 여러 에이전트가 동시에 작성하는 화이트보드를, 개별 파일 + 단일 집약자로 고장 나지 않게 했습니다
-
➡️ 다음 글: 없음 (총 10회 - 이 글로 완결됩니다)
공개된 회차 (8개 - 어느 회차부터든 읽을 수 있습니다)
- 제1회 Claude Code에 매번 같은 지시를 할 필요가 없도록, 운영의 기반을 리포지토리 1개로 통합했습니다
- 제2회 git push origin main | tee log에서 보호(protection)가 무사히 지나갔기 때문에, 명령어 분할로 막았습니다
- 제3회 베이스를 별도의 리포지토리에 배포하는 두 경로를 dry-run으로 실행합니다 (apply-to-repo.sh와 bootstrap.sh)
- 제4회 Stop 훅(hook)을 5개 나열했더니 첫 번째 것만 읽혔기 때문에, 라우터 1개로 통합했습니다
- 제5회 컨텍스트 압축으로 작업이 사라지는 것을, 압축 전후의 2단계 WIP 커밋으로 방지했습니다
- 제6회 sandbox.enabled를 true로 설정해도 클라우드에는 bwrap이 없어 허용 목록 외로 지나갔습니다
- 제7회 '확인해 주시겠어요?'를 6가지 유형으로 제한했더니, 그 외의 것은 모두 자율 실행되었습니다
- 제8회 규칙과 교훈을 계속 늘어나지 않도록, 상주 바이트 예산과 '승격 = 물리 삭제'를 기계적으로 강제했습니다
자신의 리포지토리에서 재현하고 싶은 분은, 같은 리포지토리를 '어떻게 넣고, 어떻게 돌리고, 어떻게 추종할지'에 대한 매뉴얼인 Zenn Book (유료 500엔 - 체험판 있음)을 참고하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기