Architecture Decisions

Key architectural decisions in claude-code and the reasoning behind them. These represent deliberate engineering choices, not defaults.

1. Async Generator Over State Machine

The core query-ts loop uses async function* instead of a state machine or event emitter. This unifies streaming (yield), termination (typed return), and error propagation in a single function. Tool calls are tail-recursive iterations, not separate handler branches.

2. Grep Over RAG

grep-over-rag: Early versions used Voyage embeddings + vector DB. The team switched to agentic grep before launch. Rationale: accuracy on identifiers, no external storage (security), no staleness, no preprocessing. Boris Cherny confirmed: "agentic search generally works better."

3. Cache as Load-Bearing Infrastructure

cache-economics: Every design decision bends toward prompt cache preservation. The forked-agent-pattern achieves 92% prefix reuse. Breaking cache multiplies costs 5-10x. Functions that invalidate cache are prefixed DANGEROUS_.

4. Five-Layer Platform Architecture

five-layer-architecture: Not a thin API wrapper. Clean separation into Entrypoints, Runtime, Engine, Tools, Infrastructure. The bridge-system abstracts transport so the same engine powers CLI, desktop, web, IDE, and SDK.

5. Safety as a Layer, Not a Property

permission-pipeline: Permission checks, path traversal prevention, bash-security, and the auto-mode-classifier are explicit layers in a pipeline — not properties of the model. Testable, updatable, and bypassable (which is a feature for bypassPermissions mode).

6. Dead-Code Elimination as Deployment

Feature flags that compile to false leave no trace in the binary. growthbook remote flags control gradual rollout. The gap between internal and external builds is maintained entirely by the build pipeline.

7. Model as Planner

No external DAG scheduler. The model reads context and decides the next action. Planning quality scales with model quality — better models unlock better agent behavior without code changes.

8. Memory by LLM Reasoning, Not Embeddings

auto-memory and memory-hierarchy use LLM reasoning over filenames instead of vector search. Claude calls ls(), reasons about relevance, reads selected files. Simpler, interpretable, and outperforms opaque vector matching for structured files.