English lecture · source-traced

Claude Code core components inventory (everything except tools and slash commands)

Source: `claude-code/src`. For each item: what it is (a beginner metaphor) → source implementation (`file:line`) → a concrete example.

EN
lecture
source
file:line
no
embellishment
中文
sibling

Source: claude-code/src. For each item: what it is (a beginner metaphor) → source implementation (file:line) → a concrete example.


Part 1

1. Plugins

What it is

A plugin is a "capability pack" — like a VS Code extension. One directory can hold slash commands, skills (SKILL.md), subagent definitions, hooks (hook scripts), and MCP server config, all installed in one shot. The problem it solves: a single .claude/commands/xxx.md file is too scattered; you cannot conveniently share and version a whole workflow.

Source implementation

  • Plugin directory convention: plugin.json manifest + commands/ + agents/ + hooks/hooks.json, see utils/plugins/pluginLoader.ts:16-28 (file-header comments) and createPluginFromPath() (pluginLoader.ts:1357); pluginLoader.ts:1392-1398 probes in parallel whether the four optional directories commands/, agents/, skills/, output-styles/ exist.
  • Built-in plugins: shipped with the CLI, toggleable in the /plugin UI, registered in plugins/builtinPlugins.ts:21-32 (registerBuiltinPlugin), IDs of the form {name}@builtin (builtinPlugins.ts:23,38). Difference from marketplace plugins: no filesystem path (path: 'builtin' sentinel, builtinPlugins.ts:85); the user's on/off state is persisted to settings enabledPlugins (builtinPlugins.ts:71-76).
  • Marketplace mechanism: a marketplace is essentially a git repo (or URL/NPM) containing a marketplace.json catalog. The official marketplace is the GitHub repo anthropics/claude-plugins-official (utils/plugins/officialMarketplace.ts:13-27). Adding a marketplace goes through addMarketplaceSource() (utils/plugins/marketplaceManager.ts:1782); cloning uses a partial clone + sparse checkout to save bandwidth (marketplaceManager.ts:803 gitClone, 1034 reconcileSparseCheckout). Installed plugins are landed by installPluginFromMarketplace() (utils/plugins/pluginInstallationHelpers.ts:506); the load entry point is loadAllPlugins() (pluginLoader.ts:3096).
  • Priority vs built-in features: commands from all sources are merged in commands.ts:447-470 loadAllCommands, in order bundledSkills → builtinPluginSkills → directory skills → workflow → pluginCommands → pluginSkills → hard-coded built-in commands (COMMANDS()). Lookup uses findCommand() (commands.ts:688); the first match in array order wins, so a same-named user/plugin skill ranks ahead of a hard-coded built-in command.
  • UI: the /plugin command's UI lives in commands/plugin/ (ManagePlugins.tsx, BrowseMarketplace.tsx, AddMarketplace.tsx, etc.).

Example

After /plugin marketplace add anthropics/claude-plugins-official, gitClone sparse-clones the repo into ~/.claude/plugins/marketplaces/, then /plugin install feature-dev@claude-plugins-official; on next startup createPluginFromPath finds its commands/, agents/, hooks/hooks.json, and those commands appear in the / list, source-tagged as plugin.


Part 2

2. Skills

What it is

A skill is a "spec sheet you pull on demand." Metaphor: stuffing every tool's full manual into the drawer (the system prompt) is too heavy, so Claude Code only pastes a one-page "table of contents" on the drawer (skill name + one-sentence description); when the model decides it needs a particular manual, it pulls the whole book out via the Skill tool.

