Claude Code - Risk Assessment & Teaching Complexity Analysis
Coding Conventions
Naming Conventions
- Files: PascalCase for classes/components (
BashTool.tsx,QueryEngine.ts), camelCase for utilities (processUserInput.ts) - Directories: PascalCase for tool/component directories (
AgentTool/,FileEditTool/), camelCase for utility modules (settings/,permissions/) - Types: PascalCase, often with descriptive suffixes (
ToolUseContext,PermissionDecisionReason,TaskStateBase) - Functions: camelCase, verb-first (
buildTool(),findToolByName(),getSystemPrompt()) - Constants: SCREAMING_SNAKE_CASE (
REMOTE_SAFE_COMMANDS,INTERNAL_ONLY_COMMANDS)
File Organization Patterns
- Each tool:
XxxTool.ts(x)(core) +prompt.ts(model description) +UI.tsx(render) +constants.ts - Each command: sub-directory with
index.tsorcommand-name.ts - Root-level files serve as "barrel" re-exports or top-level orchestrators
types/directory breaks circular import cycles
TypeScript Patterns
- Zod v4 for runtime schema validation (tool inputs, settings)
- Discriminated unions for
Command(3 variants),PermissionDecisionReason(9 variants),TaskType(7 variants) - Branded types for
SessionId,AgentIdviaids.ts - DeepImmutable<> wrapper for
AppStateto enforce immutable updates - AsyncGenerator for streaming data flow (
query(),submitMessage()) feature()frombun:bundlefor compile-time dead code eliminationmemoizefrom lodash-es for caching expensive computations
Key Design Patterns
1. Builder/Factory Pattern: buildTool()
- Location:
src/Tool.ts - Every tool is constructed via
buildTool(def), which merges defaults for optional methods - The
ToolDeftype defines what implementors must/may provide;Toolis the fully-resolved type
2. Dependency Injection: ToolUseContext
- Location:
src/Tool.ts - A 40+ field context object passed through the entire tool call chain as function arguments
- Avoids global state; different modes (REPL/SDK/sub-agent) provide different field subsets
- This is NOT a traditional DI container; it's a large "environment" bag
3. AsyncGenerator/Coroutine Pattern
- Location:
src/query.ts,src/QueryEngine.ts query()andsubmitMessage()are bothAsyncGeneratorfunctions- Enables backpressure-aware streaming consumption
- Natural fit for "produce events as they happen" model
4. Observer/Pub-Sub Pattern
- Location:
src/state/store.ts - 35-line Zustand-style store:
createStore<T>()->{ getState, setState, subscribe } - React integration via
useSyncExternalStoreinsrc/state/AppState.tsx
5. Command Pattern (Discriminated Union)
- Location:
src/types/command.ts - Three command variants:
PromptCommand,LocalCommand,LocalJSXCommand - Dispatched by
typefield in the command registry
6. Strategy Pattern: Permission Handlers
- Location:
src/hooks/useCanUseTool.tsx - Three-way handler chain: coordinator -> swarm worker -> interactive
- Selection based on runtime context (is coordinator? is swarm worker? is interactive?)
7. Decorator Pattern
- Location:
src/QueryEngine.ts wrappedCanUseToolwraps the originalcanUseToolto append permission denial records
8. Plugin/Extension Pattern
- Location:
src/skills/,src/plugins/,src/services/mcp/ - Skills: Markdown files with YAML frontmatter -> dynamic
Commandgeneration - Plugins: Structured packages providing MCP servers, slash commands, hooks
- MCP: External tool servers connected via stdio/SSE/HTTP/WebSocket
Complexity Hotspots (Teaching Difficulty Ranking)
Critical Complexity (Require Dedicated Chapters)
1. src/main.tsx — The God Function
- ~4000+ lines in a single file
- Contains ALL CLI argument parsing, ALL run mode branches, ALL precondition validation
- Teaching approach: Draw a mode branch tree first, then deep-dive per-branch
2. src/query.ts — The Agentic Loop
while(true)loop with 7continuepaths- Implicit state machine: auto-compact, max-token recovery, reactive compact, etc.
- No explicit state machine definition; trigger conditions scattered across conditionals
3. src/tools/BashTool/bashPermissions.ts — 2600-line Permission Engine
- Wildcard matching, command parsing, speculative classifier
- The single most complex file in the tools/ directory
4. src/ink/ — Custom React Reconciler
- Complete TUI framework: reconciler, Yoga WASM layout, ANSI rendering, terminal I/O
- ~85 files implementing a full React renderer targeting terminal output
- Requires deep React internals knowledge to understand
5. src/screens/REPL.tsx — The Interactive Session
- ~3000+ lines orchestrating all UI interactions
- Manages message display, user input, permission dialogs, task panels, teammate views
High Complexity (Substantial Explanation Needed)
6. src/hooks/useCanUseTool.tsx — Permission Decision Tree
- Multi-layer async race: coordinator -> swarm -> speculative classifier (2s timeout) -> interactive dialog
Promise.racewith timeout, multiple fallback paths- Note: File is React Compiler output, harder to read than source
7. src/QueryEngine.ts::submitMessage() — ~900 lines
- Single async generator function containing transcript persistence, budget checks, snip compaction, message dispatch
- Multiple interleaved concerns in one function
8. src/bootstrap/state.ts — Global Mutable Singleton
- 80+ getter/setter functions, implicit temporal coupling
- Some getters return uninitialized values before
init()completes
9. src/Tool.ts::ToolUseContext — 40+ Field Context Object
- Optional fields mean different modes provide different subsets
- No type-level enforcement of which fields exist in which mode
Medium Complexity (Moderate Explanation)
10. src/commands.ts — Feature Flag Conditional Loading
feature('FLAG') ? require('./module') : nullpattern breaks static analysis- 70+ commands with dynamic skill/plugin merging
11. src/services/mcp/ — MCP Client Management
- 4 transport types (stdio, SSE, HTTP, WebSocket)
- OAuth authentication, tool/resource enumeration
12. src/services/compact/ — Context Window Management
- Auto-compact, micro-compact, snip strategies
- Critical for understanding how Claude Code handles long conversations
Teaching-Relevant "Aha Moments"
These are the non-obvious architectural decisions that will create the biggest learning impact:
The AsyncGenerator Pipeline: Why
query()is a generator, not a callback/promise — it enables natural backpressure and streaming without complex event emitter wiringToolUseContext as "Everything Bag": Why a single 40-field object instead of 10 smaller interfaces — pragmatic trade-off for a system where most tools need most context
The 35-Line Store: How
src/state/store.tsachieves Zustand-like functionality in 35 lines, and why the team chose this over a librarybuildTool() Factory: How a single factory function with TypeScript generics ensures every tool implements the full
Toolinterface while making most methods optionalCompile-Time Feature Flags: How
bun:bundle'sfeature()enables dead code elimination at build time while GrowthBook provides runtime overridesPermission Decision Cascade: The 9-variant
PermissionDecisionReasonunion that traces exactly why every permission decision was made — a lesson in auditabilityRecursive Agent Architecture: How
AgentToolcallsquery()recursively to create sub-agents, sharing some context (file cache) while isolating others (message history)Custom React Reconciler for Terminal: Why Anthropic built their own Ink fork instead of using the npm package — performance and control needs for a production CLI tool
Risks for Teaching Guide Creation
Content Organization Risks
R1: main.tsx is too large to explain linearly
- Mitigation: Break into "mode branches" and explain each as a separate path through the function
R2: React Compiler output files are unreadable
- Affected:
AppState.tsx,useCanUseTool.tsx - Mitigation: Explain the pre-compilation logic; reference source maps embedded in file footers
R3: Circular dependency patterns
- The
types/directory exists specifically to break cycles - Teaching must explain why certain types live in
types/vs their "natural" module
R4: Feature flag dead code
- Readers may be confused by code blocks wrapped in
feature('FLAG')that are never reachable in open-source builds - Mitigation: Explain the DCE system early, mark feature-gated code clearly
Scope Risks
R5: utils/ is 564 files — cannot cover exhaustively
- Strategy: Cover key sub-areas (bash/, permissions/, settings/, swarm/, model/) and provide a directory map for the rest
R6: components/ is 389 files — UI coverage needs scoping
- Strategy: Focus on message rendering pipeline, permission dialogs, and the design system; treat rest as reference