위키 관리도 자동화하고 사람의 실수를 막자! karpathy llm wiki 위에 얹은 자동화 시스템 (2편)
요약: 1편에서는 「문서 더미는 그 자체로 기억이 아니다」 와 「프롬프트만으로는 풀리지 않는 자리」 까지 짚었습니다.
2편은 그다음 단계의 기록입니다.
같은 폴더를 어떻게 정리했더니 에이전트가 더 이상 두 버전을 같은 무게로 읽지 않게 됐는지에 대해서입니다.
제가 작업 중인 플젝 기준으로 시스템을 적용했는데요,
실제로 어떻게 워크플로우가 돌아갔는지에 대해서도 실제 예시를 통해 더 상세히 서술해보겠습니다.시리즈 3/4 · 본편 2편

4편 시리즈, 지금은 어디
| 프롤로그 | 메모리 아키텍처 업그레이드는 왜 이제 선택이 아닌가 | 시리즈 문제의식, 4편 안내 |
| 본편 1편 | 프롬프트만으로는 안 되는 순간, 문서 메모리는 왜 무너지는가 | 답이 오락가락하는 원인 진단 |
| 본편 2편 (지금 이 글) | 위키 관리도 자동화하고 사람의 실수를 막자! karpathy llm wiki 위에 얹은 자동화 시스템 | 폴더 구조와 frontmatter 로 마찰을 정리한 과정 |
| 본편 3편 (다음) | AI 에이전트 메모리, 파일 더미로는 왜 무너지는가 | git 위에서 오래 가는 운영 구조 |
본편 2편은 「내가 결국 어떤 모양에 도착했는가」 를 보여 주는 글입니다.
본편 1편이 「왜 평범한 폴더로는 안 됐나」 였다면, 이 글은 「그래서 어떻게 바꿨나」 입니다. 정답을 주는 게 아닙니다.
제가 하고 있는 사이드 프로젝트를 예시로 보여 줘서, 읽고계신 여러분의 본인 프로젝트에 무엇을 가져갈지 본인이 판단할 수 있게 하려는 게 글의 궁극적인 목적입니다.
타겟 유저들이 인터뷰에서 피드백 6개를 제공했을 때
타겟 유저(코덕 친구들)들이 서비스에 대한 피드백을 여섯 개를 주었습니다.
디자인 개편, 어드민 화면, 자잘한 다듬기가 섞여 있었습니다. 평소 같으면 사람이 일일이 분류해서 「어디다 어떻게 반영할지」 정리해야 할 양입니다.
그걸 그대로 Claude Code 에 던졌더니 「하나의 큰 개편 기획안 + 별도 어드민 기획안 + 작은 변경 모음」 세 묶음으로 알아서 갈라 정리해 줬습니다. 작업 도중에는 사람이 묻지 않은 곳에서, 데이터 모델이 옛 결정과 틀어져 있던 자리까지 같이 잡아 줬습니다.
이게 가능했던 이유는 단순합니다. 폴더 자체가 「어떤 자료가 어디로 가야 하는지」 를 미리 정해 둔 구조였기 때문입니다. 디자인 피드백은 mobile-design/ 으로, 어드민 변경은 strategy/ 의 새 plan 으로, 자잘한 다듬기는 spec 안의 변경 모음으로. 데이터 모델 어긋남은 frontmatter status 라벨과 decision log 가 함께 검출했습니다.
본 2편은 이 자동 정리가 어떻게 가능했는지의 기록입니다. 1편에서 본 frontmatter 처방 위에 폴더 구조와 운영 컨벤션이 어떻게 얹혔는지를 봅니다.
이 글에서 다룰 것
제목의 "자동화" 가 가리키는 영역을 먼저 합의해 두겠습니다. 본 2편이 다루는 자동화는 정적 컨벤션과 인덱스입니다. frontmatter status 라벨, 번호 prefix, 역할별 폴더, decision log 같이 한 번 정해 두면 다음부터 자리가 알아서 잡히는 장치들입니다. hook, /docs-sync, 정기 점검 같은 실행 자동화는 본편 3편으로 미룹니다. 같은 단어 안에 두 영역이 섞여 있어서 한 번 분리해 두는 편이 안전합니다.
이 네 장치가 라이프사이클로 연관고리가 생기는 순간, 페이지가 다시 읽히는 자료로 바뀝니다. 본편 2편에서 다섯 가지를 봅니다.
- 1편이 끝났을 때 폴더가 어떤 모양이었는지. 출발점에 대해서 서술합니다.
- 핵심 결정 네 가지. 작업 메모리 분리, 번호 prefix, 역할별 폴더 분류, 코드 직결 정의 분리 (실제로의 워크플로우와 당시 프롬프트까지 공개)
- frontmatter
status라벨이 실제 폴더에 어떻게 들어가 있는지 - 루트
CLAUDE.md가 어떻게 진입점 역할을 하는지 - 같은 자리를 다르게 채우는 답들. Notion, Linear,
CLAUDE.md한 장 같은 대안 중 본인에게 무엇이 맞는지 고를 때
이 글의 목표는 파일 이름을 외우게 하는 것이 아닙니다.
블로그를 보고 "내 프로젝트에는 어떤 폴더가 필요하고, 어떤 문서는 매번 읽히면 안 되며, 어떤 문서는 공식 결정으로 남겨야 하는지" 를 판단할 수 있는 수준으로 이해할 수 있으면 됩니다.
그래서 실제 파일 구조를 보여 주되, 각 폴더의 이름보다 역할을 더 중요하게 설명하겠습니다.
1편에서 받은 전제, 폴더 자체가 깨진다는 것
본편 1편의 결론은 한 줄입니다. 저장소 안에 이미 서로 다른 전제가 공존하면, 에이전트는 그중 하나를 골라 그럴듯한 답을 합성합니다.
같은 사실의 두 버전이 폴더 안에 있고 어느 쪽이 활성, 어느 쪽이 폐기인지 명시되어 있지 않으면, 에이전트는 둘 다 같은 무게로 읽고 적당히 종합합니다. 본편 1편이 처방으로 내놓은 한 줄은 frontmatter status 라벨이었습니다. 사람과 에이전트 모두 한 줄에 「이게 활성인지」 를 알 수 있게 한 방책이었습니다.
본편 2편은 이 처방이 폴더 전체에 어떻게 자리 잡았는지의 기록입니다.
1편이 끝났을 때 폴더는 이 모양이었습니다
본편 1편 끝 시점, 그러니까 14개 충돌이 막 발견됐던 그 직후의 폴더 상태입니다.
docs/
├── README.md
├── _claude/
├── strategy/
├── handbook/
├── mobile-design/
├── spec/
├── data-model/
├── .obsidian/
└── dataview-queryboard.md
처음부터 이렇게 깔끔했던 것은 아닙니다. 전략 문서, 화면 문서, 데이터 정의, 인터뷰 노트가 한동안 느슨하게 쌓였고, 충돌을 겪고 나서야 위처럼 역할을 나눴습니다. 이 모양에서 네 가지 결정을 차례로 더해 갔습니다.
여기서 docs/ 는 단순한 문서 보관함이 아닙니다. 코드와 함께 버전 관리되는 팀의 지식 저장소입니다.
Notion 처럼 예쁘게 보이는 도구는 아니지만, commit history 가 남고, branch 에서 실험할 수 있고, 에이전트가 직접 읽고 수정할 수 있다는 장점이 있습니다. (MCP 도 귀찮고 토큰 아까움ㅠ.ㅠ)
이 프로젝트에서는 그 장점이 더 컸습니다. (옵시디언 얘기는 아래에서 후술할 예정)
핵심 결정 네 가지
결정 1, 작업 메모리만 따로 떼어 마스터 폴더로
가장 먼저 한 일은 「에이전트가 매 세션 시작에 무조건 읽어야 할 압축 컨텍스트」 를 별도 폴더로 분리하는 결정이었습니다. 폴더 이름은 docs/_claude/ 로 잡았습니다. 앞에 언더스코어 (_) 를 붙여 알파벳순 정렬에서 위로 올라가게 하는 작은 트릭입니다.
그 안에서 매일 쓰는 핵심 파일은 네 개입니다.
docs/_claude/
├── Instructions.md # 에이전트의 행동 규칙 (톤·금지·메모리 갱신 시그널 등)
├── Context.md # 프로젝트 압축 요약 (제품 한 줄·팀·현재 단계)
├── Memory.md # 사용자 선호·교정 사항 누적 로그
└── Archive-Guide.md # 자동 백업·복구 가이드 (자세한 건 본편 3편)
운영하면서 여기에 보조 파일 다섯 개가 더 붙었습니다.
| 파일 | 역할 |
|---|---|
Frontmatter-Standard.md |
vault 전체 frontmatter 스키마와 decision ID 규칙 |
LLM-Wiki-Pattern.md |
Karpathy LLM wiki 패턴을 이 레포에 맞게 옮긴 운영 모델 |
Obsidian-Setup.md |
Obsidian vault, Dataview, Smart Connections 셋업 |
Maintenance.md |
_claude/ 자체를 점검하는 Dataview queryboard |
README.md |
Layer 2 마스터 폴더 입구 |
핵심은 "모든 파일을 매 세션 다 넣는다" 가 아닙니다. 실제 SessionStart hook 은 Context.md 만 자동 주입합니다. Instructions.md 와 Memory.md 는 루트 CLAUDE.md 와 작업 규칙을 통해 먼저 읽도록 지시하고, 나머지 보조 파일은 필요할 때만 읽습니다. docs/_claude/ 는 컨텍스트에 넣을 파일 묶음이라기보다 컨텍스트를 운영하는 기준 폴더에 가깝습니다.
초보 독자 입장에서는 이 차이가 가장 헷갈릴 수 있습니다. docs/_claude/ 안에 파일이 많다고 해서 전부 매 세션 Claude 머리에 들어가는 게 아닙니다. 매번 넣는 파일은 짧아야 합니다. 이 프로젝트에서는 Context.md 가 그 역할을 합니다. 나머지 파일은 "필요할 때 찾아볼 운영 매뉴얼" 에 가깝습니다. 사람에게도 온보딩 문서 전체를 첫날 다 외우게 하지 않는 것과 같습니다.
결정 2, 번호 prefix 로 읽는 순서를 정한다
각 폴더 안의 주요 문서에는 01_, 02_, 14_, 30_ 같은 번호 prefix 를 붙였습니다. 사람과 에이전트 모두 「제일 먼저 읽어야 할 게 뭔가」 를 한 줄에 알 수 있게 하는 장치입니다.
docs/
├── strategy/
│ ├── 08_mogui_prd.md
│ ├── 14_decision_log.md
│ └── 27_plan_2026-05-02_admin_분류칩_입력UI.md
├── mobile-design/
│ ├── 00_mobile_ia_wireframe.md
│ ├── 04_shade_detail.md
│ └── 13_atlas_shade_map.md
├── spec/
│ ├── 01_error_cases.md
│ └── 02_qa_scenarios.md
└── data-model/
└── 01_erd.md
번호 순서가 곧 「논리 흐름」 입니다. strategy/08_mogui_prd.md 는 제품 정의, strategy/14_decision_log.md 는 공식 결정, strategy/27_plan... 이후 문서는 실행 계획이라는 식입니다. 에이전트도 어느 문서를 먼저 봐야 할지 모를 때 번호 순으로 가면 됩니다.
번호를 안 붙이는 자리도 있습니다. 결정 로그나 인터뷰 노트같이 시간 순으로 누적되는 자료는 폴더 안에 날짜·일련번호로 들어가고, 폴더 자체는 번호 없이 둡니다.
결정 3, 폴더는 「누가 만지는가」 로 자른다
핵심 폴더 네 개를 「누가 주로 만지는가」 기준으로 잘랐습니다.
| 폴더 | 누가 만지나 | 무엇이 들어가나 |
|---|---|---|
handbook/ |
모두 | 한장 요약, 온보딩, 용어 사전 |
strategy/ |
PM·기획 위주 | PRD, 가설, 계획 문서, 결정 로그 |
mobile-design/ |
디자이너 + PM | 모바일 IA, 화면 흐름, UX 정책, 디자인 토큰 |
spec/ |
개발자 + QA | 에러 케이스, QA 시나리오, 인터뷰 운영 스펙 |
data-model/ |
개발자 | ERD, DBML, Supabase 스키마 안내 |
.obsidian/ |
사람 | vault 설정, 플러그인 baseline |
「기능별」 분류 (auth/, payment/ 같은) 가 아니라 「역할별」 분류로 갔습니다. 사이드 프로젝트는 사람이 적고, 어느 폴더를 누가 만지는지가 더 직관적이라 이쪽을 택했습니다.
여기에 docs/README.md 가 전체 지도 역할을 합니다. 신규 개발자는 handbook/ 으로, PM·전략을 보는 사람은 strategy/ 로, 화면을 보는 사람은 mobile-design/ 으로, AI 컨텍스트 시스템을 보는 사람은 _claude/ 로 들어가게 되어 있습니다. 실제로 docs/README.md 는 이 진입점을 표로 정리해 둡니다.
이 방식의 trade-off 도 있습니다. 역할별 폴더는 작은 팀에서는 직관적이지만, 서비스가 커지면 기능별 문서가 더 필요해질 수 있습니다. auth, billing, search 같은 기능 단위로 팀이 갈라지는 순간에는 역할별 폴더만으로는 부족합니다. 그래서 이 구조는 "영원한 정답" 이 아니라 현재 팀 규모와 작업 방식에 맞춘 선택입니다. 중요한 것은 폴더 이름이 아니라, 문서를 찾는 사람이 길을 잃지 않는 것입니다.
결정 4, 코드와 직결된 정의는 별도 파일로
데이터베이스 스키마 같은, 코드와 직접 연결되는 정의는 마크다운이 아니라 별도 형식으로 빼냈습니다.
docs/data-model/
├── 01_erd.md
├── mogui_product_model.dbml
└── mogui_schema.dbml
DBML (Database Markup Language) 은 데이터베이스 테이블과 관계를 텍스트로 정의하는 형식입니다. 다만 최종 truth 는 문서가 아니라 실제 Supabase DB 와 supabase/migrations/ 입니다. DBML 은 사람이 보는 설계도이고, 마크다운 문서들은 그 설계도를 안내합니다.
이 결정은 단순한 파일 형식 선택이 아니라, 어느 정보가 어디에 있어야 진실의 원천인가를 정하는 자리입니다. 데이터 정의는 코드 (DBML), 결정 로그는 strategy 폴더, 행동 규칙은 _claude/Instructions.md. 같은 사실이 여러 자리에 흩어지지 않게.
이 원칙은 다른 프로젝트에도 그대로 옮길 수 있습니다. API 스펙은 OpenAPI, DB 스키마는 migration, 이벤트 정의는 analytics schema 처럼 각자 더 강한 원천이 있을 수 있습니다. 마크다운은 그 원천을 설명하고 연결하는 문서이지, 항상 최종 truth 가 아닙니다. 이 구분을 안 하면 "문서에는 컬럼이 있는데 DB 에는 없는" 식의 버그가 생깁니다.
frontmatter standard format (제 개인 플젝 기준)
본편 1편에서 정의한 status 라벨 (active / draft / pending / archived / superseded) 이 폴더에 실제로 어떻게 들어가 있는지 보여 드립니다. 여기서 자유롭게 커스텀하셔도 됩니다. 저는 karpathy llm wiki 정석 패턴을 따라서 처리해두었습니다.
docs/strategy/14_decision_log.md (현재 활성 결정 로그):
---
status: active
type: decision-log
updated: 2026-04-29
---
# Decision Log
D14: 모바일 앱 보류 — 데스크톱 사용 시간이 압도적
D17: 영문 송장 우선 (해외 클라이언트 60%)
...
docs/strategy/03_old_pricing_proposal.md (대체된 가격 정책 초안):
---
status: superseded
superseded_by: ../strategy/14_decision_log.md#D17
type: proposal
updated: 2026-03-15
---
# (이 문서는 14_decision_log.md D17 로 대체됨)
# Old Pricing Proposal — 무료 플랜 포함
...
docs/strategy/15_pending_mobile_strategy.md (보류 중인 결정):
---
status: pending
type: proposal
updated: 2026-04-22
---
# Mobile Strategy (PENDING)
> 아직 확정 결정 아님. 본 문서는 논의용 초안.
(본문)
세 자리 모두 frontmatter 한 줄을 보면 「이 문서를 지금 기준으로 봐도 되는가」 를 즉시 알 수 있습니다. 사람도, 에이전트도.
여기에 related: 필드를 붙이면 한 단계 더 좋아집니다. 어떤 PRD 가 특정 결정 로그와 화면 문서에 연결되어 있으면, 에이전트는 PRD 만 읽고 끝내지 않고 함께 봐야 할 후보를 알 수 있습니다. Obsidian 에서는 이 관계가 backlink 로 보이고, Dataview 에서는 status: active 이면서 type: strategy 인 문서만 표로 뽑아 볼 수 있습니다.
다만 이 역시 자동 그래프 메모리는 아닙니다. related: 는 사람이 적거나, 에이전트가 제안하고 사람이 승인한 링크입니다. Smart Connections 가 비슷한 문서를 추천해 줄 수는 있지만, 그 추천이 곧 공식 관계가 되는 것은 아닙니다. 최종 관계는 frontmatter 와 본문 링크로 남겨야 합니다.
루트 CLAUDE.md 가 진입점이 되는 자리
폴더를 아무리 잘 정리해 둬도, 에이전트가 「어디부터 읽어야 하나」 를 모르면 의미가 없습니다. 루트 CLAUDE.md 가 그 진입점 역할을 합니다. 1편에서 본 로딩 메커니즘이 여기서도 핵심입니다.
"Claude Code reads CLAUDE.md files by walking up the directory tree from your current working directory... All discovered files are concatenated into context rather than overriding each other."
(번역: Claude Code 는 현재 디렉토리에서 위로 걸어 올라가며 발견되는 모든
CLAUDE.md를 컨텍스트에 이어 붙인다. 덮어쓰지 않는다.)
이 메커니즘을 활용해 루트 CLAUDE.md 에 다음을 적어 두었습니다.
# Project: Mogui Wiki
## Layer 2 (작업 메모리), 매 세션 먼저 읽어 주세요
답하기 전에 다음 세 파일을 반드시 먼저 읽어 주세요.
- `docs/_claude/Instructions.md` (행동 규칙)
- `docs/_claude/Context.md` (프로젝트 압축 요약)
- `docs/_claude/Memory.md` (누적된 사용자 선호·교정)
## 코드 안전 룰 (우선)
- Supabase 마이그레이션은 새 timestamp 파일로만. 기존 파일 수정 금지.
- 데이터베이스 스키마 변경 시 `docs/data-model/mogui_schema.dbml` 도 함께 갱신.
## Status 라벨 신뢰
- `status: active` 만 현재 기준. `superseded` / `archived` 는 무시.
- 두 active 가 충돌하면 결정 로그 (`docs/strategy/14_decision_log.md`) 우선.
루트 CLAUDE.md 는 약 30~50줄 안에 끝냅니다. 길게 늘리면 그 안에서 지시가 충돌하기 시작합니다. 무엇을 어디서 읽어야 하는지의 지도까지가 역할이고, 디테일은 가리키는 파일들에 있습니다.
이 한 파일이 자리 잡은 뒤로, 새 세션에서 에이전트는 어디부터 읽어야 하는지 잃어버리지 않습니다. 실제 자동 주입은 .claude/hooks/load-context.sh 가 Context.md 를 넣는 방식이고, Instructions.md 와 Memory.md 는 필요할 때 바로 따라 읽게 됩니다. 매번 「우리 프로젝트가 뭐였더라」 를 다시 설명할 필요가 줄었습니다.
여기서도 중요한 trade-off 가 있습니다. CLAUDE.md 에 @docs/_claude/Context.md 처럼 import 를 걸어 매번 로드하게 만들 수도 있습니다. 공식 문서 기준으로 @path import 는 세션 시작 시 함께 컨텍스트에 들어갑니다.
하지만 import 를 많이 걸수록 시작 컨텍스트가 무거워지고, CLAUDE.md 가 커질수록 지시 준수도 떨어질 수 있습니다. 그래서 이 프로젝트는 루트 CLAUDE.md 는 짧은 지도 역할에 두고, 실제 압축 컨텍스트 주입은 hook 으로 분리했습니다. 이 선택은 본편 3편에서 더 자세히 봅니다.
더 심플하게 또 다른 대안들도 고려 가능합니다.
여기까지 읽으면 「이게 정석이구나」 싶을 수 있는데, 본편 2편의 자세는 정반대입니다.
이건 제가 팀플젝 레포에서 구축한 한 가지 예시일 뿐이고, 같은 자리를 다른 답으로 채우는 사람도 많습니다.
| 답 | 어떤 팀에 잘 맞나 | 약점 |
|---|---|---|
| Notion 위주 | 시각화·블록 편집 강함, 비개발자 기여 좋음 | git 추적 안 됨, 에이전트 자동 로드 안 됨 |
| Linear (또는 Jira) | 결정 로그·이슈 트래킹·릴리스 관리 강함 | 「문서」 자리는 약함, 에이전트가 직접 읽기 어려움 |
CLAUDE.md 한 장 (docs/ 없음) |
솔로·작은 팀, 시작 단계 | 규모 커지면 한 파일이 비대해짐, 충돌 추적 어려움 |
본 시리즈 방식 (docs/_claude/ + docs/ 폴더 분리 + frontmatter) |
2~5명 팀, Claude Code 메인, 문서가 어느 정도 누적된 단계 | 셋업 비용 있음, 작은 팀엔 과할 수 있음 |
본인 팀이 솔로이거나 막 시작했으면 CLAUDE.md 한 장에서 출발하는 게 낫습니다.
Notion 을 이미 쓰고 비개발자 기여가 많은 팀이면 Notion 을 메인으로 두고 _claude/ 만 git 으로 두는 하이브리드도 가능합니다.
본 시리즈 방식이 정석이라기보다, 본인 팀, 도구, 규모에 맞는 답이 따로 있다는 쪽에 가깝습니다.
이 글이 보여 드리는 건 그 한 가지 답이 어떻게 생겼는지일 뿐입니다.
제가 Obsidian 을 고른 이유도 대단한 철학 때문은 아닙니다.
docs/ 가 이미 Markdown 이었고, Obsidian 은 그 폴더를 그대로 vault 로 열 수 있었기 때문입니다. 추가 export 나 동기화 없이, git 에 있는 문서가 곧 사람이 보는 wiki 가 됩니다.
반대로 팀이 이미 Notion 에 익숙하고 문서 대부분이 Notion database 로 관리된다면, Notion 을 버릴 이유는 없습니다.
이 시리즈의 핵심은 도구가 아니라 문서 상태와 우선순위를 명시하는 습관 입니다.
실제 팀플젝에서 일어난 일: 피드백 6개를 던졌을 때 무엇이 일어났나
도입에서 짧게 보여드린 사례를 단계별로 따라가 봅니다.
입력 메시지부터 기획안 두 개로 정리되기까지, 사람이 한 일과 시스템이 한 일이 무엇이었는지요.
어떻게 워크플로우가 흘렀는지 구체적 저희 팀 플젝 기준으로 예시를 보여드리겠습니다.
입력, 그냥 던진 메시지
치즈 (팀 멤버 외부 익명) 가 새 세션에 다음을 그대로 붙였습니다.
UI/UX 개선할 것 생각중...
- 홈 탭 UI 대폭 변경: 제목 텍스트 (트위터 발색, 다시 찾기 쉽게) 없애고.
요즘 본 발색·방금 올라온 발색 영역도 다 빼고.
태그 칩 (카테고리·컬러패밀리·제형 등) 들을 카테고리별로 출력해놓고
여러 개 선택해서 탐색할 수 있게.
- 탐색 탭의 팔레트 제거. 완전 제거.
- 탐색 탭의 기준 발색 선택하기도 없애려고.
상세 시트에서 연관 발색 타고 들어가면 됨.
- 어드민이 데이터를 UI 통해 수정할 수 있게
(제품 정보 수정 진입경로가 지금 없음, 으악).
- 상세 페이지 polish (버튼 크기·제품명 위치·중복 컴포넌트 제거 등).
- 자잘한 UI 수정 (시트 너비 같은 거).
이건 다 코덕 트친들의 제너럴한 피드백. 어드민 빼고.
치즈는 따로 정리해 달라고 하지 않았습니다. 그냥 던졌습니다. /docs-sync 같은 슬래시 커맨드도 명시적으로 호출하지 않았습니다. 그런데도 다음 단계가 자연스럽게 진행됐습니다.
분류, Claude 가 자동으로 갈라 정리
Claude 가 위 메시지를 보고 응답한 분류 표입니다.
| 1 | 홈 탭 = 태그 탐색 hub | 큰 변경 | 새 기획안 |
| 2 | 탐색 탭 팔레트 제거 | 작은 변경 | 1 번과 같은 묶음 |
| 3 | 탐색 탭 기준 발색 제거 | 작은 변경 | 1 번과 같은 묶음 |
| 4 | 어드민 제품 정보 수정 UI | 별도 영역 | 별도 기획안 |
| 5 | 상세 페이지 polish | 코드 변경 | 작은 변경 묶음 |
| 6 | 시트 너비 등 polish | 코드 변경 | 작은 변경 묶음 |
다음에 짧은 통찰이 따라왔습니다.
1, 2, 3 은 한 가지 변화의 다른 면입니다. 탐색 입구 (태그 필터·팔레트·기준 발색) 가 탐색 탭 안에 분산되어 있었는데, 그게 홈 탭으로 옮겨가는 흐름입니다. 한 기획안에 묶는 게 자연스럽습니다.
4 는 다른 영역입니다. 권한, 진입 경로, 데이터 모델 결정이 따로 필요합니다.
5, 6 은 기획안을 쓸 가치 없이 바로 코드로 가도 됩니다.
피드백을 한 묶음으로 뭉뚱그리지도, 여섯 개를 다 별도 기획안으로 쪼개지도 않았습니다. 의미상 한 묶음인지 별도 영역인지 작은 변경인지 분류한 결과입니다.
추천, 작업 단위 분리
분류 다음은 작업 단위 추천이었습니다.
- 탐색 패러다임 재정의 기획안 — 1, 2, 3 묶음
- 어드민 데이터 수정 UI 기획안 — 4 단독
- 한 PR 안에 두 개 commit — 5, 6
권고 한 줄도 같이 왔습니다.
기획안은 가볍게 쓰는 게 좋습니다. 배경, 결정, 작업 순서, 끝났다는 기준 정도입니다. 코덕 트친들 피드백을 본문에 그대로 인용해 두는 편이 미래에 도움이 됩니다.
사람 승인
치즈는 한 줄로 답했습니다.
이대로 가자. 기획안 두 개 + 작은 commit.
사전 정리, 작성 직전에 결정해 둘 다섯 가지
승인 후 첫 기획안 (탐색 패러다임 재정의) 을 쓰기 직전에, Claude 가 결정해 둘 거리 다섯 개를 먼저 물었습니다.
기획안 본문에 들어갈 결정 거리:
1. 카테고리 → 컬러패밀리 cascade. 동적 필터인지, 하드코딩인지
2. 컬러패밀리 셔플 단위. 매 방문마다 / 카테고리 바꿀 때마다 / 다시 뽑기 버튼
3. 결과가 0 일 때 처리. 빈 화면 / 마지막 칩 해제 제안
4. 홈 탭 현재 상태. 코드 확인이 필요한가
5. 컬러패밀리 칩에 4 축 메타 입력. 직접 / 자동 / 둘 다
치즈가 한 줄씩 답했고, 기획안 작성이 시작됐습니다.
안 시킨 곳까지 자동으로 짚는다
본문 작성을 시작하기 전에, Claude 가 컬러 분류축 데이터 모델을 확인하다가 다음을 보고했습니다.
잠깐, 다른 그림이 보입니다.
발색 메타 테이블에 4 축 컬럼이 일부 있는데
(채도·웜쿨·명도) "탁기" 가 빠져 있습니다.
코드 안의 4 축 컬럼명과 합의된 결정 문서의 컬럼명도 다릅니다.
(코드: chroma/murk/temp/value
결정 문서: chroma/cloudiness/temperature/lightness)
또 사용자가 발색 올릴 때 입력하는 4 축 점수는
swatch 캡션 본문 끝에 [axes: chroma=3, murk=1, ...] 같이
텍스트로 들어 있습니다. 별도 컬럼으로 분리하는 마이그레이션이
미실행 상태입니다.
이건 탐색 패러다임 재정의 기획안과는 별 작업입니다.
다만 같이 정리하지 않으면 미래에 헷갈릴 자리.
어떻게 할까요?
이 발견이 사례의 핵심입니다. 사람이 「데이터 모델 점검해 달라」 고 한 적이 없습니다. 「홈 탭만 정리하자」 고 했습니다. 그런데도 한 자료를 통합하다가 다른 영역에서 틀어진 곳까지 자동으로 짚어 냈습니다. 위키가 풍부해질수록 LLM 이 영향 범위를 자기가 넓혀 갑니다.
별 작업으로 분리
치즈가 답했습니다.
별도 작업으로 정리해 줘. 이번 기획안엔 짧은 메모만 남기고.
Claude 의 후속 처리는 이렇습니다.
- 탐색 패러다임 재정의 기획안 본문 작성을 진행
- 같은 기획안 끝부분 메모 섹션에 별 작업 안내 두 줄 추가
- 4 축 마이그레이션과 컬럼명 통일은 별 작업으로 미룸
사람의 의도 「지금 홈 탭만 끝내자」 를 정확히 따랐습니다.
실제 커밋에 남은 모양
위 사례가 「대화 안에서 정리된 흐름」이라면, 실제 repo 에 남은 사례도 있습니다. d9f6b8f8e9296a7cf682721dd0eb1ea4a1a71656 커밋입니다.
커밋 제목은 이렇습니다.
feat(admin/27): 분류 칩 입력 UI + 카테고리 트리 + 머지 helper + 4축 정리
겉으로 보면 어드민 기능 구현 커밋입니다. 그런데 문서 변경을 같이 보면, 이 글이 말하는 wiki 구조가 실제로 어떻게 쓰였는지 보입니다.
| 같이 움직인 파일 | 무슨 일이 있었나 |
|---|---|
docs/strategy/27_plan_...admin_분류칩_입력UI.md |
status: stub 에서 completed 로 바뀌고 Phase 1~4 완료 내역이 들어감 |
docs/strategy/14_decision_log.md |
D53, D54, D55 결정이 추가됨 |
docs/strategy/30_plan_...shade_detail...md |
4축 dot scatter 위젯이 후속 작업으로 새로 분리됨 |
docs/strategy/28_plan..., 29_plan... |
related: 에 30번 plan 연결이 추가됨 |
docs/_claude/Context.md |
현재 단계 요약에 27_plan completed, 30_plan stub 이 반영됨 |
이 커밋은 "코드 변경 + 문서 변경" 정도가 아닙니다. 구현하면서 생긴 결정은 D 번호로 잠기고, 완료된 계획은 상태가 바뀌고, 다음 작업은 새 plan 으로 빠지고, 매 세션 자동으로 들어가는 압축 컨텍스트도 같이 갱신됐습니다.
위 「대화 안에서 자료를 던졌더니 기획안 두 개가 됐다」 와 같은 패턴이 실제 커밋에서도 보입니다.
새 구현/판단 발생
→ 기존 plan 상태 갱신
→ 공식 결정 D 번호 추가
→ 다음 작업은 새 plan 으로 분리
→ Context.md 압축본 갱신
검색 더미가 아닙니다. 파일이 서로 역할을 나눠 움직이는 wiki 에 가깝습니다.
사람이 한 일은 두 가지
치즈가 한 일은 두 가지였습니다.
- 어느 옵션으로 갈지 정하기 (분류·추천 결과에 「이대로 가자」)
- 데이터 모델 정리는 별 작업으로 미루자고 결정하기
그 외에는 다 Claude 가 했습니다. 폴더 결정, 본문 작성, 페이지 사이 연결, 메모 섹션 갱신, 커밋 시점의 frontmatter 갱신.
그게 가능했던 메커니즘
피드백 6개를 그냥 메시지로 던졌을 뿐인데 자동 분류 → 기획안 추천 → 데이터 모델 점검까지 진행됐습니다. 다섯 자리가 미리 깔려 있어서 가능한 흐름이었습니다.

