Claude Code가 도구 실행 여부를 결정하는 방법 — 거부 규칙부터 AI 분류기까지.
Claude Code의 권한 시스템은 모든 도구 호출이 사용자의 의도와 보안 정책에 부합하는지 검증하는 핵심 게이트키퍼입니다. 단순한 허용/거부 목록이 아닌, 다단계 결정 파이프라인을 통해 규칙 매칭, 모드 기반 변환, AI 분류기까지 계층적으로 동작합니다.
permissions/ 디렉토리 — permissionCheck.ts, permissionRules.ts, permissionModes.ts, autoModeClassifier.ts
권한 시스템의 핵심 원칙:
bypassPermissions 모드조차 우회할 수 없는 4가지 보호 장치가 존재합니다모든 도구 호출은 다음 세 단계를 순서대로 통과합니다:
첫 번째로 거부(deny) 규칙을 평가합니다. 거부 규칙에 매칭되면 즉시 차단되며, 어떤 모드나 허용 규칙으로도 이를 되돌릴 수 없습니다. 이후 .git/과 .claude/ 디렉토리에 대한 안전 검사, requiresUserInteraction 플래그, 콘텐츠 기반 ask 규칙도 이 단계에서 평가됩니다.
// permissionCheck.ts — 거부 규칙이 항상 최우선
const denyMatch = rules.deny.find(r => matchesRule(r, toolCall))
if (denyMatch) {
return { decision: 'deny', reason: denyMatch.reason }
}
// 안전 검사: .git/ 및 .claude/ 쓰기 보호
if (isProtectedPath(toolCall.path)) {
return { decision: 'ask', reason: 'protected directory' }
}
거부되지 않은 호출은 현재 권한 모드와 허용(allow) 규칙을 기준으로 평가됩니다. 허용 규칙에 매칭되면 프롬프트 없이 실행됩니다. 매칭되지 않으면 모드에 따라 ask(사용자에게 질문) 또는 allow(자동 허용)로 분류됩니다.
최종 결정이 ask인 경우, 현재 모드에 따라 변환됩니다. 예를 들어 bypassPermissions 모드에서는 ask가 allow로 변환되고, dontAsk 모드에서는 ask가 deny로 변환됩니다.
bypassPermissions도 bypass 불가능한 4가지가 있습니다: 거부 규칙, requiresUserInteraction 플래그, 콘텐츠 기반 ask 규칙, .git/ 및 .claude/ 안전 검사. 이 4가지는 모든 모드에서 항상 사용자에게 프롬프트되거나 거부됩니다.
Claude Code는 5가지 권한 모드를 지원하며, 각 모드는 ask 결정을 다르게 변환합니다:
default: 기본 모드. 허용 규칙에 매칭되지 않는 도구 호출은 사용자에게 프롬프트됩니다.plan: 계획 전용 모드. 읽기 도구만 자동 허용되고, 쓰기 도구는 deny로 변환됩니다.acceptEdits: 파일 편집은 자동 허용하지만 Bash, MCP 등 다른 도구는 프롬프트합니다.bypassPermissions: ask를 allow로 변환합니다 (위의 4가지 예외 제외).dontAsk / auto: ask를 deny로 변환합니다. CI/스크립팅 환경에서 사용자 입력 없이 실행할 때 사용합니다.// permissionModes.ts — 모드별 ask 변환
function transformAskDecision(mode: PermissionMode): Decision {
switch (mode) {
case 'bypassPermissions': return 'allow' // ask → allow
case 'dontAsk': return 'deny' // ask → deny
case 'default': return 'ask' // ask → ask (프롬프트)
// ...
}
}
dontAsk vs bypassPermissions두 모드 모두 사용자 프롬프트를 제거하지만 정반대 방향으로 동작합니다. bypassPermissions는 "묻지 않고 허용"이고, dontAsk는 "묻지 않고 거부"입니다. CI/자동화 환경에서는 dontAsk가 안전한 기본값입니다 — 허용 규칙에 명시적으로 등록되지 않은 도구 호출은 자동으로 차단됩니다.
규칙은 세 가지 매칭 방식을 지원합니다:
Bash(npm test) — 정확히 해당 명령어만 매칭Bash(npm:*) — npm으로 시작하는 모든 명령어 매칭. 콜론 뒤 와일드카드로 접두사 매칭 표시Bash(npm:*)와 같은 패턴 — npm 다음에 오는 모든 문자를 매칭. *는 단일 글로브 패턴으로 동작// permissionRules.ts — 규칙 매칭 로직
function matchesRule(rule: Rule, toolCall: ToolCall): boolean {
const pattern = rule.pattern
if (pattern.includes('*')) {
// 와일드카드 매칭: Bash(npm:*) → "npm"으로 시작하는 모든 것
return globMatch(toolCall.input, pattern)
}
// 정확 매칭
return toolCall.input === pattern
}
Bash(npm:*)는 와일드카드 매칭의 예시입니다. npm install, npm test, npm run build 등 npm으로 시작하는 모든 Bash 명령어에 매칭됩니다.
규칙은 8개의 소스에서 로드되며, 각 소스는 우선순위가 다릅니다. 우선순위가 높은 소스의 규칙이 낮은 소스를 덮어씁니다:
--allowedTools, --disallowedTools~/.claude/settings.json.claude/settings.json.claude/settings.local.json거부 규칙은 소스에 관계없이 항상 허용 규칙보다 우선합니다. 같은 도구에 대해 상위 소스에서 거부하고 하위 소스에서 허용해도 거부가 승리합니다.
섀도 규칙이란 더 높은 우선순위의 규칙에 의해 실질적으로 무효화된 규칙입니다. 예를 들어, 사용자 설정에서 allow: ["Bash(npm:*)"]를 설정했지만 정책 설정에서 deny: ["Bash(npm:*)"]가 있으면, 사용자의 허용 규칙은 섀도 처리됩니다. 권한 설명기(Permission Explainer)는 이러한 섀도 관계를 시각적으로 보여줍니다.
자동(auto) 모드는 AI 분류기를 사용하여 도구 호출의 안전성을 판단합니다. 안전 도구 허용 목록에 있는 도구는 분류 없이 즉시 허용되고, 그 외의 도구는 분류기가 평가합니다.
읽기 전용 도구(Read, Glob, Grep 등)는 기본적으로 안전한 것으로 분류되어 AI 분류기 호출 없이 자동 허용됩니다.
AI 분류기의 안전장치로, 연속 거부 횟수와 총 거부 횟수를 추적합니다:
// autoModeClassifier.ts — 거부 추적
let consecutiveDenials = 0
let totalDenials = 0
if (consecutiveDenials >= 3 || totalDenials >= 20) {
// 자동 허용 대신 사용자에게 프롬프트
return { decision: 'ask', fallback: true }
}
권한 설명기(Permission Explainer)는 특정 도구 호출에 대해 어떤 규칙이 어떤 소스에서 매칭되었는지, 최종 결정이 어떻게 도출되었는지를 단계별로 설명합니다. 디버깅 시 왜 특정 도구가 차단되거나 허용되었는지 추적하는 데 필수적인 도구입니다. 섀도 규칙도 명시적으로 표시하여 규칙 충돌의 원인을 빠르게 파악할 수 있습니다.
bypassPermissions 모드조차 우회할 수 없는 4가지: 거부 규칙, requiresUserInteraction, 콘텐츠 ask 규칙, .git/.claude 안전 검사default, plan, acceptEdits, bypassPermissions, dontAsk/auto)가 ask 결정을 다르게 변환합니다Q1. deny 규칙에 Bash(*)가 있고 allow 규칙에 Bash(ls:*)가 있을 때, ls -la 실행 시 결과는?
Bash(*)는 모든 Bash 호출에 매칭되므로, allow 규칙에 관계없이 즉시 거부됩니다. 거부 규칙은 항상 최우선입니다.Q2. bypassPermissions 모드에서도 사용자에게 프롬프트되는 것은?
.git/ 디렉토리는 안전 검사 대상입니다. bypassPermissions 모드라도 .git/이나 .claude/ 디렉토리에 대한 쓰기는 항상 사용자에게 프롬프트됩니다. 이는 리포지토리 무결성을 보호하기 위한 불가침 안전 장치입니다.Q3. 자동 모드 AI 분류기가 3연속 거부를 기록한 후, 4번째 도구 호출 시 동작은?
Q4. Bash(npm:*) 규칙의 매칭 타입은?
Bash(npm:*)에서 *는 와일드카드 글로브 패턴입니다. npm 뒤에 오는 모든 문자열에 매칭됩니다. 와일드카드 매칭은 정확 매칭과 달리 패턴 기반으로 유연한 규칙 정의를 가능하게 합니다.Q5. dontAsk와 bypassPermissions의 차이는?
bypassPermissions는 "묻지 않고 허용" (ask → allow), dontAsk는 "묻지 않고 거부" (ask → deny)로 변환합니다. CI 환경에서는 dontAsk + 명시적 allow 규칙 조합이 안전한 패턴입니다.