🎯 Six-Layer Architecture
Layer 1 -- Priority Resolver
systemPrompt.ts implementa override > coordinator > agent > custom > default
Layer 2 -- Content Factory
prompts.ts monta secoes estaticas + dinamicas por sessao
Layer 3 -- Section Registry
systemPromptSections.ts gerencia caching memoized vs. volatile
Layer 4 -- CLAUDE.md Loader
claudemd.ts lida com descoberta multi-scope, @include, frontmatter
Layer 5 -- Memory System
memdir/memdir.ts injeta MEMORY.md + auto-memory
Layer 6 -- Cache Boundary
SYSTEM_PROMPT_DYNAMIC_BOUNDARY separa prefixo de escopo global
🎯 Priority Resolver - Which Prompt Runs?
buildEffectiveSystemPrompt() implementa um waterfall estrito de prioridades. Uma vez que uma fonte de maior prioridade e encontrada, camadas inferiores sao ignoradas.
💡 Insight-chave
appendSystemPrompt sempre anexa a todo branch exceto quando overrideSystemPrompt esta ativo. Em modo proactive/KAIROS, instrucoes do agente sao appended ao prompt default ao inves de substitui-lo.
🏭 Content Factory - getSystemPrompt()
export async function getSystemPrompt(tools, model, additionalDirs, mcpClients) {
const [skillToolCommands, outputStyleConfig, envInfo] = await Promise.all([
getSkillToolCommands(cwd),
getOutputStyleConfig(),
computeSimpleEnvInfo(model, additionalDirs),
])
return [
// -- Static (globally cacheable) --
getSimpleIntroSection(outputStyleConfig),
getSimpleSystemSection(),
getSimpleDoingTasksSection(),
getActionsSection(),
getUsingYourToolsSection(enabledTools),
getSimpleToneAndStyleSection(),
getOutputEfficiencySection(),
// -- Boundary marker --
SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
// -- Dynamic (session-specific) --
...resolvedDynamicSections,
].filter(s => s !== null)
}
Referencia de Secoes Estaticas
| Secao | Conteudo |
|---|---|
| getSimpleIntroSection() | Identidade, URL-generation guard, CYBER_RISK_INSTRUCTION |
| getSimpleSystemSection() | Markdown rendering, permission-mode, prompt-injection warning |
| getSimpleDoingTasksSection() | Task scope, YAGNI, security hygiene, code-style |
| getActionsSection() | Reversibility, blast-radius guidance, risky action taxonomy |
| getUsingYourToolsSection() | Prefer dedicated tools, parallel calls, task-tracking |
| getSimpleToneAndStyleSection() | No emojis, file:line references, GitHub format |
| getOutputEfficiencySection() | Conciseness/prose quality rules |
📋 Dynamic Sections Registry
// Memoized -- computed once per session
export function systemPromptSection(name, compute): SystemPromptSection {
return { name, compute, cacheBreak: false }
}
// Volatile -- recomputes every turn
export function DANGEROUS_uncachedSystemPromptSection(name, compute, reason) {
return { name, compute, cacheBreak: true }
}
| Section | Cache | Conteudo |
|---|---|---|
| session_guidance | memo | Ask-user, interactive shell, skill syntax |
| memory | memo | CLAUDE.md hierarchy + MEMORY.md |
| env_info_simple | memo | CWD, git, platform, model, cutoff |
| language | memo | "Always respond in X" |
| output_style | memo | Named output style from settings |
| mcp_instructions | volatile | Per-server instruction blocks |
| scratchpad | memo | Per-session scratchpad path and rules |
| token_budget | memo | "Keep working until target" instruction |
⚠️ Por que mcp_instructions e volatile?
"MCP servers can connect and disconnect between turns. If the instructions were cached, a server that connects after the first turn would never get injected." O custo e potencialmente bustar o prompt cache em eventos de connect/disconnect.
💰 The Cache Boundary
A API do Claude suporta prompt caching: prefixos identicos sao cobrados a uma fracao do custo normal. Para explorar isso, o system prompt se divide em um prefixo estavel (mesmo para todos os usuarios) e um tail volatil (conteudo por sessao).
export const SYSTEM_PROMPT_DYNAMIC_BOUNDARY = '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'
// WARNING: Do not remove or reorder this marker without updating cache logic in:
// - src/utils/api.ts (splitSysPromptPrefix)
// - src/services/api/claude.ts (buildSystemPromptBlocks)
✅ Static Prefix (global cache)
- Intro
- System
- Doing Tasks
- Actions
- Tools
- Tone
- Output Efficiency
🔄 Dynamic Tail (per-session)
- Session Guidance
- Memory/CLAUDE.md
- Env Info
- Language
- Output Style
- MCP Instructions
- Scratchpad, FRC, Token Budget
⚠️ Engineering Constraint
Qualquer expressao condicional de runtime colocada antes da boundary multiplica o numero de hashes de prefixo de cache distintos por 2 por condicao. Engenheiros explicitamente moveram flags session-specific para apos a boundary por exatamente esta razao.
📂 CLAUDE.md Injection
Load Order (prioridade crescente)
/etc/claude-code/CLAUDE.md) -- Global para todos os usuarios
~/.claude/CLAUDE.md) -- Global privado por projeto
CLAUDE.md / .claude/CLAUDE.md / .claude/rules/*.md)
CLAUDE.local.md) -- Privado especifico do projeto
A Diretiva @include
# CLAUDE.md
@shared-rules.md # relative path (same dir)
@./scripts/lint-conventions.md # explicit relative
@~/company/global-standards.md # home-relative
@/absolute/path/to/rules.md # absolute
Arquivos incluidos sao inseridos como entradas separadas antes do arquivo que os inclui. Referencias circulares sao prevenidas via set de caminhos processados.
Frontmatter Path Filtering
---
paths:
- src/components/**
- "*.tsx"
---
Always use named exports in React components.
📊 MEMORY.md Limits
Auto-memory (memdir/memdir.ts) trunca MEMORY.md em 200 linhas ou 25,000 bytes, o que disparar primeiro, com warning anexado se truncado.
🤖 Subagent Enhancement & Escape Hatches
CLAUDE_CODE_SIMPLE=1
Ativa um system prompt de tres linhas -- sem instrucoes, sem CLAUDE.md, sem tool guidance. Util para benchmarking da capability raw do modelo.
if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) {
return [`You are Claude Code...\n\nCWD: ${getCwd()}\nDate: ${getSessionStartDate()}`]
}
Subagents
Subagents lancados por AgentTool nao passam por getSystemPrompt(). Eles partem de DEFAULT_AGENT_PROMPT e sao enriquecidos com enhanceSystemPromptWithEnvDetails().
export const DEFAULT_AGENT_PROMPT = `You are an agent for Claude Code,
Anthropic's official CLI for Claude. Given the user's message, you should
use the tools available to complete the task. Complete the task fully--
don't gold-plate, but don't leave it half-done.`
Proactive / KAIROS Mode
Retorna um prompt curto de identidade de agente autonomo ao inves do prompt completo de sessao interativa:
return [
`\nYou are an autonomous agent. Use the available tools...\n\n${CYBER_RISK_INSTRUCTION}`,
getSystemRemindersSection(),
await loadMemoryPrompt(),
envInfo,
getLanguageSection(settings.language),
getMcpInstructionsSection(mcpClients),
getScratchpadInstructions(),
getProactiveSection(),
].filter(s => s !== null)
📋 Resumo do Modulo
buildEffectiveSystemPrompt() implementa waterfall estrito: override > coordinator > agent > custom > default
mcp_instructions e volatile
getSystemPrompt() e partem de DEFAULT_AGENT_PROMPT
CLAUDE_CODE_SIMPLE=1 para stub, proactive mode para identidade autonoma