Claude Code Docs 해체 분석 (1): 지침 및 메모리 저장
Claude 공식 문서(claude.ai/memory)를 읽으면서 생긴 의문들을 중심으로 정리했다.
자동 메모리가 “모든 세션에 로드된다”의 의미
실제로 저장되는 것은 파일이다.
Claude가 대화 중 유용하다고 판단한 정보를 ~/.claude/projects/<project>/memory/에 마크다운 파일로 기록한다.
그리고 다음 세션이 시작될 때 그 파일들의 인덱스인 MEMORY.md의 첫 200줄을 컨텍스트에 주입한다.
1
2
3
4
~/.claude/projects/<project>/memory/
├── MEMORY.md ← 이 파일의 첫 200줄이 매 세션 로드됨
├── debugging.md
└── preferences.md
대화 내용이 그대로 저장되는 것이 아니라, Claude가 “이건 다음에도 유용하겠다”고 판단한 내용을 작성한다.
대화는 세션이 끝나면 사라지고, 작성된 파일만 남는다.
200줄을 초과하는 메모리 내용은 자동 로드되지 않고, 관련 작업이 생겼을 때만 불러온다.
그래서 MEMORY.md 는 세부 내용 없이 인덱스 역할에 충실해야 하고, 세부 내용은 주제별 파일로 분리하는 구조가 효율적이다.
/init이 제안하는 “개선 사항”의 기준
/init 명령을 실행하면 Claude가 코드베이스를 분석한 뒤 CLAUDE.md 초안을 생성한다.
이 때 CLAUDE.md가 작성되어 있다면, 실제 코드를 기준으로 작성된 CLAUDE.md 파일과의 간극을 찾아 제안한다.
예를 들어 코드베이스에 ESLint 설정은 있는데 CLAUDE.md에 lint 명령이 언급되지 않았다면 이를 추가 제안한다.
테스트 파일 패턴이 존재하는데 테스트 실행 방법이 없다면 그것도 마찬가지다.
처음 프로젝트를 시작할 때 /init으로 기초를 잡고, 이후 협업하면서 필요한 규칙을 점진적으로 추가하는 흐름이 자연스럽다.
/init이 만든 초안을 그대로 쓰는 것보다 팀이 실제로 따르는 컨벤션과 대조해 다듬는 과정이 더 중요하다.
CLAUDE.md와 .claude/rules/
CLAUDE.md 안에서 @파일경로 형식으로 다른 파일을 불러올 수 있다.
경로는 파일명까지 포함한 실제 상대 경로를 사용해야 한다.
1
2
3
4
5
6
7
8
# 프로젝트 컨텍스트
프로젝트 개요는 @./README.md를 참조.
사용 가능한 npm 명령은 @./package.json 참조.
# 작성 규칙
- 코드 스타일: @.claude/rules/code-style.md
- 테스트 작성법: @.claude/rules/testing.md
- git 워크플로우: @.claude/rules/git-workflow.md
@README.md처럼 이미 존재하는 파일을 그대로 참조하면, 같은 내용을 CLAUDE.md에 중복 작성할 필요가 없다.
package.json의 스크립트 목록이나 README의 프로젝트 개요가 자동으로 컨텍스트에 포함된다.
참조된 파일은 최대 5단계 깊이까지 재귀 가져오기가 가능하다.
즉 @.claude/rules/testing.md 안에서 또 다른 파일을 참조할 수 있다는 뜻.
.claude/rules/ 하위 파일들은 이렇게
1) CLAUDE.md에서 @가져오기로 참조되거나
2) paths frontmatter를 통해 조건부로 로드하는
두 가지 방식으로 활용된다.
@ 참조도 없고, paths frontmatter도 없는 파일은 아무데도 적용되지 않는다.
1
2
3
4
5
6
.claude/
├── CLAUDE.md # 핵심 지침만 (200줄 이내) + @참조 포인터
└── rules/
├── code-style.md
├── testing.md
└── git-workflow.md
분리 기준
CLAUDE.md 파일 내부에 작성될 텍스트를 rules로의 분리를 결정하는 기준은 분량이 아니라 조건부 적용 필요 여부이다.
| 조건 | 위치 |
|---|---|
| 모든 작업에 항상 적용 | CLAUDE.md 본문 |
| 특정 경로/파일 패턴에만 적용 | .claude/rules/ + paths frontmatter |
| 분량이 많지만 항상 필요 | CLAUDE.md에서 @rules/...로 참조 |
가령 “인증 관련 파일은 반드시 security review를 거친다”는 규칙은 src/auth/**에만 적용되므로 rules 파일로 분리하는 것이 맞다. 반면 “코드 블록에 언어를 명시한다”는 규칙은 모든 파일에 적용되므로 CLAUDE.md에 두면 된다.
paths frontmatter
paths frontmatter는 CLAUDE.md 본문에는 사용할 수 없고, .claude/rules/ 하위 파일에서만 유효하다.
1
2
3
4
5
6
7
8
9
---
paths:
- "src/api/**/*.ts"
- "src/middleware/**"
---
# API 개발 규칙
- 모든 엔드포인트는 입력 유효성 검사를 포함한다
- 표준 에러 응답 형식을 유지한다
Claude가 src/api/users.ts 같은 파일을 열거나 수정할 때만 이 규칙 파일이 컨텍스트에 포함된다.
관련 없는 파일 작업 시에는 로드되지 않아 컨텍스트 낭비를 줄인다.
paths 외에 다른 특수 frontmatter 태그는 없다.
조건부 로딩이 필요하면 paths를 쓰고, 항상 적용되어야 할 규칙은 CLAUDE.md 본문에 직접 쓰면 된다.
--add-dir 플래그가 필요한 이유
Claude Code를 서브디렉터리에서 실행하거나, 환경변수로 작업 디렉터리를 지정할 때는 해당 경로의 CLAUDE.md가 자동으로 로드되지 않는다.
--add-dir 플래그는 Claude가 신뢰하고 읽을 수 있는 디렉터리를 명시적으로 추가한다.
1
claude --add-dir /path/to/shared-rules
모노레포 환경에서 루트 CLAUDE.md와 패키지별 CLAUDE.md를 함께 적용할 때 유용하다.
플래그 없이는 현재 실행 경로 기준으로만 CLAUDE.md를 탐색하기 때문에 의도한 규칙이 로드되지 않을 수 있다.
모노레포란
모노레포(monorepo)는 여러 패키지나 팀의 코드를 하나의 레포지토리에서 관리하는 구조다.
1
2
3
4
5
6
7
my-repo/
├── CLAUDE.md # 공통 규칙
├── packages/
│ ├── web/
│ │ └── CLAUDE.md # 웹 팀 규칙
│ └── api/
│ └── CLAUDE.md # API 팀 규칙
packages/web 디렉터리에서 Claude Code를 실행하면 루트의 CLAUDE.md는 자동 로드되지 않는다.
--add-dir로 루트 경로를 추가해야 공통 규칙과 패키지별 규칙을 함께 적용할 수 있다.
1
claude --add-dir /path/to/my-repo
심볼릭 링크로 공통 규칙 동기화
여러 프로젝트에서 동일한 규칙을 공유해야 할 때 심볼릭 링크를 활용할 수 있다.
ln은 macOS/Linux 터미널 내장 명령어로, 파일을 가리키는 링크를 생성한다.
ln -s <원본 경로> <링크 경로> 형식으로 사용하며, 이렇게 만들어진 심볼릭 링크(소프트 링크)는 원본 파일을 참조할 뿐 내용을 복사하지 않는다.
링크를 열면 원본 파일이 열리고, 원본을 수정하면 링크를 통해 접근하는 쪽에도 즉시 반영된다.
1
2
3
4
5
6
7
8
9
10
11
# 공통 규칙 원본
~/shared-claude-rules/
├── code-style.md
└── testing.md
# 각 프로젝트에서 심볼릭 링크 생성
ln -s ~/shared-claude-rules/code-style.md \
~/project-a/.claude/rules/code-style.md
ln -s ~/shared-claude-rules/code-style.md \
~/project-b/.claude/rules/code-style.md
원본 파일 하나를 수정하면 링크가 걸린 모든 프로젝트에 즉시 반영된다.
팀 공통 컨벤션을 별도 레포에서 관리하면서 각 프로젝트에 링크만 걸어두는 구조가 가능하다.
관리 설정 — CLAUDE.md는 “부탁”, settings.json은 “법”
CLAUDE.md는 사용자 메시지로 전달되기 때문에 기술적인 강제력이 없다.
지침이 모호하거나 다른 지침과 충돌하면 Claude가 임의로 해석할 수 있다.
반면 settings.json의 관리 설정은 Claude Code가 직접 읽는 제어 파일로, 동작 자체를 제한한다.
1
2
3
4
5
6
7
8
{
"permissions": {
"deny": ["Bash(git push:*)", "Bash(rm:*)"]
},
"sandbox": {
"enabled": true
}
}
위 설정은 Claude가 git push나 rm을 실행하려 해도 기술적으로 차단한다.
CLAUDE.md에 “git push 하지 말 것”이라고 써두는 것과는 차원이 다르다.
적용 범위별 settings.json 위치:
| 파일 경로 | 적용 범위 |
|---|---|
~/.claude/settings.json | 사용자 전체 |
.claude/settings.json | 현재 프로젝트 |
.claude/settings.local.json | 로컬 전용 (git 제외) |
보안 정책이나 특정 명령어 실행 제한처럼 반드시 지켜져야 하는 규칙은 settings.json에, 코딩 스타일처럼 맥락에 따라 유연하게 적용될 규칙은 CLAUDE.md에 두는 것이 맞다.
참고할 수 있는 자료
settings.json의 전체 옵션을 탐구하려면 공식 문서가 출발점이다.
- 공식 문서: Settings, Permissions
- 커뮤니티 가이드: eesel.ai — settings.json 완전 가이드, claudelog.com
- 설정 예제 모음: GitHub — feiskyer/claude-code-settings
permissions.deny가 실제로 차단되지 않는 버그처럼, 설정이 의도대로 동작하지 않는 경우는 anthropics/claude-code GitHub Issues에서 확인할 수 있다.
개인 사용 양식
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// ~/.claude/settings.json (전역, 개인용)
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"model": "claude-sonnet-4-6",
"effortLevel": "medium",
"alwaysThinkingEnabled": true,
"autoUpdatesChannel": "stable",
"cleanupPeriodDays": 30,
"attribution": {
"commit": "Generated with Claude Code",
"pr": "Created with assistance from Claude Code"
},
"permissions": {
"defaultMode": "acceptEdits",
"allow": [
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(ls *)",
"Bash(cat *)",
"Bash(grep *)",
"Bash(find *)",
"Bash(npm run *)",
"Bash(yarn *)",
"Bash(pnpm *)"
],
"deny": [
"Bash(sudo *)",
"Bash(rm -rf *)",
"Bash(git push --force *)",
"Bash(curl *)",
"Bash(wget *)",
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/secrets/**)",
"Read(**/*.key)",
"Read(**/*.pem)",
"Read(~/.ssh/**)"
]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// .claude/settings.json(프로젝트, git commit)
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"includeGitInstructions": true,
"companyAnnouncements": [
"PR은 최소 1명 이상 리뷰 후 머지",
"push 전 npm run test 실행 필수"
],
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run lint:fix)",
"Bash(npm run test *)",
"Bash(npm run build)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force *)",
"Bash(git rebase *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "npx eslint --fix $CLAUDE_FILE_PATH 2>/dev/null || true"
}
]
}
]
}
}
1
2
3
4
5
6
7
8
9
10
// .claude/settings.local.json (개인 로컬, gitignore)
// `.gitignore`에 반드시 추가: .claude/settings.local.json
{
"effortLevel": "high",
"permissions": {
"allow": [
"Bash(curl *)"
]
}
}
claudeMdExcludes와 모노레포 환경
모노레포에서는 여러 팀의 CLAUDE.md가 충돌하거나 서로 간섭할 수 있다.
claudeMdExcludes 설정으로 특정 경로의 CLAUDE.md를 무시할 수 있다.
1
2
3
4
5
{
"claudeMdExcludes": [
"packages/legacy-team/**"
]
}
이 설정은 .claude/settings.local.json에만 두는 것이 원칙이다.
settings.json에 넣으면 레포 전체에 적용되어 다른 팀원에게도 영향을 주기 때문이다.
settings.local.json은 .gitignore에 포함되므로 개인 환경에서만 유효하다.
팀별로 독립적인 규칙 영역이 필요하다면 --add-dir과 claudeMdExcludes를 함께 활용해 각 팀이 자신의 규칙만 로드하도록 구성할 수 있다.
/memory와 /compact의 차이
둘 다 메모리 관련 명령처럼 보이지만 역할이 완전히 다르다.
/memory — 현재 세션에 로드된 모든 CLAUDE.md와 자동 메모리 파일 목록을 보여준다.
파일을 선택하면 에디터에서 바로 열 수 있고, 자동 메모리 켜기/끄기 토글도 여기서 가능하다.
메모리 파일을 조회하고 편집하는 UI다.
/compact — 현재 대화의 컨텍스트 윈도우가 가득 찰 때 사용한다.
대화 내용을 요약하여 컨텍스트를 압축하고, 그 과정에서 CLAUDE.md를 다시 주입한다.
메모리 파일 자체와는 무관하며, 긴 작업 세션을 이어가기 위한 대화 압축 도구다.
/compact 실행 후 CLAUDE.md가 재주입되기 때문에, 긴 세션 중에 CLAUDE.md를 수정했다면 /compact 이후 변경 사항이 반영된다.
사용 기준은 단순하다. 메모리 파일을 보고 싶거나 수정하고 싶으면 /memory, 대화가 너무 길어져서 컨텍스트가 부족해졌으면 /compact다.