다섯 자리를 차례로 짚어 봅니다.
1자리, SessionStart hook 으로 압축 컨텍스트가 자동 주입
.claude/hooks/load-context.sh 가 SessionStart 시점에 등록되어 있습니다. 10줄짜리 단순 cat 스크립트로, docs/_claude/Context.md 본문을 stdout 으로 출력합니다.
Claude Code 의 약속에 따라 SessionStart 시점의 stdout 은 그대로 컨텍스트에 들어갑니다. 새 세션을 열면 Context.md (제품 한 줄, 팀, 스택, 핵심 결정, 진행 우선순위, 용어 사전) 가 이미 깔린 상태입니다. 사용자가 한 글자도 안 쳤는데 약 10KB 의 압축 컨텍스트가 컨텍스트 윈도우에 있습니다.
2자리, 루트 가 자동 발견
Claude Code 는 현재 디렉터리에서 위로 올라가며 CLAUDE.md 를 찾고, 그 본문을 컨텍스트로 합칩니다. SessionStart hook 이 아니라 Claude Code 자체의 기본 동작입니다.
이 프로젝트의 루트 CLAUDE.md 가 가진 한 줄이 핵심입니다.
제품/전략/팀 관련 질문은 답하기 전에 반드시 다음 3개 파일을 먼저 읽어라:
- docs/_claude/Instructions.md
- docs/_claude/Context.md
- docs/_claude/Memory.md
3자리, 첫 프롬프트 받으면 Claude 가 Instructions.md 를 직접 read
CLAUDE.md 안내에 따라 Claude 가 docs/_claude/Instructions.md 를 명시적으로 read 합니다. SessionStart hook 으로 자동 주입되는 게 아닙니다. CLAUDE.md 의 「먼저 읽어라」 안내를 따라 Claude 가 직접 읽으러 가는 흐름입니다.
이 차이가 중요합니다. SessionStart hook 으로 자동 주입되는 건 Context.md 한 개입니다. Instructions.md 는 CLAUDE.md 안내가 트리거하는 「반자동 read」 입니다. 이 구조의 장점은 토큰 절약입니다. Instructions.md 는 분량이 적지 않아서 매번 자동 주입하면 매 세션이 무거워집니다. 「Claude 가 필요할 때 읽으러 간다」 가 더 가볍습니다.
4자리, Instructions.md § Docs Workflow 트리거 발동
Instructions.md 안에 다음이 적혀 있습니다.
새 피드백, 회의록, QA 결과, PM 에이전트 산출물, 또는 여러 항목이 섞인 자유 텍스트 입력이 들어오면 다음 순서로 처리:
- 원본 위치 제안
- 영향 문서 후보 제안
- 링크 제안
- 상태 제안
사람 승인 대기
- 승인된 변경만 반영
코덕 피드백 6개가 자유 텍스트로 들어오면 Claude 가 이 트리거를 인식해 plan-first 흐름을 발동합니다. 분류 → 위치 제안 → 영향 → 승인 대기 → 반영의 순서가 그대로 위 사례에서 보입니다.
/docs-sync 슬래시 커맨드는 같은 룰을 명시 호출하는 alias 입니다. 슬래시를 안 쳐도 룰 자체는 이미 살아 있습니다.
5자리, frontmatter 표준이 wiki 갱신을 잡아 줌
승인 후 변경이 반영될 때, frontmatter 의 status, related, updated 같은 필드가 함께 갱신됩니다. 이게 1편의 처방 (status 라벨 + decision log) 과 직접 연결됩니다.
추가로 .githooks/pre-commit 에서 updated 필드를 자동으로 오늘 날짜로 채워 줍니다. 사람이 매번 갱신일을 손으로 채울 일이 없어집니다. 이 hook 디테일은 본편 3편에서 더 봅니다.
다섯 자리를 한 줄로
압축 컨텍스트 자동 주입 + CLAUDE.md 안내 + Instructions.md 의 plan-first 룰 + frontmatter 표준 + commit hook 이 한 줄에 꿰여 있어서, 사람이 슬래시 한 줄 안 쳐도 plan-first 흐름이 작동합니다.
빠진 자리가 하나라도 있으면 흐름이 끊깁니다. Context.md 만 있고 Instructions.md 가 없으면 plan-first 룰이 컨텍스트에 안 들어옵니다. CLAUDE.md 가 안내를 안 하면 Claude 가 Instructions.md 를 read 하지 않습니다. Docs Workflow 트리거가 모호하면 자유 텍스트 입력에서 발동하지 않습니다.
이 시스템을 본인 레포에 옮기려면 다섯 자리를 모두 두는 게 출발점입니다. 어느 한 자리만 두면 절반만 작동합니다.
룰의 두 층, 메모리 자동 갱신과 hook 승격
피드백 6개 사례가 한 번 짠 시스템이 굴러가는 모습이라면, 이 시스템이 시간이 지나면서 어떻게 룰을 더해 가는지의 사례도 있습니다. 이모지 차단 룰이 대표입니다. 한 그림으로 보면 이렇습니다.

