Skip to main content

Context Assembly & System Prompt Engineering

Each request sent to the LLM consists of three context parts. This assembly system determines what the LLM "knows" and "how it acts."

Three-Part Context Structure

PartSourceContent
System PromptgetSystemPrompt()Role definition, tool instructions, behavior rules
User ContextgetUserContext()CLAUDE.md project rules, current date
System ContextgetSystemContext()Git status snapshot, auxiliary info

These three parts are loaded in parallel by fetchSystemPromptParts() in src/utils/queryContext.ts.

System Prompt Assembly

Structure: Static Prefix + Dynamic Sections

+---------------------------------------------+
| Static Prefix (cacheable) |
| - Role definition |
| - Tool instructions |
| - Behavior rules |
| - Per-tool usage guides |
+------ SYSTEM_PROMPT_DYNAMIC_BOUNDARY --------+
| Dynamic Sections (may vary per request) |
| - Memory instructions |
| - Environment info |
| - Language preference |
| - MCP server instructions |
| - Output style settings |
+---------------------------------------------+

Cache Boundary Design

SYSTEM_PROMPT_DYNAMIC_BOUNDARY optimizes Anthropic API's prompt caching: static content before the boundary stays constant across turns (cacheable), while dynamic content after it can change freely without invalidating the cache.

Dynamic Section System

// src/constants/systemPromptSections.ts
systemPromptSection('memory_instructions', () => loadMemoryPrompt())
// Computed once per session, cached until /clear or compact

DANGEROUS_uncachedSystemPromptSection('env', () => getEnvInfo())
// Recomputed every time (name warns about performance impact)

User Context

getUserContext() in src/context.ts returns a { [key: string]: string } dictionary containing:

  1. CLAUDE.md chain: project rules loaded from multiple locations (working dir, project root, parent dirs, ~/.claude/)
  2. Current date: injected for LLM time awareness

System Context

getSystemContext() returns auxiliary keyed strings, notably git status snapshots when enabled.

Context Injection into API Requests

deps.callModel(messagesForAPI, {
systemPrompt: prependUserContext(systemPrompt, userContext),
...appendSystemContext(systemContext),
});

Key Source Files

FileResponsibility
src/constants/prompts.tsgetSystemPrompt(): main system prompt assembly
src/constants/systemPromptSections.tsDynamic section system
src/context.tsgetUserContext() / getSystemContext()
src/utils/queryContext.tsfetchSystemPromptParts(): parallel loading

Next

Go to 07-memory-system.md to learn how the memory system maintains knowledge across sessions.

Hands-on Experiment

This chapter has a corresponding Python experiment:

Lab 06 — Prompt Assembly

Covers: three-part assembly, cache boundary, CLAUDE.md chain

cd experiments && python -m exp_06_prompt_assembly.main --mock