-
Claude Code settings.json vs settings.local.json — 왜 둘로 나뉘었나IT 2026. 4. 23. 22:00
왜 파일이 두 개인가
Claude Code를 쓰다 보면 어느 순간 홈 디렉토리에
~/.claude/settings.json과~/.claude/settings.local.json이 나란히 생겨 있다. 이름이 비슷해서 처음에는 둘을 구별하지 않고 아무 쪽에나 설정을 적게 되는데, 이 둘의 역할은 명확하게 나뉘어 있다. 단순히 파일이 쪼개진 것이 아니라 공유 가능한 규칙과 개인 판단을 분리하기 위한 설계 결정이다.이 글에서는 Claude Code의 settings 계층 구조를 정리하고,
.local.json이 접미사 하나로 무엇이 달라지는지, 그리고 어떤 설정을 어느 파일에 두는 것이 최선인지를 개인 환경의 실제 구성을 예로 들어 정리한다.Claude Code의 Settings 계층
공식 문서에서 Claude Code는 설정을 Managed / Project / User / Local의 네 계층으로 설명한다. 그런데 실제로 돌려보면 사용자 홈 디렉토리(
~/.claude/)에도settings.local.json을 두면 읽어간다. 즉 공식 표현은 4계층이지만, Local 패턴(*.local.json)은 프로젝트와 사용자 양쪽 모두에서 동작한다. 이를 풀어쓰면 실제 적용되는 우선순위는 다음 6단계로 보는 편이 정확하다.우선순위가 높은 순부터 정렬하면 아래와 같다.
# 계층 위치 공유 대상 Git 추적 1 Managed 시스템/원격 (예: /etc/claude-code/managed-settings.json)기관 전체 N/A 2 CLI 인자 실행 시 플래그 일회성 N/A 3 Project Local <repo>/.claude/settings.local.json개인 (해당 프로젝트만) 자동 gitignore 4 Project Global <repo>/.claude/settings.json팀 전체 커밋 대상 5 User Local ~/.claude/settings.local.json개인 (모든 프로젝트) 추적 안 함 6 User Global ~/.claude/settings.json개인 (모든 프로젝트) 추적 안 함 예를 들어 User Global에서
Bash(npm run *)을 허용해 두더라도 Project Global에서 거부하면 실제로는 차단된다. 조직이나 팀이 강제하고 싶은 규칙은 위쪽 계층에 두면 아래에서 뚫을 수 없다.한 가지 유의점. 공식 문서에는
~/.claude/settings.local.json이 별도 scope로 명시되어 있지 않다. 그럼에도 실제 동작상 읽히고,.local.json이라는 이름 규약 덕분에 git으로부터 분리하기도 쉬워서, 개인 HITL 허용 목록처럼 사용자 수준에서도 공유 가능한 규칙과 개인 판단을 나누고 싶을 때 유용하게 쓰인다. 다만 공식 지원이 명시되어 있지 않으므로, 사용하기 전에 본인 버전에서 정말 읽히는지 한 번은 확인해 두는 것이 좋다.사용자 홈(
~/.claude/)에 있는 두 파일은 각각 User Global(settings.json)과 User Local(settings.local.json)에 해당한다. 즉 "모든 프로젝트에 공통으로 적용되는 개인 설정"을 두 갈래로 쪼갠 것이며, 같은 키가 겹치면 User Local이 User Global을 덮어쓴다..local.json 접미사가 바꾸는 세 가지
같은
settings인데.local이 붙으면 세 가지가 바뀐다.- Git 추적에서 자동 제외된다. 프로젝트 루트의
.claude/settings.local.json은 Claude Code가 저장소의.gitignore에 자동 등록한다. 개인 오버라이드가 실수로 커밋되어 팀 설정을 오염시키는 사고를 구조적으로 막는다. - 우선순위가 더 높다. 같은 레벨 내에서
settings.json과settings.local.json이 충돌하면 local이 이긴다. 프로젝트 수준에서는 팀 규칙을 그대로 둔 채 개인만 느슨하게 쓸 수 있고, 사용자 수준에서도 기본값과 개인 오버라이드를 분리할 수 있다. - 의미적으로 "개인 판단"을 담는 공간이다. 기술적 차이를 넘어, 이 파일은 "내가 동의했다"는 표시가 담기는 곳이다. 특히 permissions의 allow 목록이 그렇다.
역할 분담 — 규칙은 settings.json, 동의는 settings.local.json
개인 환경에서 두 파일이 어떻게 분담하고 있는지를 보면 설계 의도가 더 잘 보인다. 내
~/.claude/settings.json에는 훅(hooks)만 들어 있다.{ "skipDangerousModePermissionPrompt": true, "hooks": { "PostToolUse": [ { "matcher": "Bash", "hooks": [{ "command": "python3 ~/scripts/hooks/dispatcher_post_bash.py" }] }, { "matcher": "Edit", "hooks": [{ "command": "python3 ~/scripts/hooks/dispatcher_post_edit.py" }] } ], "PreToolUse": [ { "matcher": "Bash", "hooks": [{ "command": "python3 ~/scripts/hooks/dispatcher_pre_bash.py" }] } ], "Stop": [ { "hooks": [{ "command": "python3 ~/scripts/hooks/dispatcher_stop.py" }] } ] } }훅은 감사 로그를 쌓고, 위험한 Bash 명령을 정규식으로 차단하고, 세션 종료 시 후처리를 돈다. 개인이 "누가 편집했는지 보기 싫어서" 끄고 켜는 종류가 아니다. 한번 정해지면 계속 그대로 돌아야 하는 규칙이다. 그래서
settings.json에 둔다.반면
~/.claude/settings.local.json에는 permissions만 있다.{ "permissions": { "allow": [ "Bash(*)", "WebSearch", "WebFetch", "Skill(update-config)", "Read(//home/theojin/**)" ], "deny": [ "Bash(rm -rf *)", "Bash(sudo rm -rf *)", "Bash(git reset --hard*)", "Bash(git push --force*)", "Bash(chmod -R 777*)", "Bash(mkfs *)", "Bash(dd if=*of=/dev/*)" ] } }여기에 들어간 것들은 모두 내가 개인적으로 동의한 판단이다. "Bash 전체를 허용하되 이 몇 가지는 절대 금지"라는 정책은 사람마다 다를 수 있다. 다른 사람에게 강요할 수도 없고, 팀 저장소에 커밋하면 남의 판단을 내 것처럼 쓰게 된다. 그래서 local에 두는 것이 맞다.
요약하면 이런 대응이 자연스럽다.
- settings.json — 모두가 따라야 하는 훅, MCP 서버, 공통 환경 변수, 팀 금지 규칙
- settings.local.json — 개인 HITL 허용 목록, 실험 중인 스킬 권한, 일회성 예외
배열은 덮어쓰지 않고 합쳐진다
한 가지 주의할 점은 permissions의
deny,allow,ask같은 배열 설정이 덮어쓰기가 아니라 병합이라는 사실이다.즉 User의 deny에
Read(.env)가 있고 Project의 deny에Read(secrets/*)가 있다면 결과는 "둘 다 차단"이다. Project가 User 값을 지우지 않는다. 덕분에 팀이 정한 안전 규칙을 개인 오버라이드로 약화시키기가 어렵다. 반대로 개인이 추가하는 금지 목록은 팀 규칙 위에 자연스럽게 얹힌다.이 때문에 다음과 같은 패턴이 안정적이다.
- 절대 풀리면 안 되는 금지 규칙은 상위 계층(User 또는 Project
settings.json)에deny로 박아둔다. - 개인이 자기 책임으로 여는 허용 규칙은
settings.local.json에만 쌓는다. allow를 아무리 채워도deny를 이기지 못하도록 두 개를 분리 관리한다.
왜 이렇게 나눴을까 — 설계 의도
이 구조를 여러 번 만지다 보면 결국 세 가지 관심사가 보인다.
- 공유 가능한 규칙과 개인 판단의 분리. 훅은 공유해도 해가 없지만, "나는 내 홈 디렉토리 전체 읽기를 허용한다" 같은 결정은 다른 사람에게 강요할 수 없다. 같은 파일에 섞이면 커밋 여부를 매번 고민해야 한다.
- 팀 규칙을 덮어쓰지 않는 오버라이드 공간. 개인이 잠깐 느슨하게 쓰고 싶을 때 팀 설정을 직접 편집하면 상대를 위협하는 변경이 된다. local 파일이라는 안전한 오버라이드 공간을 별도로 두면, 팀
settings.json은 건드리지 않은 채 개인만 예외를 적용할 수 있다. - 사고 방지.
.local.json이 자동 gitignore된다는 점 하나만으로, 민감한 허용 규칙이 실수로 저장소에 올라가는 사고를 구조적으로 차단한다. 규칙으로 막는 것이 아니라 기본값으로 막는 쪽이 훨씬 강하다.
결과적으로 이 분리는 "규칙은 투명하게 공유하고, 판단은 개인이 책임진다"는 거버넌스 모델을 파일 구조에 그대로 반영한 것이다.
실전에서의 최선
지금까지 살펴본 내용을 실전용 체크리스트로 정리하면 이렇다.
- 훅은 무조건
settings.json에. 훅은 팀이든 개인이든 "항상 돌아야 하는 규칙"이다. local에 두면 끄고 싶을 때 쉽게 끌 수 있는데, 그게 보통 문제의 시작이다. - permissions의 allow는
settings.local.json에. "나는 이 명령을 이 범위까지 허용한다"는 선언은 개인 판단이다. 공유 파일에 두면 다른 사람의 동의까지 끌어들이는 셈이 된다. - permissions의 deny는 상황에 따라 둘 다. 팀이 강제하고 싶은 deny는
settings.json에, 개인이 추가로 쌓는 deny는settings.local.json에. 배열은 병합되므로 둘을 합친 결과가 그대로 적용된다. - 환경 변수와 API 키는 계층을 구분. 개인 키, 실험용 값은 User 계층의
settings.local.json에. 팀이 공유해야 하는 기본값은 Project의settings.json에. - 의심스러우면 local로. "이걸 공유 파일에 둬도 될까?" 망설여지면 일단 local에 두는 편이 안전하다. 공유로 옮기는 건 나중에 해도 늦지 않지만, 실수로 공유된 설정은 되돌리기 번거롭다.
마치며
settings.json과settings.local.json의 분리는 단순한 파일 정리 문제가 아니다. "어떤 설정이 공유되어야 하고, 어떤 설정은 개인의 책임으로 남아야 하는가"라는 질문에 Claude Code가 내놓은 구조적 답이다.이 관점으로 다시 내 설정을 보면, 훅은 규칙이고 permissions는 동의다. 규칙은 파일 하나로 묶어 공유하고, 동의는 본인만 볼 수 있는 local에 쌓는다. 접미사 하나 차이지만, 그 안에는 "도구가 사람 대신 판단하지 않고, 판단은 개인에게 돌려준다"는 태도가 담겨 있다.
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
ADR, 설계 결정을 기록하는 가장 가벼운 방법 — AI 에이전트가 '왜'를 알게 되는 문서 (1) 2026.04.26 데이터 파이프라인 문서에는 뭘 써야 할까 — architecture.md가 다루지 않는 것 (1) 2026.04.25 아키텍처 문서에는 뭘 써야 할까 — AI 에이전트가 읽는 시대의 architecture.md (0) 2026.04.25 Docs-as-Code로 사이드 프로젝트 문서화하기 — 코드 위키 실전 적용기 (1) 2026.04.25 벡터 DB 온디맨드 관리 — Qdrant와 임베딩 서버의 cold start 실측 (0) 2026.04.24 AI 에이전트가 뭘 했는지 추적하기 — 경량 감사 로그 구축기 (0) 2026.04.23 AI 코딩 에이전트의 권한 관리 — 화이트리스트에서 블랙리스트로 전환한 이유 (0) 2026.04.22 코딩 에이전트는 README.md를 읽을까? — 2026년 4월 실측 현황 (0) 2026.04.22 Context Engineering — AI 코딩 에이전트에 맥락을 주입하는 우선순위 체계 (0) 2026.04.22 Claude Code 스킬과 훅 — AI 코딩 도구에 왜 통제 체계가 필요한가 (1) 2026.04.22 - Git 추적에서 자동 제외된다. 프로젝트 루트의