위쪽 갈래 (부탁 layer) 와 아래쪽 갈래 (강제 layer) 가 합쳐지는 자리에서 100% 재현이 만들어집니다. 차례로 풀어 봅니다.
사용자 발화 → Memory.md 자동 갱신

도리토가 평범한 대화 중 한 줄 던졌습니다.


이모지 극혐. 기술 글이나 문서에 쓰지 마.
명령을 내리거나 슬래시를 친 건 아닙니다. 그런데도 Claude 가 직접 docs/_claude/Memory.md 의 Corrections 섹션에 한 줄을 추가하고 보고했습니다.
Memory.md 의 Corrections 섹션에 추가했어요.
- 2026-04-27 — 기술 글, 문서 작성 시 이모지를 쓰지 않는다. 사용자가 강하게 금지함.
이게 가능한 이유는 Instructions.md 의 § Memory Update Protocol 에 트리거가 적혀 있기 때문입니다.
"그렇게 하지마 / 이건 별로" → § Corrections 에 한 줄 추가
도리토가 「극혐」 같은 강한 부정 표현을 쓰면, Claude 가 그걸 Corrections 트리거로 인식해 자동으로 메모리에 누적합니다. 사람이 손으로 메모리 파일을 열어 줄 추가할 필요가 없습니다.
부탁만으로는 안 풀린 자리
문제는 텍스트 한 줄로 적힌 룰이 LLM 의 기본 경향 (이모지로 톤을 부드럽게 하려는 습관) 을 항상 이기지는 못한다는 점입니다. 특히 첫 응답에서 무의식적으로 이모지가 끼어듭니다. 1편의 결론 (「부탁만으로 안 풀린다」) 과 같은 메커니즘입니다.
hook 으로 승격, 도구 호출 단계에서 차단
도리토가 한 줄 더 던졌습니다.
계속 이모지 왤케 쓰냐? 본문에 이모지 들어가는 것 자체를 하지못하게 강제해 ㅡㅡ
(라는 맥락으로 말 하니까 알아서 hook 만들까여? 제안해줌)
Claude 가 만든 결과는 두 곳에 들어갑니다. .claude/settings.json 의 PreToolUse hook 등록 (Write|Edit 매칭) + .claude/hooks/no-emoji-check.sh 검사 스크립트입니다. 핵심만 보면 이렇습니다.
#!/bin/bash
# <repo>/.claude/hooks/no-emoji-check.sh — PreToolUse hook (Write|Edit): block emojis from being written
# Why: docs/_claude/Memory.md Corrections 행 = "기술 글·문서 작성 시 이모지 금지" (2026-04-27).
# 사용자가 강하게 금지함. 이 hook 가 Write/Edit 의 도구 입력을 검사해 강제.
# 발견 시 텍스트 대안 (안 됨, 금지, 가능, 주의 등) 으로 다시 쓰도록 deny.
set -euo pipefail
INPUT=$(cat)
# Self-skip: hook 인프라 파일 (.claude/hooks/*) 은 검사 제외.
# 이유: hook 본인 코드의 regex 정의나 주석 안 unicode 글자가 본인 검사에 걸려
# hook 자체를 수정 못하는 deadlock 방지. (read-only intentional unicode.)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ "$FILE_PATH" == *.claude/hooks/* ]]; then
exit 0
fi
# Extract content from Write (.content) or Edit (.new_string) tool inputs.
CONTENT=$(echo "$INPUT" | jq -r '
.tool_input.content //
.tool_input.new_string //
empty
')
if [[ -z "$CONTENT" ]]; then
exit 0
fi
# Detect emojis. Unicode ranges:
# - U+1F000 to U+1FAFF: 본격 emoji block (얼굴 / 음식 / 동물 등)
# - U+2600 to U+27BF : misc symbols / dingbats (체크 / 경고 / 별 등)
# - U+2B00 to U+2BFF : misc symbols / arrows (블록 사각형 등)
# Excluded on purpose: 화살표 (U+2190-U+21FF), 곱셈 기호 (U+00D7) — 기술 글 자주 씀.
#
# Fail-closed: detector (python3) 실패 시 deny — 검사기 못 돌면 이모지가
# 슬쩍 통과할 위험이 있어 안전 차단. stderr 는 임시 파일로 분리 capture 해서
# 사용자에게 원인 보임.
TMPERR=$(mktemp)
trap 'rm -f "$TMPERR"' EXIT
if ! EMOJIS=$(echo "$CONTENT" | python3 -c "
import sys, re
content = sys.stdin.read()
pattern = re.compile('[\U0001F000-\U0001FAFF☀-➿⬀-⯿]')
matches = pattern.findall(content)
if matches:
seen = []
for c in matches:
if c not in seen:
seen.append(c)
print(','.join(seen[:5]))
" 2>"$TMPERR"); then
ERR_MSG=$(cat "$TMPERR")
jq -n --arg err "$ERR_MSG" '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: ("[Hook] no-emoji-check.sh detector 실행 실패 — 안전 차단 (fail-closed). 원인: " + $err + ". python3 가 PATH 에 있는지 / 입력 인코딩 확인.")
}
}'
exit 0
fi
if [[ -n "$EMOJIS" ]]; then
jq -n --arg emojis "$EMOJIS" '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: ("[Hook] 이모지 금지 — 텍스트 대안 사용 (안 됨, 금지, 가능, 주의 등). 발견: " + $emojis)
}
}'
fi
exit 0
PreToolUse hook 의 약속 (deny JSON 을 출력하면 도구 호출이 차단됨) 을 활용합니다. fail-closed 로 동작해서, 검사기 (python3) 가 깨졌을 때도 안전 차단 쪽으로 빠집니다.
self-skip 로직도 들어 있어서 hook 본인 코드 안의 정규식 안 unicode 글자가 본인 검사에 걸려 hook 자체를 수정 못 하는 deadlock 도 피했습니다.
이모지가 들어간 파일은 그 뒤로 단 한 번도 commit 되지 않았습니다. Claude 가 어기려 해도 도구 호출 단계에서 막힙니다.
룰이 두 층에 산다
같은 룰 (이모지 금지) 이 두 층에 자리합니다.
| Memory.md 의 한 줄 | 부탁 | 약 80% |
| PreToolUse hook | 강제 차단 | 100% |
메모리 파일의 한 줄만 있어도 80% 는 작동합니다. 마지막 20% (첫 응답에서 무의식 중에 이모지가 끼어드는 예외) 가 안 풀립니다.
그걸 hook 으로 강제하면 100% 가 됩니다.
본 글의 자리에서 이 사례가 가지는 의미
본 2편의 자동화 = 정적 컨벤션 + 인덱스 라고 도입에서 합의했습니다. 이모지 차단 hook 은 실행 자동화 영역이라 본편 3편에서 더 자세히 다룹니다.
다만 이 사례를 한 자리 미리 둔 이유가 있습니다. 메모리 시스템이 한 번 짠 뒤 끝이 아니라, 시간이 지나면서 룰을 학습하고 필요하면 hook 으로 승격까지 한다는 점입니다. 정적 컨벤션은 출발점이고, 같은 룰이 반복적으로 어겨질 때 실행 자동화로 옮겨 가는 단계까지가 한 묶음입니다. 본편 3편에서 hook 의 다섯 시점, 슬래시 커맨드, 자동 백업, 정기 점검을 차례로 봅니다.
남는 것
폴더 정리는 「잘 분류하는 일」 이 아니라 「읽는 순서, 역할, 상태가 한 줄에 보이게 하는 일」 입니다.
이 글에서 본 네 가지 결정 (작업 메모리 분리, 번호 prefix, 역할별 폴더, 코드 직결 정의 분리) 은 각각 따로 보면 평범합니다.
한 줄에 꿰이면 폴더가 「다시 읽히는 자료」 로 바뀝니다. 사람도 에이전트도 매번 처음 보는 사람처럼 헤매지 않게 됩니다.