Source implementation

  • Directory format: under /skills/ only the skill-name/SKILL.md directory layout is recognized; a lone .md file is not treated as a skill (skills/loadSkillsDir.ts:424-428). Load locations have four layers: enterprise-managed, user-level ~/.claude/skills, project-level .claude/skills (including --add-dir), and the legacy /commands/ directory (loadSkillsDir.ts:638-714).
  • Full set of SKILL.md frontmatter fields (parse entry parseSkillFrontmatterFields, loadSkillsDir.ts:185-265):
  • name (display name, :238), description (:208-214, default extracted from the body), when_to_use (:252, tells the model which scenes to invoke)
  • allowed-tools (:242, whitelist of tools available while the skill runs)
  • argument-hint, arguments (:245-251, argument hint and named arguments)
  • version (:253), model (:221-226, may be inherit or a specific model)
  • effort (:228-235, can specify thinking effort)
  • disable-model-invocation (:255, humans only), user-invocable (:216-219, false hides it from the / menu)
  • hooks (:259, skill-level hooks; Zod validation in parseHooksFromFrontmatter :136-153)
  • context: fork (:260, run in a forked sub-context), agent (:261)
  • shell (:263, which interpreter embedded shell commands use)
  • paths (parseSkillPaths :159-178, gitignore-style path filter — conditional skills, activated only when a matching-path file is read/written; activation logic starts at activateConditionalSkillsForPaths :997)
  • Progressive disclosure:
  • Stage one — inject only the listing: utils/attachments.ts:2661 getSkillListingAttachments packs every skill's name/description/whenToUse into one skill_listing attachment (attachments.ts:2744-2749), trimmed to a token budget (formatCommandsWithinBudget :2744), and sent once per agent with incremental top-ups (:2698-2732).
  • Stage two — load the full text only on invoke: the model calls the Skill tool (tools/SkillTool/SkillTool.ts:580 call) → runs that Command's getPromptForCommand (loadSkillsDir.ts:344-399), and only then concatenates Base directory for this skill: ... + the full body, does argument substitution (substituteArguments :349), replaces ${CLAUDE_SKILL_DIR}/${CLAUDE_SESSION_ID} (:356-369), and even executes markdown-embedded !`...` shell commands (:375). Safety detail: skills from MCP are "remote untrusted content" and never execute embedded shell (:372-374).
  • Dynamic discovery: while a session reads/writes files, nested .claude/skills are discovered by walking up from the file path (discoverSkillDirsForPaths :861-915), skipping gitignored directories (:892-897); a skill in a deeper directory overrides a same-named shallower one (:944-951).
  • Built-in bundled skills: compiled into the binary, registered in code (skills/bundledSkills.ts:53 registerBundledSkill), directory skills/bundled/: batch, claudeApi, claudeInChrome, debug, keybindings, loop, loremIpsum, remember, scheduleRemoteAgents, simplify, skillify, stuck, updateConfig, verify. Skills with attachments (files field, bundledSkills.ts:29-36) unpack reference files to disk only on first invoke (extractBundledSkillFiles :131-145), with O_NOFOLLOW|O_EXCL against symlink attacks (:176-193).
  • MCP skills: MCP servers can also provide skills; they reuse the same parse logic via the registry in skills/mcpSkillBuilders.ts (to avoid a cyclic dependency).

Example

~/.claude/skills/pdf/SKILL.md says description: PDF 表格提取 + allowed-tools: Read, Bash. At startup the model only sees one line "pdf — PDF 表格提取"; when the user says "pull the table on page 3 of report.pdf," the model calls the Skill tool, and only then does Claude read the full SKILL.md and learn that scripts/extract.py exists, then runs the script with Bash.


Part 3

3. MCP (Model Context Protocol)

What it is

MCP is "USB-C for AI": any external service (a database, Figma, an internal company system) that implements a server per the MCP protocol can be plugged into Claude Code, and its tools, resources, and prompt templates become immediately usable.

