Context: Studying Claude Code source code (backup branch)

Complete Message Anatomy of a Claude Code API Turn

System Prompt (role: system)

Built in QueryEngine.ts:321, finalized in claude.ts:1358:

  1. Attribution header (fingerprint)
  2. CLI sysprompt prefix (interactive vs non-interactive)
  3. Default system prompt (or custom SDK prompt)
  4. Memory mechanics prompt (if custom prompt + memory override)
  5. Append system prompt (SDK callers)
  6. Advisor tool instructions (if advisor model)
  7. Chrome tool search instructions (if chrome MCP)
  8. gitStatus (from context.ts:116 via appendSystemContext)
  9. cacheBreaker (ant-only)

Messages (role: user or assistant)

Everything except system prompt and assistant responses is user-role. The API only has system/user/assistant roles.

Session Start

  • [user, isMeta] Deferred tools listing (claude.ts:1337)
  • [user, isMeta] userContext wrapped in <system-reminder> (api.ts:449): CLAUDE.md content, currentDate

User Input + Attachments

  • [user] Actual user message
  • [user, isMeta] ~30+ attachment types from getAttachments() (attachments.ts:743), all <system-reminder> wrapped. Categories:
    • User input: @-mentioned files (simulated Read tool_use/result), MCP resources, agent mentions, skill discovery
    • Per-turn state: queued_commands, date_change, ultrathink_effort, deferred_tools_delta, agent_listing_delta, mcp_instructions_delta, changed files, nested_memory, relevant_memories, dynamic_skill, skill_listing, plan_mode, todo/task_reminder, teammate_mailbox, team_context, critical_system_reminder, compaction_reminder, context_efficiency, output_style, diagnostics, IDE state
    • Post-compact: invoked_skills (up to 25K tokens), plan_file_reference, current_session_memory

Model Response

  • [assistant] thinking block, text blocks, tool_use blocks

Tool Execution Cycle (toolExecution.ts)

For each tool_use in the assistant response:

PreToolUse hooks:
  [user, isMeta] hook_success              (line 815)
  [user, isMeta] hook_additional_context   (line 846, <system-reminder> wrapped)
  [user, isMeta] hook_permission_decision  (if hook decided)
  [user, isMeta] hook_blocking_error       (if hook blocked)
  OR [user] tool_result error              (line 853, if hook stopped)

Permission check:
  [user, isMeta] command_permissions       (line 985)

Tool result:
  [user] tool_result                       (line 1478)

PostToolUse hooks (non-MCP, pushed immediately):
  [user, isMeta] hook_success              (line 1515)
  [user, isMeta] hook_additional_context   (toolHooks.ts:133)

Tool's newMessages (e.g. SkillTool):
  [user] command metadata                  (<command-message> tags)
  [user, isMeta] SKILL.md content          (full skill instructions)
  [user, isMeta] skill @-mention attachments
  [user, isMeta] command_permissions       (skill's allowedTools)

  [user, isMeta] hook_stopped_continuation (line 1572, if preventContinuation)

Then getAttachmentMessages runs again with updated state, plus memory prefetch and skill discovery prefetch consume.

Loop repeats for each subsequent tool_use until stop_reason: end_turn.

Key Observations

  1. All injected content is user-role. Hooks, attachments, skills, tool results, file changes, IDE state, memory, team messages: all isMeta: true user messages. The model has no formal way to distinguish sources.
  2. Consecutive user messages are merged by normalizeMessagesForAPI (messages.ts:1989) into single user turns. Content blocks accumulate.
  3. <system-reminder> is the only priority signal. With tengu_chair_sermon gate, all attachments get ensureSystemReminderWrap. Without it, only some types wrap explicitly. Either way, no formal authority hierarchy.
  4. Recency dominates. Order within a turn: user input → attachments → assistant → PreToolUse hooks → tool_result → PostToolUse hooks → skill newMessages → more attachments. Skill content and post-execution attachments have strongest positional influence.