Claude Code Agent Loop Deep Dive (9): Sidechains, Sub-agents, and agentId Routing A developer's deep-dive analysis of Claude Code's agent loop reveals that sub-agents run the same recursively invoked queryLoop function as the main agent, distinguished only by whether toolUseContext.agentId is undefined. Sub-agent messages are written to separate sidechain transcripts (.claude/subagents/agent-.jsonl) rather than the main session JSONL, with the sidechain's first message's parentUuid pointing back to the Agent tool-use message in the main tree. The previous eight posts described one loop: a user presses Enter, the loop runs until completion, and control returns to the user. Claude Code also has a more surprising arrangement: a loop can run inside another loop . When the primary conversation requests the Agent tool, Claude Code starts a sub-agent to perform an independent task and return only its final result. From the main loop's perspective, this is a long-running tool that eventually returns text. From the sub-agent's perspective, it is a complete loop with its own messages, tool execution, and stop decisions. The central question is whether this requires a separate sub-agent loop implementation—or whether it is the same loop with a different context. queryLoop , called recursively The obvious design would define two implementations, perhaps MainLoop and SubagentLoop . Claude Code takes the opposite approach: main agents and sub-agents run the same queryLoop function. Starting a sub-agent follows this shape: The main loop sees an Agent tool use ↓ Create a new toolUseContext ├── agentId = a new generated ID ├── messages = a fresh history ├── system prompt = a sub-agent-specific prompt └── other scoped fields ↓ Call queryLoop newToolUseContext recursively ↓ The sub-agent reaches completed and returns its result ↓ Append that result to the main history as tool result It is one function, recursively invoked. A sub-agent can even start another sub-agent, which is simply another recursive call. The benefit is maintenance: a bug fix, recovery transition, or scheduling improvement applies to both primary and sub-agent runs without being implemented twice. agentId routes the main-thread-only behavior Shared code still needs to know which context it is running in. Claude Code uses a single flag: toolUseContext.agentId === undefined toolUseContext.agentId is a generated identifier The loop contains several checks like if toolUseContext.agentId . They select behaviors that exist only on the primary thread: CLAUDE.md loading One flag covers many branch points. It costs some local readability—each branch needs a reason—but preserves the much larger advantage of shared loop code. Main-loop messages are persisted in a session transcript such as: ~/.claude/projects/