Source implementation

  • Client: services/mcp/client.ts (3348 lines), based on the official @modelcontextprotocol/sdk Client (client.ts:7). Supported transports (schema in services/mcp/types.ts:28-131):
  • stdio — local subprocess (client.ts:950 new StdioClientTransport)
  • sse — HTTP long-poll push (client.ts:673,702 SSEClientTransport)
  • http — Streamable HTTP (client.ts:861,900 StreamableHTTPClientTransport)
  • ws/ws-ide — WebSocket (client.ts:734,783)
  • sdk — in-process SDK transport (client.ts:3278 SdkControlClientTransport), plus special types sse-ide, claudeai-proxy, etc.
  • Config and approval: servers can be registered in .mcp.json at the project root (enterprises also have managed-mcp.json, services/mcp/config.ts:64-66). Because project-level config may come from an untrusted repo, startup pops an approval dialog for every pending server: handleMcpjsonServerApprovals() (services/mcpServerApproval.tsx:13-40; a single server uses MCPServerApprovalDialog, several use MCPServerMultiselectDialog). The state machine is getProjectMcpServerStatus() (services/mcp/utils.ts:351): settings enabledMcpjsonServers/disabledMcpjsonServers record the user's choice; enableAllProjectMcpServers can approve all (utils.ts:371); --dangerously-skip-permissions and non-interactive mode auto-approve, with a strict anti-RCE comment (utils.ts:383-400). Load time only admits approved servers (config.ts:1164-1168).
  • Tools into the conversation: fetchToolsForClient() (client.ts:1742) calls tools/list, then wraps them as MCPTool (tools/MCPTool/MCPTool.ts), names them mcp__serverName__toolName (buildMcpToolName, client.ts:1767). Permission rules support server-level wildcards: mcp__server1 or mcp__server1__* (utils/permissions/permissions.ts:236-259).
  • Resources and prompts: ListMcpResourcesTool, ReadMcpResourceTool, McpAuthTool (imported at client.ts:53-56) let the model browse/read MCP resources; MCP prompts are turned into Commands (client.ts:2038-2077, names likewise mcp__server__prompt format :2058).
  • Connection management: React context MCPConnectionManager (services/mcp/MCPConnectionManager.tsx) + useManageMCPConnections handle reconnect and on/off; the /mcp command provides a management UI. Server states are connected/failed/needs-auth/pending/disabled (types.ts:183-248); needs-auth goes through MCP OAuth login.

Example

Project .mcp.json says {"mcpServers": {"github": {"type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"]}}}. A colleague who just cloned the repo, first opening Claude Code, gets a "do you trust the github server?" approval dialog; after approval the tool list gains mcp__github__create_issue, and the permissions page can allow the whole server with one rule mcp__github.


Part 4

4. API and authentication

What it is

Claude Code supports four "ways to pay": a Claude subscription account (OAuth login), an API key billed by usage, and enterprise cloud-vendor channels (AWS Bedrock / Google Vertex / Azure Foundry). Like one SIM that can ride a contract plan, a prepaid card, or a company leased line.

Source implementation

  • Provider detection: utils/model/providers.ts:6-13 getAPIProvider — looks at env CLAUDE_CODE_USE_BEDROCK/CLAUDE_CODE_USE_VERTEX/CLAUDE_CODE_USE_FOUNDRY; if none are set, it is firstParty.
  • OAuth login flow (standard authorization code + PKCE): services/oauth/index.ts:14-120 OAuthService — generate code_verifier/challenge (:29,57-58), start a local localhost listener AuthCodeListener (:49-50, auth-code-listener.ts), construct two URLs: the automatic flow (open a browser that jumps back to localhost) and the manual flow (copy-paste the code, :71-72); once the code is in hand, exchangeCodeForTokens swaps it for a token (:103-109). Persistence after login is in cli/handlers/auth.ts:44 installOAuthTokens. The scope system is in constants/oauth.ts (user:inference, user:profile, org:create_api_key).
  • Credential storage: on macOS the OAuth token lives in the Keychain (utils/secureStorage/index.ts:9-17: macOsKeychainStorage, falling back to plainTextStorage on failure; other platforms currently use a plaintext file). API-key source priority is in utils/auth.ts: apiKeyHelper (an executable configured in settings, auth.ts:123), ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN env (:126,134), --settings injection, keychain.
  • Token refresh: checkAndRefreshOAuthTokenIfNeeded() (utils/auth.ts:1427-1560) — on finding an expired accessToken, first clear the cache and re-read (another process may already have refreshed), then take a file lock (lockfile.lock :1500) to keep multiple processes from refreshing at once, retry up to 5 times (:1453); a subscriber refresh omits scopes so the server can expand them (:1544-1550). On 401/"token revoked", the retry layer forces a refresh (services/api/withRetry.ts:246-252).
  • Billing / attribution header: the first block of every request's system prompt is x-anthropic-billing-header: cc_version=...; cc_entrypoint=...; cch=...; cc_workload=... (generated in constants/system.ts:86-95). splitSysPromptPrefix() (utils/api.ts:321-376) lifts it out of the system prompt and marks cacheScope: null (does not participate in the prompt cache); remaining static blocks use global/org cache scopes — so changing entrypoint does not break the cache.

