中文 | English
- Readers who finished P1 and are ready for Claude Code’s actual heart
- Readers who want to connect “mode routing” to “how one request really runs”
90-120 minutes
This stage narrows the work to the three things inside the single-turn mainline:
- how one request becomes the control rhythm inside
query/queryLoop - how model output, tool call, tool execution, and
tool_resultflow back into one loop - why permissions and streaming become important exactly here
Mainline position: enter query / queryLoop → model output → tool call → tool execution → tool result flows back → next turn or exit
sequenceDiagram
participant QE as QueryEngine
participant Q as query()
participant QL as queryLoop() — while(true)
participant API as services/api/claude.ts
participant Tool as BashTool + 3-layer permissions
QE->>Q: yield* query(params)
Q->>QL: yield* queryLoop()
loop each turn
QL->>QL: yield stream_request_start
QL->>API: queryModelWithStreaming
API-->>QL: streaming event flow
alt end_turn (task complete)
QL-->>Q: yield done → return
else tool_use (tool call)
QL->>Tool: semantic deny → rule match → ask user → execute
Tool-->>QL: tool_result
QL->>QL: append to history, continue while(true)
end
end
Q-->>QE: event stream ends
Unlike P1, this page is now inside the real request mainline.
Your job here is not to memorize features. It is to see why one request advances in this order:
query/queryLoopdrives the turn- the model returns text or a tool call
- tool execution results must re-enter message history
- streaming and permissions determine whether the turn can keep moving safely
Keep l2_agent_loop.py as the main anchor:
python examples/l2_agent_loop.pyWith an API key, then add the supporting boundaries:
python examples/l7_permissions.py
python examples/l8_streaming.pyWithout an API key, at least run:
python examples/l7_permissions.pyDo not let l7 or l8 steal the spotlight. They support the mainline; they do not replace l2.
Read in this order:
Only after the mainline feels stable, add:
Open these three mainline files first:
claudecode_src/src/query.ts— wherequery/queryLoopdrives the single-turn loopclaudecode_src/src/QueryEngine.ts— where session orchestration supports the turnclaudecode_src/src/services/api/claude.ts— where model streaming becomes higher-level events
After the mainline connects cleanly, add one tool boundary:
claudecode_src/src/tools/BashTool/bashPermissions.tsclaudecode_src/src/tools/BashTool/bashSecurity.ts
Deliberately ignore these branches for now:
- prompt cache and memory
- MCP / hooks / plugins extension surfaces
- multi-agent / structured output
- deep REPL UI state organization
- do not read every tool registration detail yet; follow only the boundary required for one turn
This page is about locking in the single-turn spine, not expanding to the whole system map too early.
Use two passes:
l2_agent_loop.pyL2query.tsQueryEngine.ts
l7_permissions.pyl8_streaming.pyL7L8services/api/claude.ts
export async function* queryasync function* queryLooptool_resultBASH_SECURITY_CHECK_IDSstream_request_startqueryModelWithStreamingfirst_chunk
- Why is Claude Code’s core abstraction closer to “state machine plus event stream” than a normal
whileloop? - Why must tool results be appended back into message history instead of being printed and discarded?
- Why do permissions and streaming belong inside the main call chain instead of hanging off the side?
- Exercise 1: trace one minimal call chain
- Exercise 3: tools and permissions boundary
- Exercise 4: streaming events
By the end of this page, you should be able to:
- explain the basic rhythm of one turn driven by
query.ts - explain how model output, tool execution, and
tool_resultform one loop - describe where permission checks, streamed events, and loop exit conditions each live
- know clearly that memory and later architectural branches are not the focus yet
If you cannot, go back to:
L2ifqueryandqueryLoopare still blurred togetherL7if security checks and user approval still feel like one thingL8if you still think streaming only means “print tokens as they arrive”
Continue to P3 Source Reading