Cómo Claude Code Construye su System Prompt: 18 Capas que No Ves
Cuando escribes un prompt a Claude Code, no eres el único que habla. Hay 18 secciones ensambladas en orden estricto, una frontera dinámica que optimiza costes de caching y una filosofía de código que lucha contra la sobreingeniería. Esto es lo que encontramos al abrir el capó.
Claude Code es el CLI oficial de Anthropic para Claude. Es la herramienta que la mayoría de desarrolladores utilizan hoy para escribir código con asistencia de IA directamente desde la terminal. Pero la herramienta que ves — el prompt, la respuesta, la edición de archivos — es solo la capa visible de un sistema de ingeniería de prompts de nivel industrial.
Lo que no ves es que cada interacción que tienes con Claude Code está mediada por un system prompt de 18 secciones ensambladas en orden estricto, con una frontera dinámica que divide el prompt en una parte cacheable y otra que cambia por sesión. Hay una taxonomía explícita de riesgo, instrucciones en negativo que luchan contra los vicios del modelo, y un sistema de memoización que asegura que el prompt no se recalcula innecesariamente.
Lo sabemos porque hemos hecho reverse engineering del código fuente. Este artículo es el primero de una serie de 6 donde desmontamos Claude Code pieza a pieza.
⚡ Tesis de este artículo
El system prompt de Claude Code no es un texto estático — es un pipeline de ensamblaje con 18 secciones, cada una con su propósito, su gate condicional y su estrategia de caching. Entender cómo está construido revela patrones de ingeniería de prompts que puedes aplicar a tus propios agentes.
18 secciones en orden estricto
El punto de entrada es getSystemPrompt() en constants/prompts.ts. Esta función ensambla el system prompt concatenando secciones memoizadas en un orden que nunca cambia. Las primeras 12 secciones son estáticas y cacheables. Las últimas 6 cambian por sesión.
Pipeline de Ensamblaje Completo
"You are Claude Code, Anthropic's official CLI for Claude."
Modo interactivo vs headless — cambia "assist" por "complete"
Permite pentesting autorizado; prohíbe DoS y supply chain attacks
"NEVER generate or guess URLs" — previene phishing accidental
Modo de permisos activo, hooks de lifecycle, reglas de summarización
Anti-YAGNI puro: "Don't add features beyond what was asked for"
Taxonomía LOW/MEDIUM/HIGH risk para cada operación
Cuándo usar cada herramienta, encadenamiento, paralelización
Contexto aislado, herramientas heredadas, tools prohibidas
Internal: "≤25 words entre tools" — External: "Be terse"
Solo activo con feature flag TOKEN_BUDGET — muestra consumo por turn
Modo autónomo: tick-based wake-ups, notificaciones push, webhooks
══ __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ ══ CWD, git branch, OS, modelo, fecha, shell
Directorio temporal para archivos intermedios
CACHED_MICROCOMPACT — limpia resultados antiguos de tools
Instrucciones custom de cada servidor MCP conectado
Memorias extraídas automáticamente de conversaciones previas
Instrucciones de proyecto del usuario — extensión del system prompt
💡 ¿Por qué importa el orden? No es arbitrario. Los modelos de lenguaje prestan más atención al inicio y al final del sistema prompt (efecto de primacía y recencia). Anthropic coloca la identidad al principio y las instrucciones de proyecto del usuario (CLAUDE.md) al final — exactamente donde más peso tendrán.
La Frontera Dinámica — El Truco de Caching
En la posición 12–13 del pipeline hay un marcador que es invisible para ti:
__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ Este sentinel divide el system prompt en dos zonas con propósitos muy diferentes:
Zona Estática (arriba)
Secciones 1–12. Se cachean en la API de Anthropic entre turns. No se re-tokenizan cada vez que envías un mensaje.
Resultado: latencia menor, menos tokens facturados, misma funcionalidad.
Zona Dinámica (abajo)
Secciones 13–18. Cambian por sesión: directorio de trabajo, fecha, rama git, contenido de CLAUDE.md, memorias.
Se recalculan en cada turn porque reflejan el estado actual del entorno.
¿Por qué es esto un truco de ingeniería? Porque el prompt caching de Anthropic funciona por prefijo: si los primeros N tokens de un prompt coinciden con un prompt anterior, se reutiliza el cache. Al colocar todo el contenido estable antes de la frontera, Anthropic maximiza los cache hits. Cada turn de tu conversación reutiliza ~70% del system prompt sin pagar por él.
📊 Patrón aplicable: Si construyes agentes con la API de Anthropic, aplica la misma técnica. Coloca todo tu prompt estático antes de un marcador y todo lo dinámico (variables de entorno, fecha, historial) después. Reducirás costes y latencia sin cambiar una sola instrucción.
El Sistema de Caching Interno
Además del caching en la API, Claude Code tiene un sistema de memoización interno en systemPromptSections.ts. Cada sección del system prompt se calcula una vez y se cachea hasta que haces /clear o /compact.
// Memoized — cacheado hasta /clear o /compact systemPromptSection(name: string, compute: () => string): string // Recalcula CADA turn — rompe el cache (usar con moderación) DANGEROUS_uncachedSystemPromptSection( name: string, compute: () => string, reason: string ): string // Llamado en /clear y /compact — limpia también beta header latches clearSystemPromptSections(): void
El nombre DANGEROUS_uncachedSystemPromptSection no es accidental. El prefijo DANGEROUS es una señal deliberada para los desarrolladores: usar esta variante rompe el prompt cache, aumenta la latencia y cuesta más. Solo se usa para secciones que genuinamente cambian entre turns (como la información de entorno).
La Filosofía Anti-YAGNI
La sección 6 del pipeline — "Doing Tasks" — contiene la filosofía de código de Claude Code. Y es notablemente opinionada. En lugar de decir "escribe buen código", el prompt lista explícitamente lo que NO debes hacer:
- Don't add features beyond what was asked for - Don't add error handling for scenarios that can't happen - Don't create helpers for one-time operations - Don't add flexibility for "future needs" when not requested
Esto es anti-YAGNI puro — "You Ain't Gonna Need It". Anthropic ha descubierto que los LLMs, dejados a su aire, tienden a sobreingeniería: crean abstracciones innecesarias, añaden manejo de errores para escenarios imposibles, y construyen "por si acaso". Las instrucciones en negativo combaten estos vicios directamente.
🏗️ Build Interno (Anthropic)
- • Minimizar comentarios en código
- • Ser thorough con edge cases
- • NUNCA decir "no puedo" — intentar siempre
- • Mostrar el error real, no rehusar preventivamente
🌍 Build Externo (Público)
- • No añadir features más allá de lo pedido
- • No crear helpers para operaciones puntuales
- • No añadir flexibilidad "por si acaso"
- • Instrucciones más conservadoras (más guardrails)
La versión interna de Anthropic es notablemente más agresiva: empuja al modelo a intentar todo y mostrar errores reales en lugar de rehusar. La versión pública es más conservadora porque opera con usuarios menos técnicos que necesitan más protección.
La Taxonomía de Riesgo
La sección 7 — "Actions" — enseña al modelo una taxonomía de radio de explosión (blast radius). En lugar de depender del juicio subjetivo del modelo para decidir qué es peligroso, le da categorías concretas:
| Nivel | Ejemplos | Acción |
|---|---|---|
| LOW | Leer archivos, buscar código, git status, formatear | Ejecutar sin pedir permiso |
| MEDIUM | Escribir/editar archivos, crear ramas, ejecutar builds | Ejecutar con precaución |
| HIGH | Borrar archivos, force push, rm -rf, DROP TABLE | Pedir confirmación explícita |
Además, hay un subconjunto de operaciones que siempre requieren confirmación independientemente del modo de permisos:
- • Comandos destructivos —
rm -rf,DROP TABLE, formateo de disco - • Operaciones visibles para otros —
git push, enviar emails, publicar paquetes - • Cambios difíciles de revertir — Migraciones de BD, force push, cambios en configs fuera del proyecto
🎯 Patrón de diseño: En lugar de decir al modelo "ten cuidado", dale una tabla de decisión. Las taxonomías explícitas son más efectivas que las instrucciones vagas porque eliminan la ambigüedad. Si tu agente necesita decidir si algo es peligroso, no le pidas que "juzgue" — dale categorías concretas.
Secciones Condicionales y sus Gates
No todas las 18 secciones están siempre presentes. Varias están controladas por feature flags que se activan según el contexto:
| Sección | Gate / Trigger | Efecto |
|---|---|---|
| Token Budget | feature('TOKEN_BUDGET') | Muestra conteo de tokens por turn |
| KAIROS / Proactive | feature('PROACTIVE') | Modo autónomo: wake-ups, push, webhooks |
| Result Clearing | CACHED_MICROCOMPACT | Auto-limpia tool results antiguos |
| Coordinator Mode | Activación manual | Reduce toolset a Agent + TaskStop + SendMessage |
| Plan Mode | Usuario entra en plan mode | Modelo propone planes en vez de ejecutar |
| Simple Mode | CLAUDE_CODE_SIMPLE | Reduce a Bash + Read + Edit solamente |
| Memory | Sistema de memoria habilitado | Inyecta contenido de memorias extraídas |
| MCP | Servidores MCP conectados | Inyecta instrucciones de cada servidor |
Esto significa que el system prompt no tiene un tamaño fijo. Según la configuración del usuario y las features activas, puede variar significativamente. El sistema de memoización asegura que solo las secciones activas se ensamblan y cachean.
Patrones que Puedes Aplicar Hoy
Lo que hemos visto no es solo un ejercicio de curiosidad. Hay patrones concretos de ingeniería de prompts que puedes extraer de este diseño y aplicar a tus propios agentes:
1. Separar prompt estático de dinámico
Si usas la API de Anthropic, Claude o cualquier modelo con prompt caching, coloca todo el contenido estable al principio del system prompt. Variables de entorno, fecha, historial — todo al final. Cada cache hit ahorra tokens y latencia.
2. Instrucciones en negativo (anti-patterns)
En lugar de decir "escribe código limpio", di "no añadas abstracciones innecesarias, no crees helpers para operaciones puntuales". Los LLMs responden mejor a prohibiciones concretas que a aspiraciones vagas.
3. Taxonomía de riesgo explícita
Si tu agente ejecuta acciones en el mundo real, no le pidas que "sea cuidadoso". Dale una tabla: LOW = ejecutar libre, MEDIUM = precaución, HIGH = confirmar. Categorías concretas eliminan la ambigüedad.
4. Naming como documentación
DANGEROUS_uncachedSystemPromptSection grita "no uses esto a la ligera". Los nombres de funciones son la primera línea de documentación — hazlos intencionales.
5. Feature flags en el prompt
Claude Code no tiene un prompt monolítico — tiene secciones condicionales controladas por flags. Esto permite A/B testing de instrucciones, rollbacks rápidos, y adaptación por contexto sin reescribir el prompt completo.
Un Prompt es un Sistema
El system prompt de Claude Code no es un texto largo pegado al principio de cada conversación. Es un sistema de ensamblaje con 18 secciones, cada una con su propósito, su gate condicional, su estrategia de caching, y su razón de existir.
La diferencia entre un "prompt" y un "sistema de prompts" es la misma que entre un script de bash y una aplicación. Escala, mantenibilidad, y la capacidad de evolucionar sin romper todo.
En el próximo artículo de esta serie, exploraremos el sistema de compresión de contexto — cómo Claude Code gestiona conversaciones que exceden la ventana de contexto sin perder ninguna instrucción del usuario. Cuatro niveles de compresión, presupuestos de tokens, y circuitos de emergencia.
📚 Serie Anatomía de Claude Code: Este es el artículo 1 de 6. Los siguientes cubren compresión de contexto, sistemas de memoria, features ocultas, sistema de herramientas y permisos, y el build dual (interno vs público).
¿Construyes agentes con LLMs?
En Cadences diseñamos agentes con los mismos patrones industriales que hemos descubierto en Claude Code. Si quieres aplicar estos principios a tu negocio, hablemos.
Gonzalo Monzón
Fundador de CadencesLab. Ingeniero de software, arquitecto de sistemas multi-agente y eterno estudiante de cómo piensan las máquinas. Esta serie nace de meses de reverse engineering sobre las herramientas que usamos a diario.