A handful of patterns appear repeatedly across the ~1,900 source files. Recognizing them on sight will significantly reduce the time it takes to understand any given module.
Every tool is created with buildTool(), defined in src/Tool.ts. The factory attaches the input schema, permission model, execution logic, and UI rendering into a single cohesive object that the Query Engine can call.
export const MyTool = buildTool({
name: 'MyTool',
aliases: ['my_tool'],
description: 'What this tool does',
inputSchema: z.object({
param: z.string(),
}),
async call(args, context, canUseTool, parentMessage, onProgress) {
// Execute and return { data: result, newMessages?: [...] }
},
async checkPermissions(input, context) {
// Return { granted: boolean, reason?: string, prompt?: string }
},
isConcurrencySafe(input) {
// Return true if this tool can run in parallel with other tools
},
isReadOnly(input) {
// Return true if this tool makes no changes (e.g. file reads, searches)
},
prompt(options) {
// Return system prompt text injected before each query
},
renderToolUseMessage(input, options) {
// Return JSX rendered when Claude invokes this tool
},
renderToolResultMessage(content, progressMessages, options) {
// Return JSX rendered when the tool result is shown
},
})
isReadOnly() and isConcurrencySafe() influence whether the Query Engine can run tools in parallel. Tools that declare themselves read-only and concurrency-safe can execute simultaneously — for example, multiple FileReadTool calls in one LLM turn.
Feature flag gates
Claude Code uses Bun’s bun:bundle import for compile-time dead-code elimination. Code inside an inactive feature flag is completely stripped from the production binary — it never ships.
import { feature } from 'bun:bundle'
if (feature('VOICE_MODE')) {
// This entire block is removed at build time if VOICE_MODE is off
const voiceCommand = require('./commands/voice/index.js').default
}
Notable feature flags you’ll encounter:
| Flag | Feature |
|---|
PROACTIVE | Proactive agent mode (autonomous background actions) |
KAIROS | Kairos subsystem |
BRIDGE_MODE | IDE bridge integration |
DAEMON | Background daemon mode |
VOICE_MODE | Voice input and output |
AGENT_TRIGGERS | Triggered agent actions |
MONITOR_TOOL | Monitoring tool |
COORDINATOR_MODE | Multi-agent coordinator |
WORKFLOW_SCRIPTS | Workflow automation scripts |
To find all feature flag usage in the source, run rg "feature\(" src/. This shows every guarded block.
Anthropic-internal gates
Some code paths are only active for Anthropic employees. These gates are a simple environment variable check:
if (process.env.USER_TYPE === 'ant') {
// Anthropic employee-only features
}
You’ll find this pattern gating internal diagnostics, experimental modes, and development-only tooling. Use rg "USER_TYPE.*ant" src/ to locate all occurrences.
Command definition pattern
Slash commands (/commit, /review, etc.) follow a consistent satisfies Command pattern, which gives TypeScript structural type checking without requiring a class:
const command = {
type: 'prompt',
name: 'my-command',
description: 'What this command does',
progressMessage: 'working...',
allowedTools: ['Bash(git *)', 'FileRead(*)'],
source: 'builtin',
async getPromptForCommand(args, context) {
return [{ type: 'text', text: '...' }]
},
} satisfies Command
There are three command types:
PromptCommand
LocalCommand
LocalJSXCommand
Sends a formatted prompt to the LLM with a specific set of allowed tools. The getPromptForCommand() function builds the message array. Used for /review, /commit, and most agent commands.
Runs entirely in-process and returns plain text to the REPL. No LLM call is made. Used for lightweight commands like /cost and /version.
Runs in-process and returns React JSX. Used for commands that render rich terminal UI, like /doctor and /install.
Index re-exports
Almost every directory has an index.ts that re-exports the module’s public API. This keeps import paths clean and lets internal structure change without affecting callers.
// src/tools/BashTool/index.ts
export { BashTool } from './BashTool.js'
When you open a directory and see only an index.ts, it is a thin facade — follow the imports to find the real implementation.
Lazy dynamic imports
Heavy modules are loaded on demand with dynamic import() rather than at startup. This keeps the initial startup time fast.
// Only loaded when OpenTelemetry is first needed (~400KB)
const { OpenTelemetry } = await import('./heavy-module.js')
You’ll see this pattern for OpenTelemetry (~400KB), gRPC (~700KB), and other optional dependencies that most users may never invoke.
ESM with .js extensions
Claude Code uses Bun’s ES module convention: all import statements reference .js extensions even though the actual files are .ts. Bun resolves these transparently at runtime.
// The import references .js — Bun will load the .ts file
import { something } from './utils.js'
Do not be confused by .js extensions in import statements — there are no compiled .js files in src/. All files are TypeScript; Bun handles the resolution.
Parallel prefetch
src/main.tsx fires several async side-effects before evaluating any heavy modules. This hides I/O latency behind module load time:
// Fires before heavy module evaluation — hides I/O latency
startMdmRawRead()
startKeychainPrefetch()
// GrowthBook feature flag fetch also starts here
The results are awaited later, after the necessary modules are loaded. This is why startup feels fast despite loading a complex React + Ink application.