본인 프로젝트의 docs/ 도 비슷한 모양이라면, 위 네 가지 중 하나라도 적용해 보세요.
_claude/ 마스터 폴더 분리만 해도 새 세션마다 컨텍스트 다시 설명하는 비용이 절반으로 줄어듭니다.
「어디서 시작」 의 첫 번째 가져갈 만한 행동입니다.
다음 글 (본편 3편) 에서는, 위 구조가 시간이 지나면서도 깨지지 않게 만드는 장치를 봅니다.
새 결정이 들어오면 /docs-sync 로 영향 문서를 먼저 제안하게 하고, 일주일에 한 번 정합성 점검을 돌리고, Memory.md 가 잘못 덮어쓰였을 때 복구할 수 있게 백업 루틴을 둔 방식입니다. 자동으로 모든 문제가 해결되는 건 아니지만, 사람이 봐야 할 지점을 훨씬 작게 줄여 줍니다.
2편의 한 문장 결론은 이것입니다. docs 를 메모리처럼 쓰려면 폴더가 아니라 읽는 규칙을 설계해야 합니다.
3편은 그 읽는 규칙을 Claude Code 안에서 어떻게 실행 장치로 묶었는지 다룹니다.
읽어주셔서 감사합니다! 다음 편에서 만나요 !
'AI 메모리 관리 시스템 (연재 중)' 카테고리의 다른 글
| [AX 사내도입까지? 시즌 2-01] Dorito's AI Agent Memory System (진행 중) (1) | 2026.06.24 |
|---|---|
| [AI 메모리 시스템 적용기 회고:03편] AI 메모리는 왜 다시 무너지는가 — 자동화와 복구 루틴 (5) | 2026.05.03 |
| [AI 메모리 시스템 적용기 회고:01편] 문서를 많이 줬는데 AI는 왜 더 헷갈렸을까 (0) | 2026.04.27 |
| [AI 메모리 시스템 적용기 회고:프롤로그] AI를 잘 쓰려면, 프롬프트보다 먼저 메모리를 설계해야 한다 (4) | 2026.04.26 |