Example

The user runs /login → OAuthService opens the browser for authorization → the browser jumps back to http://localhost:PORT/callback?code=... → the CLI swaps for a token and stores it in the macOS Keychain. An hour later the token expires; checkAndRefreshOAuthTokenIfNeeded takes the file lock and silently renews; the user notices nothing.


Part 5

5. effort / thinking

What it is

A "thinking budget" — before answering, the model can draft (thinking), and the draft length is tunable. effort is the new-generation unified knob (low/medium/high/max); thinking budget is the old-style exact token count; the Claude 4.6 family supports "adaptive" (the model decides how long to think).

Source implementation

  • effort grades: utils/effort.ts:14-20 defines low/medium/high/max (also allows a number, used internally). Which models support it is decided by modelSupportsEffort() (effort.ts:26-50, currently an opus-4-6/sonnet-4-6 allowlist); the max grade is Opus 4.6 only (effort.ts:55-69); unsupported models auto-drop to high (the clamp in resolveAppliedEffort :152-168).
  • Priority chain: resolveAppliedEffort() (effort.ts:152-168): env CLAUDE_CODE_EFFORT_LEVEL → session state (what the user set with /effort or /model, appState.effortValue) → the model's default. On persist, numeric grades and an external user's max are not written to settings (toPersistableEffort :101-112). The /effort command is implemented in commands/effort/effort.tsx:16-20.
  • Sent to the API: services/api/claude.ts:437-465 configureEffort — a string grade goes directly into outputConfig.effort (:453-455); a numeric grade takes the internal effort_override (:458-463, ant-only). The final apply point is claude.ts:1458 resolveAppliedEffort → :1483.
  • thinking config: type ThinkingConfig = adaptive | enabled(budgetTokens) | disabled (utils/thinking.ts:10-13). modelSupportsThinking() (:90-110) splits by provider: on firstParty and Foundry every Claude 4+ supports it; Bedrock/Vertex only recognize sonnet-4/opus-4. On by default; MAX_THINKING_TOKENS=0 or settings alwaysThinkingEnabled: false can turn it off (shouldEnableThinkingByDefault :146-162).
  • Request construction: services/api/claude.ts:1596-1630 — models that support adaptive (the 4.6 family, modelSupportsAdaptiveThinking thinking.ts:113-144) send {type: 'adaptive'} with no budget; older models send {type: 'enabled', budget_tokens: N}, budget = min(maxOutputTokens-1, thinkingConfig.budgetTokens ?? model default) (:1617-1627).
  • interleaved thinking: injected as a beta header (utils/betas.ts:95 'interleaved_thinking'), letting the model think between tool calls; Foundry supports it on all models (betas.ts:102).
  • Easter egg: the keyword ultrathink in user input triggers a highlight and a higher thinking grade (thinking.ts:29-31 hasUltrathinkKeyword, rainbow render :60-86), double-gated by feature flag ULTRATHINK + GrowthBook tengu_turtle_carbon (:19-24).

Example

The user /effort high (persisted to settings); the next request's API body has output_config: {effort: 'high'}; if it is Opus 4.6, the thinking field is {type: 'adaptive'}, and the model decides thinking length itself; the status bar shows the current grade in sync (getDisplayedEffortLevel effort.ts:170-178).


Part 6

6. Model selection and fallback

What it is

A "lead actor and understudy" mechanism: normally use the primary model (mainLoopModel); when Anthropic's servers are overloaded (HTTP 529), automatically swap in the backup (fallbackModel) so the conversation does not break.

