Claude Code로 작업하다 보면, npm install이나 git status를 실행할 때마다 "이 도구를 허가하시겠습니까?"라는 프롬프트가 나타나 흐름이 끊길 때가 있다. 매번 엔터를 누르는 것이 은근히 스트레스이며, 긴 세션에서는 체감상 10% 정도의 시간을 빼앗기는 기분이 들었다.
이 기사는 그 프롬프트를 90% 줄이기 위한 settings.json 작성법을 정리한 메모이다. 같은 부분에서 어려움을 겪은 사람들을 위해, 내가 시도했던 allowlist 패턴과 실수했던 포인트들을 남겨둔다.
-
Claude Code를 일상적으로 사용하는 엔지니어
-
도구 허가 프롬프트에 지친 사람
-
.claude/settings.json의 동작을 제대로 정리하고 싶은 사람
-
macOS 14.x(Darwin 24.6.0)
-
Claude Code(/permissions 명령어를 사용할 수 있는 버전) - Node.js 22.x / Python 3.13
-
셸: zsh
-
~/.claude/settings.json의 permissions.allow에 Bash·MCP의 안전한 정형 패턴을 열거
-
프로젝트 고유의 것은 .claude/settings.json에 나누어 작성
-
Bash는 Bash(npm install:*)와 같이 **콜론(:) + 와일드카드(*)**가 필수(이를 모르면 매칭되지 않음)
-
deny는 allow보다 우선순위가 높음(이 부분에서 실수하기 쉬움)
-
위험한 계열(rm -rf, git push --force)은 명시적으로 deny에 넣어 사고 방지
이렇게 하면 npm / git status / gh pr / Read / Grep 등의 프롬프트는 거의 사라진다.
먼저 현재 나오고 있는 프롬프트의 내역을 보고 싶다. 최근 세션의 로그를 집계하여 빈번하게 발생하는 도구를 나열해 주는 /fewer-permission-prompts라는 스킬이 동봉되어 있다.
/fewer-permission-prompts
출력 이미지(내 환경의 예):
[summary] 최근 200 세션 동안 허가 프롬프트가 발생한 도구 상위
- Bash(npm install:*) 42 회
- Bash(git status:*) 35 회
...
이를 바탕으로 settings.json에 추가할 후보를 결정한다. 자신이 일상적으로 여러 번 허가하고 있는 것을 우선하여 allowlist에 넣어가는 것이 정답이다. 처음부터 전부 작성하려고 하면 입도(granularity)가 어긋나게 된다.
~/.claude/settings.json(모든 프로젝트 공통)을 편집한다. 읽기 계열·조사 계열은 기본적으로 allow에 넣어도 문제없다.
{
"permissions": {
"allow": [
...
]
}
}
Read · Grep · Glob과 같은 읽기 전용 도구는 통째로 allow에 넣어도 문제없다. 이것만으로도 프롬프트 수는 대폭 줄어든다.
리포지토리 직하의 .claude/settings.json에 프로젝트 고유의 명령어를 작성한다. 예를 들어 Next.js 프로젝트라면:
{
"permissions": {
"allow": [
...
]
}
}
pnpm과 npm 같은 패키지 매니저(Package Manager)의 차이는 프로젝트 측으로 분리하는 것이 운영상 깔끔하다. 글로벌하게 pnpm을 작성해 버리면 npm 프로젝트에 불필요한 허가가 섞여 들어간다.
Claude Code를 한 번 종료하고 재시작하거나, /config reload로 설정을 재로드한다. 그 후 평소처럼 작업하여 npm install이나 git status에서 프롬프트가 나오지 않는다면 성공이다.
확인용으로 일부러 deny에 넣은 명령어를 실행해 본다:
> git push --force origin main
여기서 "허가하시겠습니까?" 프롬프트가 뜨는지 확인한다. 이것이 뜨지 않는다면 deny가 작동하지 않는 것이다(후술할 주의점 참조).
처음에 이 부분을 깨닫지 못해서 1시간을 허비했다.
NG 예시:
"allow": ["Bash(npm install)"]
이렇게 작성하면 **완전 일치 (Exact Match)**로 취급되어, npm install --save react와 같이 인자(argument)가 포함되어 있으면 매칭되지 않는다. 프롬프트가 계속 나타나며 "allow에 적었는데 왜 안 되지?"라는 상황이 발생한다.
OK 예시:
"allow": ["Bash(npm install:*)"]
:*가 "이후의 인자는 무엇이든 상관없음"을 의미하는 와일드카드(wildcard)이다. Bash 도구 특유의 표기법으로, 콜론(:)이 경계 기호(boundary symbol)로 사용된다는 점에 주의해야 한다. Bash(npm install*)와 같이 아스테리스크(*)만 붙여서는 작동하지 않는다.
서브 커맨드(subcommand)가 가변적인 경우에는 Bash(npm run *:*)와 같이 커맨드 쪽에도 *를 넣는다. 이렇게 하면 npm run dev, npm run build, npm run test 모두에 적용된다. allow에 Bash(git push:*)라고 쓰고, deny에 Bash(git push --force*)라고 쓰면, git push --force는 deny가 우선하므로 정상적으로 프롬프트가 나타난다.
여기서 "allow에 적었으니 그냥 통과되어야 한다"라고 착각하면 보안 사고로 이어질 수 있다. 금지하고 싶은 작업은 명시적으로 deny에 작성한다. allow와 deny에서 동일한 패턴이 충돌하면 deny가 승리한다는 점을 기억해 두자.
우선순위는 ~/.claude/settings.local.json (로컬 개인) → .claude/settings.json (프로젝트) → ~/.claude/settings.json (사용자) 순이며, 더 구체적인 계층이 나중에 적용되어 덮어쓴다(last-one-wins).
단, deny는 어느 레이어(layer)에서도 유효하다 (사용자 계층에서 deny한 것을 프로젝트 계층의 allow로 덮어쓸 수 없다). 이를 통해 보안을 담보한다.
"프로젝트에서 일시적으로 허용하고 싶다"면, 글로벌 설정을 완화하는 것이 아니라 .claude/settings.local.json에 개인용 allow를 추가하는 것이 정답이다.
MCP 서버의 도구를 허용할 때는 mcp__<server>__<tool> 형식을 사용한다.
"allow": ["mcp__notion__notion-fetch"]
포인트는 다음과 같다:
- 서버 이름과 "mcp" 사이의 구분자는 **언더스코어 두 개(
__)**이다.
- 도구 이름 쪽은 실제 등록된 이름을 그대로 사용한다 (하이픈(
-) 구분인 경우 그대로 유지).
이를 모르면, Notion 공식 MCP와 같이 notion-fetch라는 이름의 도구를 허용할 때, mcp__notion__notion_fetch라고 잘못 입력하여 영원히 매칭되지 않는 사고가 발생할 수 있다.
설정 후 /permissions를 입력하면 실제로 매칭되고 있는 규칙 목록을 볼 수 있으므로, 작성 직후 반드시 확인한다.
.claude/settings.local.json은 개인의 추가 allowlist용이다. .gitignore에 넣어두지 않으면 팀 멤버의 설정을 덮어쓰거나, 자신의 개인 허용 설정이 유출될 수 있다.
확인 방법:
grep settings.local.json .gitignore
검색 결과가 없다면 추가한다:
echo ".claude/settings.local.json" >> .gitignore
Claude Code는 첫 init 시 .gitignore에 자동으로 추가해 주는 경우가 많지만, 오래된 리포지토리(repository)에는 포함되어 있지 않을 수 있으므로 한 번 확인해 두는 것이 좋다.
왜 프롬프트가 뜨도록 설계되었는가? Claude Code는 **에이전트 (Agent)**이므로, 인간이 감시하고 있지 않아도 명령을 실행하도록 설계되어 있다. 이를 무제한으로 허용하면 rm -rf /와 같은 사고가 발생할 수 있다. 따라서 "읽기 계열은 기본 허용, 쓰기·실행 계열은 확인"이라는 기본 노선을 취하고 있다.
allowlist는 "자신이 안전하다고 판단한 것만 자동으로 허용한다"는 권한 관리 메커니즘으로, OS의 sudoers와 유사한 발상이다. 자동으로 허용한다는 것은, 스스로 그 안전성에 책임을 진다는 의미이기도 하다.
실운용에서는 "읽기 계열은 통째로 allow, 쓰기 계열은 개별 allow, 파괴 계열은 명시적 deny"라는 3단계 전략을 취하면 편의성과 안전성의 균형을 맞출 수 있다.
/fewer-permission-prompts에서 자주 발생하는 도구들을 집계하여 위에서부터 해결한다.
- 글로벌 (
~/.claude/settings.json) 설정과 프로젝트 (.claude/settings.json) 설정을 구분하여 사용한다.
- Bash 패턴은
Bash(명령어:*) 형태로 와일드카드 (Wildcard)를 붙인다.
deny는 allow보다 우선순위가 높으므로, 위험한 작업은 명시적으로 deny 한다.
.claude/settings.local.json은 .gitignore에 추가한다.
이것만으로도 프롬프트 피로 (Prompt fatigue)의 90%를 없앨 수 있다. 작업 흐름 (Flow)이 끊기지 않고 계속 이어질 수 있다는 점은 작업 시간이 길어질수록 더욱 큰 효과를 발휘한다.