How Claude Code Actually Works Under the Hood
Most developers treat Claude Code like a chatbot with file access. Type a request, get some code back, copy-paste it in. That mental model misses what actually makes it work.
Claude Code is a terminal-native coding agent built by Boris Cherny and the team at Anthropic. It doesn’t just generate text. It runs a closed loop of reading your codebase, taking actions through tools, and verifying results until a task is done. The architecture behind that loop, and the trade-offs it makes, explain why it feels fundamentally different from Copilot or Cursor.
Here’s what’s actually happening when you give it a task.
The Agentic Loop: Three Phases on Repeat
Every interaction with Claude Code triggers the same cycle: gather context, take action, verify results. Whether you’re debugging a failing test or refactoring a subsystem, it’s the same loop.
%%{init: {"layout": "dagre"}}%%
flowchart LR
A[Your Request] --> B[Gather Context]
B --> C[Take Action via Tools]
C --> D[Verify Results]
D --> |"not done"| B
D --> |"done"| E[Response]
Gather context. The client packages your prompt, the available tools, session history, and any project instructions (like your CLAUDE.md) into an API request to a Claude model.
Take action. The model decides which tools to call. Read a file. Run a test. Edit three lines in a module. The client executes those calls locally and streams results back.
Verify results. The model inspects tool output. Tests still failing? It reads the error, forms a new hypothesis, edits again. Tests pass? It returns a final response.
This loop is what separates an agent from a completion engine. Copilot suggests code. Claude Code closes the loop by checking whether that code actually works.
All Intelligence in the Model, All Side Effects in the Client
This is the architectural decision that defines Claude Code. The model never touches your filesystem directly. It can only reason and request tools. The client executes those requests mechanically.
| Component | Responsibility | Examples |
|---|---|---|
| Claude Model (remote) | Reasoning, planning, tool selection | ”I should read auth.ts first, then run the tests” |
| Claude Code Client (local) | Tool execution, security, session management | Reads the file, runs npm test, returns output |
Why this matters in practice:
- Security boundaries are enforced in the client. The model can ask to delete your database. The client can refuse.
- Behavioral quirks come from the tools, not the model. When Claude re-reads a file three times, that’s the file tool’s version tracking catching modifications, not the model being confused.
- Project-specific behavior comes from model interpretation. When Claude obeys your
CLAUDE.mdrule to “always run tests before committing,” that’s the model reading and following natural language instructions. No custom client logic needed.
This separation is why you can write a CLAUDE.md file with conditional rules like “don’t read internal-guidelines.md until you’re implementing a new endpoint” and have it just work. The client doesn’t parse those rules. The model does.
The Tool Surface: How Claude Code Interacts with Your Machine
Without tools, Claude is just a text generator. The tools are the action surface that makes it an agent.
| Tool Family | What It Does | Examples |
|---|---|---|
| File tools | Read, write, edit, multi-edit with version tracking | Read, Edit, Write |
| Execution tools | Run shell commands, tests, servers, git | Bash, git status, npm test |
| Web tools | Search documentation, fetch URLs | WebSearch, WebFetch |
| Code intelligence | Type errors, jump-to-definition via MCP plugins | Language server integrations |
Each tool call returns structured output (stdout, stderr, file contents, diffs) that gets appended to the model’s context window. The model conditions its next decision on everything it has seen so far.
A typical debugging loop looks like this:
1. Run tests → 3 failures in auth.test.ts
2. Read auth.test.ts → Expected token format mismatch
3. Read auth.ts → Found the JWT signing logic
4. Edit auth.ts → Fix the token expiry format
5. Run tests → 2 failures remaining
6. Read error output → Missing refresh token rotation
7. Edit auth.ts → Add rotation logic
8. Run tests → All passing
Eight tool calls, zero human intervention. That’s the loop doing its job.
Why Grep Instead of a Vector Database
Here’s a design decision that surprised a lot of people. Claude Code doesn’t index your codebase. No vector database. No embeddings. It uses file-based “agentic search”: grep/rg plus file reads, orchestrated by the model.
The team experimented with local vector DB RAG early on and dropped it. Here’s why:
1. Staleness under continuous edits. A coding agent modifies files constantly. Every edit invalidates some chunk embeddings. Unless you re-index after every change, the vector store returns stale snippets. When the agent then plans further edits based on stale context, things go wrong fast.
File-based retrieval avoids this entirely. The agent always reads the current file on disk. No index to drift out of sync.
2. Code is unusually grep-friendly.
Traditional RAG shines on messy knowledge bases: support docs, chat logs, unstructured specs. But code is highly structured. When you need “where is processCheckout defined” or “who calls refreshToken,” a ripgrep search plus a few file reads is often better than nearest-neighbor embedding retrieval.
3. Zero infrastructure. A proper RAG stack needs: chunking logic, an embedding model, an indexer, a vector database, background sync, permission scoping. That’s a second distributed system. Claude Code optimized for a minimalist, local-first CLI. No servers, no indexes, just tools that wrap standard filesystem commands.
4. Security footprint. A persistent vector index over your codebase encodes large portions of proprietary source. Even stored locally, it’s a sensitive asset consuming disk and RAM. Claude Code’s posture: no full-codebase index. Only the snippets the model explicitly requests get sent to the remote API.
The trade-off is real: agentic grep loops can burn tokens and run slow on large monorepos. Reports of multi-minute “grep goose chases” are common. But the Claude team accepted that worst-case token overhead in exchange for zero infra and always-fresh results.
For teams that need semantic search on massive codebases, MCP plugins like Claude Context layer a vector store on top. The core stays simple. The extension point exists when you need it.
How It Differs from Copilot
GitHub Copilot is a completion engine embedded in your IDE. It watches what you type and predicts the next few lines. Good at boilerplate. Fast at autocomplete. Operates at function-level scope.
Claude Code operates at system level. It plans multi-step operations across files, runs tests, uses git, and verifies its own work.
| Dimension | Claude Code | GitHub Copilot |
|---|---|---|
| Scope | Whole project, multi-file operations | Single file, line-level completions |
| Interface | Terminal CLI, scriptable | IDE plugin (VS Code, JetBrains) |
| Verification | Runs tests in a loop until passing | Relies on you to run tests |
| Workflow | git-centric, command-line automation | IDE-centric, minimal disruption |
| Best for | Debugging, refactors, architecture changes | Fast boilerplate, inline suggestions |
The key difference: Copilot suggests code. Claude Code suggests code, writes it, tests it, reads the error, fixes the error, and tests again. The loop is the product.
How It Differs from Cursor
Cursor is closer in ambition. It’s a full AI IDE built on VS Code with multi-file coordination, semantic search, and agentic refactoring capabilities.
But the architectural philosophy differs:
Cursor transforms the editor. AI-native refactors, inline diffs, rich context panels. You work inside Cursor’s environment.
Claude Code orchestrates from outside. It integrates with whatever editor and tools you already use. It lives in the terminal alongside your existing scripts, CI/CD pipelines, and automation.
| Dimension | Claude Code | Cursor |
|---|---|---|
| Interface | Terminal-first, editor-agnostic | Full IDE replacing VS Code |
| Context engine | Agentic search (grep + reads) | Built-in semantic search and indexing |
| Editing surface | Applies diffs via tools, review in your editor | Inline diffs and AI refactors in the IDE |
| Team adoption | Fits terminal-heavy, automation-centric teams | Teams willing to adopt a new IDE |
| Extension model | MCP plugins for additional capabilities | Cursor-specific extensions |
Cursor is the right choice if you want the IDE to be AI-native. Claude Code is the right choice if you want an agent that works alongside your existing tools.
Many teams use both. Cursor for micro-level edits in the editor. Claude Code for macro-level operations that need planning, execution, and verification loops across the entire repository.
Sessions, Snapshots, and Memory
Claude Code stores work in sessions. Each session records user messages, tool invocations, and results. Before modifying files, it snapshots them so you can revert.
Each new session starts with a fresh context window. No conversation history carries over. But two mechanisms provide continuity:
CLAUDE.md: A file in your repo that acts as persistent project instructions. The model reads it at session start and follows it like any other instruction. Because it’s model-interpreted (not client-parsed), you can encode rich conditional logic in natural language.- Auto memory: Claude can persist learnings to memory files that get loaded into future sessions.
This design means project knowledge lives in version-controlled files, not in opaque session state. Your CLAUDE.md is reviewable, editable, and shareable across the team.
The Bottom Line
Claude Code isn’t a smarter autocomplete. It’s an orchestrated agent with a clear architectural boundary: reasoning lives in the model, execution lives in the client, and tools are the bridge between them.
The agentic loop (gather context, act, verify) is what lets it close the gap between “here’s some code” and “here’s working code that passes your tests.” The decision to use grep over vector search keeps it simple, fresh, and secure at the cost of occasional token-heavy search loops. And the client-server separation means your CLAUDE.md instructions are interpreted by a frontier model, not parsed by a regex in a CLI binary.
Whether that trade-off set works for you depends on how you work. If you live in the terminal and want an agent that fits your existing workflow, it’s hard to beat. If you want AI deeply woven into a visual editor, Cursor is the better fit.
The tools aren’t mutually exclusive. The best setup I’ve found: Claude Code for the big moves, your editor of choice for the small ones.
Exploring AI coding tools and agent architectures? I’d love to hear what’s working for your team. Reach out on LinkedIn.