Source implementation

  • Primary-model resolution priority (utils/model/model.ts:84-101 getMainLoopModel):
  • what /model changed in-session (getMainLoopModelOverride, bootstrap/state.ts:838)
  • startup flag --model
  • env ANTHROPIC_MODEL
  • model in settings
  • built-in default (Opus 4.6; third-party channels default Sonnet 4.5 because listing lags, the @[MODEL LAUNCH] comment in model.ts:103-133)
  • fallback specification: CLI flag --fallback-model <model> (main.tsx:1000, help text notes "only works with --print"), parsed at main.tsx:2020, passed into the query loop main.tsx:2846 → query.ts:258. The fallback model is not allowed to be the same as the primary (main.tsx:1337 validation).
  • Trigger: in the retry layer services/api/withRetry.ts — consecutive 529 (server overload) are counted; at MAX_529_RETRIES = 3 (:54) and with a configured fallbackModel, a special FallbackTriggeredError is thrown (:163-165, :337-352). Note: by default this only fires for "non-subscribers on non-custom Opus"; env FALLBACK_FOR_ALL_PRIMARY_MODELS can open it up (:330-336). Background tasks (summaries, title generation) on 529 are dropped rather than retried with backoff (:319-327).
  • Switch execution: query.ts:894-910 — after catching FallbackTriggeredError, replace currentModel with fallbackModel, clear this turn's half-built assistant message (and fill in tool results of 'Model fallback triggered'), then resend the whole request.
  • Small-model division of labor: there is also getSmallFastModel() (services/api/claude.ts:339-340); conversation-topic detection, command descriptions, and other chores use a Haiku-class small model, separated from the main-loop model.

Example

The user runs claude -p --model opus --fallback-model sonnet "重构这个模块". At peak, Opus returns 529 three times in a row; the retry layer throws FallbackTriggeredError; the query loop silently switches to Sonnet and continues; the user only sees a model-switch notice in the transcript.


Part 7

7. Permission modes

What it is

A permission mode is "how long a leash the AI gets": from "ask me every step" to "fully off-leash," several grades, cycled with Shift+Tab.

Source implementation

  • Semantics and UI config of each mode (utils/permissions/PermissionMode.ts:42-91):
  • default — ask via dialog on every dangerous operation
  • plan (Plan Mode) — research and propose only; must not touch files / run commands; at the end, use the ExitPlanMode tool to hand the plan to the user for approval (write operations intercepted from utils/permissions/filesystem.ts:1446)
  • acceptEdits — file edits are auto-accepted (filesystem.ts:1366: edits inside the working directory are let through), everything else still asks
  • bypassPermissions — skip all asking (dangerous; needs --dangerously-skip-permissions or a UI confirmation to enable)
  • dontAsk — not exposed in the UI cycle (getNextPermissionMode.ts:70-72)
  • auto — internal (ant-only) mode; a transcript classifier judges in real time whether each operation is safe (feature flag TRANSCRIPT_CLASSIFIER, PermissionMode.ts:80-90); entering the cycle requires the isAutoModeAvailable gate (getNextPermissionMode.ts:17-29)
  • Shift+Tab cycle: keybinding defined in keybindings/defaultBindings.ts:30-36 (MODE_CYCLE_KEY; on Windows without VT mode, falls back to meta+m). Cycle order is in utils/permissions/getNextPermissionMode.ts:34-79: default → acceptEdits → plan → bypassPermissions (if available) → default. On switch, cyclePermissionMode() (:88-101) calls transitionPermissionMode to clean context (e.g. strip dangerous permissions when entering auto).
  • Mode banner: the status bar changes color by mode (PermissionMode.ts:26-30 color map: plan blue, accept cyan, bypass red).

Example

You want Claude to research a bug but fear it will thrash the code: Shift+Tab to plan; Claude reads code, writes a plan, and finally pops "approve the plan?" via ExitPlanMode; after approval it auto-switches to acceptEdits and lands the edits (filesystem.ts:1450 mode suggestion).


