CC
Claude Code
v2.1.88
Claude CodeQuery/Engine Module

Query/Engine Module

15 files · ~15K lines

The Orchestrator — every user message passes through here. QueryEngine.ts owns the conversation lifecycle; query.ts implements the 7-phase agentic loop state machine. This is the heart of everything.

QueryEngine vs query() — the distinction

QueryEngineStateful class · one per conversation

Owns the conversation: message history, system prompt assembly, session config. Async generator — call .input() with user text, get an async iterator of SDKMessage back.

QueryEngine→ delegates each turn →
query()Stateless loop · called per turn

The inner loop. Runs the 7 phases using state QueryEngine passes in. Does NOT store state — each call is independent. This makes the loop testable and forkable for subagents.

The 7-Phase query() Loop

Each iteration of query.ts goes through exactly these 7 phases. Every tool execution, every compaction, every token passes through this 1729-line file.

1
Context Projection
Trim the conversation to fit within the context window. Applies compression heuristics — drops oldest messages, truncates large tool outputs.
Recovery: If too much is dropped, phase 2 takes over.
2
Auto-Compaction Check
If token budget is near limit (>80%), trigger services/compact to summarize older context. The escalation strategy runs: trim → truncate → summarize → replace.
Recovery: After compaction, loop restarts at phase 1.
3
API Streaming
Call the Anthropic API. Stream the response — collect text_delta tokens and tool_use blocks as they arrive. Render partial text to the terminal in real-time.
Recovery: On API error: exponential backoff, up to 3 retries.
4
Tool Execution
Execute queued tool_use blocks via StreamingToolExecutor. Permission checks happen here. Tools can run concurrently if isReadOnly() and maxConcurrency allow.
Recovery: Tool errors are returned as tool_result blocks — not exceptions.
5
Attachment Processing
Prefetch and resize any attachments (images, PDFs) referenced in upcoming messages. Inject them into the next message turn before sending.
Recovery: Failed attachments become error messages, not crashes.
6
Continuation Check
Decide: did the model finish (stop_reason = end_turn) or must we loop for more tool results? If tools are pending, loop back to phase 1.
Recovery: Max iterations guard: loops terminate after N turns.
7
Yield Result / Loop
Yield SDKMessage objects to the caller (terminal or SDK). Then either loop back to phase 1 for more, or exit with a terminal state (done, error, cancelled).
Recovery: Cancelled state is propagated to cleanup handlers.

LoopState — What query() Carries

The state object passed through all 7 phases. Each phase reads and mutates parts of it.

Conversation
messagesMessage[]

Full conversation history, including all tool calls and results

systemPromptstring

Assembled system prompt including project context, CLAUDE.md, memory

toolsTool[]

Active tools for this query — built-in + MCP-proxied

Tracking
tokenBudgetTokenBudget

Tracks used/remaining tokens across prompt, output, and tool results

loopCountnumber

Current iteration count — guard against infinite tool loops

stopReasonStopReason | null

end_turn | max_tokens | tool_use | error | cancelled

Security
permissionRulesPermissionRule[]

Session-scoped rules the user has approved during this conversation

Token Budget Math — 200K Context Window

How the 200K context window of Claude Sonnet splits up in a typical session.

System Prompt
15%
Conversation History
40%
Tool Results
25%
Output Budget
15%
Safety Buffer
5%

Key Files

QueryEngine.ts~1295 lines

Conversation lifecycle, system prompt assembly, message buffering

query.ts~1729 lines

The main agentic loop state machine, 7 distinct phases

Task.ts~300 lines

Task abstraction for multi-agent parallel work

entrypoints/cli.tsx~200 lines

CLI bootstrap — fast-path (--version, daemon) then calls QueryEngine

entrypoints/sdk/~400 lines

Headless SDK entrypoint — exposes QueryEngine as a programmatic API