Chapter 5 System Design

Permission Model — 5-Tier Security

How Claude Code decides what it is allowed to do

src/utils/permissions/permissions.tsLines 180
1
import { feature } from 'bun:bundle'
2
import { APIUserAbortError } from '@anthropic-ai/sdk'
3
import type { CanUseToolFn } from '../../hooks/useCanUseTool.js'
4
import {
5
  getToolNameForPermissionCheck,
6
  mcpInfoFromString,
7
} from '../../services/mcp/mcpStringUtils.js'
8
import type { Tool, ToolPermissionContext, ToolUseContext } from '../../Tool.js'
9
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js'
10
import { shouldUseSandbox } from '../../tools/BashTool/shouldUseSandbox.js'
11
import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js'
12
import { POWERSHELL_TOOL_NAME } from '../../tools/PowerShellTool/toolName.js'
13
import { REPL_TOOL_NAME } from '../../tools/REPLTool/constants.js'
14
import type { AssistantMessage } from '../../types/message.js'
15
import { extractOutputRedirections } from '../bash/commands.js'
16
import { logForDebugging } from '../debug.js'
17
import { AbortError, toError } from '../errors.js'
18
import { logError } from '../log.js'
19
import { SandboxManager } from '../sandbox/sandbox-adapter.js'
20
import {
21
  getSettingSourceDisplayNameLowercase,
22
  SETTING_SOURCES,
23
} from '../settings/constants.js'
24
import { plural } from '../stringUtils.js'
25
import { permissionModeTitle } from './PermissionMode.js'
26
import type {
27
  PermissionAskDecision,
28
  PermissionDecision,
29
  PermissionDecisionReason,
30
  PermissionDenyDecision,
31
  PermissionResult,
32
} from './PermissionResult.js'
33
import type {
34
  PermissionBehavior,
35
  PermissionRule,
36
  PermissionRuleSource,
37
  PermissionRuleValue,
38
} from './PermissionRule.js'
39
import {
40
  applyPermissionUpdate,
41
  applyPermissionUpdates,
42
  persistPermissionUpdates,
43
} from './PermissionUpdate.js'
44
import type {
45
  PermissionUpdate,
46
  PermissionUpdateDestination,
47
} from './PermissionUpdateSchema.js'
48
import {
49
  permissionRuleValueFromString,
50
  permissionRuleValueToString,
51
} from './permissionRuleParser.js'
52
import {
53
  deletePermissionRuleFromSettings,
54
  type PermissionRuleFromEditableSettings,
55
  shouldAllowManagedPermissionRulesOnly,
56
} from './permissionsLoader.js'
57
 
58
/* eslint-disable @typescript-eslint/no-require-imports */
59
const classifierDecisionModule = feature('TRANSCRIPT_CLASSIFIER')
60
  ? (require('./classifierDecision.js') as typeof import('./classifierDecision.js'))
61
  : null
62
const autoModeStateModule = feature('TRANSCRIPT_CLASSIFIER')
63
  ? (require('./autoModeState.js') as typeof import('./autoModeState.js'))
64
  : null
65
 
66
import {
67
  addToTurnClassifierDuration,
68
  getTotalCacheCreationInputTokens,
69
  getTotalCacheReadInputTokens,
70
  getTotalInputTokens,
71
  getTotalOutputTokens,
72
} from '../../bootstrap/state.js'
73
import { getFeatureValue_CACHED_WITH_REFRESH } from '../../services/analytics/growthbook.js'
74
import {
75
  type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
76
  logEvent,
77
} from '../../services/analytics/index.js'
78
import { sanitizeToolNameForAnalytics } from '../../services/analytics/metadata.js'
79
import {
80
  clearClassifierChecking,
Annotations (click the dots)

Before any tool runs, canUseTool() is called in src/utils/permissions/permissions.ts. This is the gatekeeper — it returns allow, ask, or deny based on the current permission mode and rules.

🔑Key Insight

The auto mode uses an ML classifier to score bash commands. If the classifier confidence is high enough, the tool runs without prompting. After enough denials, it falls back to always prompting.

Permission rules use glob patterns. A rule like bash:cat * allows cat on any file. !node_modules/** excludes a path. Rules are composed from three sources: managed (org), environment, and user settings — in that priority order.

⚠️Warning

The `bypass` mode (`--dangerously-skip-permissions`) is explicitly blocked when running as root. This is checked in `src/setup.ts` before the REPL starts.

KEY TAKEAWAYS
  • Five modes: default (allow), ask (always prompt), auto (ML classifier), deny (block), bypass (admin)
  • The ML classifier scores bash commands for safety — fallback to prompting after N denials
  • Permission rules use glob patterns with negation (!node_modules/**)
  • Managed rules (from org policy) take precedence over user settings
  • The permission decision always runs BEFORE tool execution — tools never check themselves
AI Assistant

Ask anything about Permission Model — 5-Tier Security

Powered by Groq · Enter to send, Shift+Enter for newline