Part 8

8. Output styles

What it is

An output style is "a personality mask for Claude" — it rewrites the opening of the system prompt so the same model answers in a different style (e.g. didactic vs. minimal).

Source implementation

  • Built-in styles: constants/outputStyles.ts:42-100 — default (value null, no extra seasoning), Explanatory (explain every implementation choice, with a ★ Insight block template), Learning (deliberately leave 2–10 lines as a small task for the human to write, the TODO(human) mechanism).
  • Custom styles: drop a markdown file into ~/.claude/output-styles/*.md or the project's .claude/output-styles/*.md; frontmatter supports name, description, keep-coding-instructions (outputStyles/loadOutputStylesDir.ts:41-62); plugins can also provide them via an output-styles/ directory (loadOutputStylesDir.ts:11).
  • Injection: the selected style is concatenated as a # Output Style: {name}\n{prompt} paragraph into the system prompt (constants/prompts.ts:152-157), and the thesis sentence becomes "according to your Output Style below" (prompts.ts:180). keep-coding-instructions: true means keep the original coding instructions and only overlay style.
  • Switching: /output-style command (commands/output-style/); a plugin can force a style with force-for-plugin (outputStyles.ts:14-21).

Example

A beginner user /output-style Learning; when Claude writes 30 lines of code it deliberately leaves the core function, sends a "Learn by Doing" card asking you to fill in the TODO(human) part, and waits until you are ready before continuing.


Part 9

9. Memory system and quick memory

What it is

Four "brains": long-term memory across sessions (MEMORY.md auto-memory), project covenant (the CLAUDE.md family), notes for the current session (Session Memory), and the manually managed /memory editor.

Source implementation

  • Auto memory / memdir: memdir/memdir.ts — one memory directory per project (default ~/.claude/projects/<project-path>/memory/, memdir/paths.ts); entry file MEMORY.md (memdir.ts:35) hard-capped at 200 lines / 25KB, truncated with a warning when over (memdir.ts:37-40, 59-95 truncateEntrypointContent). Claude autonomously writes user preferences and project habits into markdown files under that directory; at startup they are retrieved by relevance and injected (memdir/findRelevantMemories.ts); injected entries carry a "freshness" prefix (tools/FileReadTool/FileReadTool.ts:749 memoryFileFreshnessPrefix). When the user corrects Claude, the tail of the denial message appends a hint to "consider storing this in memory" (utils/messages.ts:177-191).
  • Session Memory: services/SessionMemory/sessionMemory.ts:1-7 — a background fork of a sub-agent periodically distills the current conversation into markdown notes, without interrupting the main dialogue; used to restore context after auto-compact. Compact integration is in services/compact/sessionMemoryCompact.ts.
  • CLAUDE.md system: utils/claudemd.ts getMemoryFiles collects project/user/nested CLAUDE.md and .claude/rules; a subdirectory's CLAUDE.md is injected on demand when a file in it is read (utils/attachments.ts:1710 memoryFilesToAttachments + nestedMemoryAttachmentTriggers for dedup, FileReadTool.ts:848,870).
  • /memory command: commands/memory/memory.tsx — pops MemoryFileSelector (components/memory/MemoryFileSelector.tsx:44) to pick a user/project/nested memory file, then opens it with $EDITOR/$VISUAL (memory.tsx:72, editFileInEditor).
  • About the # quick-memory shortcut: this source snapshot does not have a #-prefix input mode — components/PromptInput/inputModes.ts:31-33 only recognizes ! (bash mode), and the PromptInputMode type (types/textInputTypes.ts:265-269) only has bash/prompt etc. The early-version # quick-append memory has, in this snapshot, evolved into the /memory command + auto-memory system (note the version difference when writing primers).

Example

You say offhand "our team writes commits in Chinese"; Claude writes that into ~/.claude/projects/xxx/memory/team-conventions.md and updates the MEMORY.md index; next week's new session, that preference shows up automatically in the system prompt with the relevant memories.


Part 10

10. Other mechanisms worth a primer

Vim mode (src/vim/)

The input box supports Vim keybindings (NORMAL/INSERT mode switch, motion, operator, text object). Implementation is split into pure-function modules: vim/motions.ts, vim/operators.ts, vim/textObjects.ts, vim/transitions.ts; state types live in types/textInputTypes.ts:255-260 VimInputState.

Voice input (src/voice/ + src/services/voiceStreamSTT.ts)

Push-to-talk: voiceStreamSTT.ts:1-36 connects to Anthropic's /api/ws/speech_to_text/voice_stream WebSocket for streaming transcription. Gate: voice/voiceModeEnabled.ts:18-24 GrowthBook kill switch + :31-40 hasVoiceAuth — must have an OAuth token (it uses the claude.ai endpoint; API key / Bedrock / Vertex are unavailable).

Remote and Bridge (src/remote/, src/bridge/)

  • bridge/bridgeMain.ts: make this machine the "executor" for the claude.ai web/App — poll the cloud for session tasks, run them locally, post results back (createSessionSpawner, getRemoteSessionUrl, createBridgeApiClient); supports worktree isolation (:22 import).
  • remote/SessionsWebSocket.ts + RemoteSessionManager.ts: bridge a local REPL session to the web for real-time control (bidirectional WebSocket; remotePermissionBridge.ts syncs permission dialogs to the web for confirmation).

Cost tracking (src/cost-tracker.ts)

Each API response's usage is run through calculateUSDCost() (utils/modelCost.js, per the model price list) and accumulated into counters in bootstrap/state (cost-tracker.ts:3-27 imports a string of getTotalCostUSD/getTotalInputTokens etc.); the /cost command displays them, and lastCost is persisted to project config (:146) for cross-session totals.

Telemetry / Analytics (src/services/analytics/)

Event instrumentation uniformly goes through logEvent(), event names of the form tengu_* (e.g. tengu_api_opus_fallback_triggered, tengu_oauth_token_refresh_starting); backends include Statsig (feature flags), GrowthBook (experiment assignment, growthbook.ts), Datadog (datadog.ts), first-party event reporting (firstPartyEventLogger.ts); sensitive fields are forced through a type tag (AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS).

Keybinding system (src/keybindings/)

A declarative keybinding system: default table keybindings/defaultBindings.ts:37+ (chunked by context Global/Chat etc.; values are action strings like app:interrupt, history:search); users can override in keybindings.json (loadUserBindings.ts); parse and match live in parser.ts/match.ts; the React side subscribes with the useKeybinding hook. ctrl+c/ctrl+d are reserved and cannot be rebound.

UDS message service (inject messages from outside)

setup.ts:86-101: at startup, create a Unix Domain Socket under $TMPDIR (--messaging-socket-path can specify); an external process can write messages into the socket to inject them into the conversation (on by default for ant, feature UDS_INBOX, implementation dynamically imported from utils/udsMessaging.js); the path is passed to child processes via $CLAUDE_CODE_MESSAGING_SOCKET, and the bind must finish before the SessionStart hook (comments :91-94). --bare mode skips it.

--worktree isolation

entrypoints/cli.tsx:247-261: -w/--worktree runs the session inside a git worktree (.claude/worktrees/<slug>), so changes do not touch the main workspace; the slug has path-traversal protection (comment utils/worktree.ts:52-55); with --tmux there is also a fast exec path.

SDK / Headless mode

  • cli/print.ts (5594 lines): entry for claude -p "..." non-interactive mode, no React tree (comment :517); supports --output-format json/stream-json, a headless profiler (:314-317), headless plugin install (:331).
  • QueryEngine.ts: abstracts "one query" into a reusable engine (shared by SDK and CLI): assemble tools/systemPrompt/toolUseContext (:370, :518), drive query.ts's async-generator loop, produce an SDKMessage stream (SDK consumers) or text (print mode).
  • Also supports --bare (slim startup: skip skill discovery, UDS, telemetry init, etc., loadSkillsDir.ts:654-675, setup.ts:86-88).
↑