Código fuente de Claude Code filtrado: análisis completo por dentro

31 de marzo, 2026 Por Alessio Romano
Código fuente de Claude Code filtrado: análisis completo por dentro

El código fuente completo de Claude Code estaba expuesto en npm. 4.756 archivos TypeScript originales metidos en un source map que cualquiera podía descargar. Lo he extraído, lo he analizado entero, y aquí te cuento cómo funciona por dentro el agente de IA más usado del momento.

Hoy me he despertado, he abierto LinkedIn y me he encontrado con que el código fuente completo de Claude Code estaba expuesto en npm. Así, sin más. 4.756 archivos TypeScript originales metidos en un source map que cualquiera podía descargar.

No ha sido un hackeo ni nada por el estilo. Alguien en Anthropic publicó el paquete npm con el archivo .map incluido y ese archivo contenía absolutamente todo: 4.756 archivos fuente, sin ofuscar, sin minificar. El código tal cual lo escribieron los ingenieros de Anthropic.

El primero en darse cuenta fue Chaofan Shou, investigador de seguridad, que lo publicó en redes. En cuestión de horas ya había repositorios en GitHub replicando el código para análisis e investigación.

Yo, como llevo meses trabajando con agentes de IA y Claude Code es mi herramienta principal de desarrollo, hice lo que tenía que hacer: me descargué todo y me lo leí.

Y la verdad es que lo que he encontrado es una pasada.

Qué vas a encontrar aquí

Voy a intentar explicar cómo funciona Claude Code por dentro de la forma más clara posible. No voy a publicar bloques de código propietario (el código es de Anthropic, todos los derechos reservados), pero sí voy a destripar la arquitectura, las decisiones de diseño y los patrones que hacen que este bicho funcione como funciona.

Esto es lo que vamos a ver:

  • La estructura general. 1.902 archivos de código propio organizados en módulos. Qué hace cada parte y cómo encaja todo.
  • El sistema de tools. Más de 40 herramientas (BashTool, FileEditTool, AgentTool, WebSearchTool...) cada una con su propio esquema, permisos y lógica de ejecución.
  • Los prompts del sistema. El archivo de 914 líneas que define cómo se comporta Claude Code.
  • El sistema de memoria. Cómo recuerda cosas entre sesiones, el famoso CLAUDE.md y la memoria automática.
  • Permisos y seguridad. Cómo decide qué puede y qué no puede tocar en tu sistema.
  • Agentes y subtareas. Cómo lanza sub-agentes para tareas paralelas y cómo orquesta trabajo complejo.
  • Features ocultas. Flags como VOICE_MODE, PROACTIVE, KAIROS o AGENT_TRIGGERS que revelan cosas en las que Anthropic está trabajando.
  • Lecciones para developers. Patrones de diseño que puedes aplicar si estás construyendo tu propio agente de IA.

Sobre la legalidad de esto

Antes de que nadie se ponga nervioso: no estoy distribuyendo código ni recomendando que nadie lo use para nada comercial. El código es de Anthropic con licencia "All rights reserved".

Lo que sí puedo hacer (y lo que hacen investigadores de seguridad y periodistas tech constantemente) es analizar cómo funciona un software y explicarlo. El source map estaba dentro de un paquete npm público, accesible con un simple npm pack. Nadie vulneró ningún sistema.

Cómo se extrajo el código

Para los técnicos, el proceso fue absurdamente simple:

npm pack @anthropic-ai/claude-code
tar -xzf anthropic-ai-claude-code-*.tgz

Dentro del paquete: un cli.js.map de 59.8 MB. Es un source map estándar con la propiedad sourcesContent poblada, lo que significa que cada archivo TypeScript original está embebido en el JSON. Con un script de 15 líneas en Node extraes el árbol de archivos completo.

Resultado: 1.902 archivos de código fuente propio, 31 MB de TypeScript puro, sin contar dependencias externas. Todo perfectamente organizado y legible.

Ahora sí, vamos al grano.

1. Qué estamos viendo exactamente

El código fuente de Claude Code son 1.902 archivos de TypeScript/TSX dentro de la carpeta src/. Es una aplicación CLI construida con TypeScript + React + Ink (sí, React renderizando en la terminal) que corre sobre Bun como runtime.

No es un wrapper fino sobre la API de Anthropic. Es un sistema completo de agente autónomo con su propio motor de rendering, sistema de permisos de 5 capas, más de 40 herramientas integradas, y un loop agéntico con streaming anticipado.

2. El arranque: de cli.tsx a la primera respuesta

Cuando ejecutas claude en tu terminal, el flujo pasa por dos archivos principales:

entrypoints/cli.tsx es el bootstrap rápido. Parsea flags como --version o --dump-system-prompt, detecta si hay que lanzar un daemon worker, y si nada de eso aplica, cede el control al archivo pesado.

main.tsx es el orquestador principal. Con más de 135 imports, este archivo carga todo lo necesario para arrancar una sesión:

  • Inicializa telemetría y profiling de startup
  • Carga configuración desde múltiples fuentes (settings de usuario, MDM empresarial, OAuth, keychain)
  • Descubre y carga plugins y skills
  • Resuelve qué modelo usar y decide si correr en modo interactivo (REPL) o headless (SDK/piped)

Un detalle interesante: usa lazy imports estratégicos para romper dependencias circulares y feature flags de compilación via bun:bundle para eliminar código muerto en el bundle final. Esto significa que el Claude Code que usas tú puede ser un bundle completamente diferente al que usan internamente en Anthropic.

3. El Agentic Loop: el corazón de todo

Si tuvieras que entender una sola cosa de Claude Code, es esto. Todo agente de IA funciona con un loop, y el de Claude Code vive en dos archivos: QueryEngine.ts (el orquestador) y query.ts (la ejecución).

Cómo funciona el ciclo

El concepto es simple: Claude recibe tu mensaje, decide si necesita usar una herramienta para responder, la usa, recibe el resultado, y decide otra vez. Repite hasta que tiene una respuesta final.

Pero la implementación tiene varios trucos que lo hacen funcionar a escala:

Streaming con ejecución anticipada. Claude Code no espera a que el modelo termine de generar toda su respuesta. Tiene un componente llamado StreamingToolExecutor que monitorea el stream de tokens en tiempo real. En cuanto detecta un bloque tool_use completo, lo ejecuta inmediatamente mientras el modelo sigue generando.

Orquestación de tools en paralelo. Si un tool se declara como seguro para concurrencia y es de solo lectura, puede correr en paralelo con otros tools similares. La concurrencia máxima se controla con una variable de entorno (default: 10).

Auto-compactación del historial. Cuando la conversación se acerca al límite del contexto, el sistema compacta automáticamente los mensajes antiguos. Reserva tokens para el resumen, mantiene un buffer de seguridad, y tiene un circuit breaker que se activa después de 3 fallos consecutivos para no quedarse en un loop infinito.

Token budget por turno. Cada turno tiene un presupuesto de tokens estricto. El sistema contabiliza tokens de entrada, salida y de cache. Si el modelo necesita más espacio, puede escalar automáticamente hasta un máximo configurado.

Stop hooks. Después de cada respuesta del modelo, se ejecutan hooks que determinan si la conversación debe continuar o terminar. Pueden ejecutar validaciones de seguridad, verificar límites de budget o disparar hooks personalizados.

Retry con backoff. Las llamadas a la API tienen reintentos automáticos con categorización de errores. Si la API devuelve "prompt too long", el sistema compacta y reintenta en vez de fallar.

4. El sistema de Tools: cómo el agente actúa en el mundo

Los tools son la interfaz entre Claude y tu sistema. Sin tools, Claude es un chatbot. Con tools, es un agente.

La interfaz Tool

Cada tool en Claude Code implementa una interfaz con métodos bien definidos para ejecutar, validar inputs, verificar permisos, indicar si es de solo lectura o destructivo, si puede correr en paralelo, y las instrucciones que Claude recibe sobre cómo usarlo. Además, cada tool tiene métodos de rendering para la UI: saben cómo dibujarse en la terminal.

El patrón buildTool: factory con defaults seguros

Todos los tools se crean con una función buildTool() que aplica defaults fail-closed. Esto significa que si alguien crea un tool nuevo y olvida definir los campos de seguridad, el sistema asume el peor caso: no puede correr en paralelo y requiere permisos de escritura. Un tool nuevo sin configurar es un tool restringido por defecto. Patrón de seguridad elegante.

El registro de tools

El archivo tools.ts tiene la función que retorna la lista completa de tools disponibles. Los hay de tres tipos:

Siempre disponibles: BashTool, FileReadTool, FileEditTool, FileWriteTool, GlobTool, GrepTool, WebFetchTool, WebSearchTool, AgentTool, SkillTool, AskUserQuestionTool, NotebookEditTool, TodoWriteTool, EnterPlanModeTool, SendMessageTool, BriefTool y algunos más.

Condicionales por feature flag: SleepTool (requiere PROACTIVE o KAIROS), CronTools (requiere AGENT_TRIGGERS), RemoteTriggerTool, WorkflowTool, WebBrowserTool, MonitorTool, SnipTool, etc.

Condicionales por entorno: REPLTool, ConfigTool y TungstenTool solo se cargan cuando el usuario es interno de Anthropic (USER_TYPE === 'ant'). LSPTool requiere un flag específico. PowerShellTool se carga solo cuando es aplicable.

assembleToolPool: la única fuente de verdad

Cuando Claude necesita saber qué tools tiene disponibles, la función que los ensambla hace algo inteligente con el orden: los built-in van primero y ordenados alfabéticamente para maximizar cache hits en la API de Anthropic. Si los tools cambian de orden entre requests, el cache se invalida. Una sola herramienta MCP intercalada entre built-ins rompería todo el cache downstream.

ToolSearch: lazy loading de tools

Cuando hay muchos tools (especialmente con varios servidores MCP), enviarlos todos en cada request es costoso en tokens. El sistema resuelve esto con carga lazy: los tools marcados como diferibles no envían su schema completo al modelo. Claude puede usar ToolSearch con un query y el sistema le devuelve los schemas completos de los tools que matchean.

5. Seguridad del BashTool: paranoia justificada

El BashTool merece su propia sección. Es el tool más poderoso (ejecuta comandos arbitrarios en tu shell) y el más peligroso. Por eso tiene más de 200KB de código de seguridad repartidos en tres archivos.

Clasificación de comandos

Antes de cualquier validación, el BashTool clasifica los comandos en categorías: búsqueda (find, grep, rg...), lectura (cat, head, tail...), listado (ls, tree, du), neutrales (echo, printf, true, false), y silenciosos (mv, cp, rm, mkdir...). Esta clasificación afecta cómo se muestra el progreso en la UI y si el tool se considera de solo lectura para efectos de concurrencia.

23 validadores de seguridad

El archivo bashSecurity.ts implementa 23 funciones de validación. Cada una detecta un vector de ataque diferente:

Ataques de inyección: sustituciones de comandos ($(), backticks), redirecciones peligrosas, tokens malformados, inyección via IFS, sustituciones en git commit hashes.

Ofuscación: caracteres Unicode que parecen ASCII, caracteres de control invisibles, espacios Unicode que parecen espacios normales, backslash-escaped whitespace, comentarios # a mitad de palabra, desincronización entre comillas y comentarios.

Escape de shell: metacaracteres especiales, variables peligrosas (IFS, PATH, LD_PRELOAD...), saltos de línea embebidos, expansión de llaves, comandos zsh peligrosos, operadores escapados, acceso a /proc/self/environ.

Comandos zsh bloqueados

El sistema tiene una blocklist específica para zsh porque ciertos comandos nativos pueden usarse para escapar del sandbox: zmodload (carga módulos arbitrarios), emulate (equivalente a eval), sysopen/sysread/syswrite (acceso directo a file descriptors), zpty (pseudo-terminal invisible), ztcp/zsocket (red, exfiltración de datos), y los zf_* (operaciones de archivo).

El sandbox

El sandbox decide si un comando debe ejecutarse en un entorno aislado. Para usuarios internos de Anthropic, usa GrowthBook (su sistema de feature flags) para mantener una lista actualizada de comandos excluidos. Un comentario interesante en el código: los comandos excluidos del sandbox son una "comodidad de UX, no una frontera de seguridad". La seguridad real es el sistema de permisos que pregunta al usuario.

Timing

Si un comando tarda más de 2 segundos, se muestra progreso. Si tarda más de 15 segundos en el agente principal, se manda a background automáticamente.

6. El System Prompt: donde vive la personalidad del agente

El system prompt de Claude Code se construye dinámicamente y es probablemente la parte más interesante para cualquiera que esté construyendo agentes.

La frontera de cache

El prompt tiene un marcador crítico: __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__

Todo lo que está ANTES de esta frontera es igual para todos los usuarios y se cachea agresivamente en la API de Anthropic. Todo lo que está DESPUÉS es específico de la sesión y no se cachea.

Esto es ingenioso a nivel de costos: la parte estática del prompt se cachea una vez y se reutiliza en millones de requests. Solo la parte dinámica se procesa por request.

Secciones del prompt

Parte cacheable (global):

  • Definición del rol (el modelo se inyecta dinámicamente)
  • Reglas de ejecución: cómo usar tools, cómo comunicarse con el usuario, cómo manejar la compresión
  • Guía de ingeniería de software: no agregues features no pedidas, lee antes de modificar, no abstraigas prematuramente
  • Evaluación de riesgo y reversibilidad de acciones

Parte dinámica (por sesión):

  • Instrucciones específicas de los tools activos
  • Instrucciones de servidores MCP conectados
  • Localización de idioma
  • Estilos de output personalizados y overrides internos de Anthropic

Meta-cognición en el prompt

Lo más interesante del system prompt no es lo técnico, es lo cognitivo. El prompt incluye heurísticas de decisión que guían el comportamiento del agente:

  • " Si un enfoque falla, diagnostica POR QUÉ antes de cambiar de táctica
  • " No reintentes la misma acción ciegamente, pero tampoco abandones un enfoque viable después de un solo fallo
  • " Si puedes decirlo en una oración, no uses tres
  • " 3 líneas similares de código son mejor que una abstracción prematura
  • " Mide dos veces, corta una vez

Esto es un patrón clave para construir agentes: el prompt debe incluir heurísticas de decisión, no solo instrucciones. Le estás enseñando al modelo CÓMO pensar sobre problemas, no solo QUÉ hacer.

7. Skills: el sistema de plugins en Markdown

Las skills son comandos reutilizables que extienden Claude Code. Lo interesante es que se definen en archivos Markdown con YAML frontmatter, un formato accesible que no requiere saber programar.

Cómo funciona la carga

El sistema escanea directorios en orden de precedencia: políticas de la organización, settings de usuario, configuración del proyecto, skills managed, built-in, MCP, y plugins. La deduplicación resuelve symlinks a rutas canónicas para evitar que la misma skill se cargue dos veces desde diferentes paths.

Formato del frontmatter

Los campos principales: nombre, descripción (que Claude lee para saber cuándo usarla), trigger de invocación automática, lista de tools permitidos, rutas de archivos, override del modelo, nivel de esfuerzo, hooks basados en eventos, y un flag para desactivar la invocación automática por el modelo. El sistema incluso estima tokens del frontmatter para contabilizar el costo de cada skill en el contexto.

Skills built-in

Claude Code viene con skills integradas para debugging, ejecución recurrente en intervalos, procesamiento en lote, simplificación de código, ayuda con la API de Claude, programación de agentes remotos, gestión de configuración, verificación de resultados, y más.

8. MCP: el protocolo universal de herramientas

MCP (Model Context Protocol) es el estándar para conectar herramientas externas a agentes de IA. Claude Code tiene una implementación completa.

Transportes soportados

Claude Code soporta 7 tipos de transporte: stdio (proceso local via stdin/stdout, el más común), SSE, SSE específico para IDEs, HTTP streamable, WebSocket, embebido en el SDK, y proxy a través de Claude.ai.

Configuración

Los servidores MCP se definen en archivos JSON con esta precedencia: managed > enterprise > project > user > local. Las rutas principales son ~/.claude/mcp-servers.json (usuario) y .claude/.mcp.json (proyecto). El sistema soporta expansión de variables de entorno con un allowlist selectivo para que puedas poner API keys sin riesgo de filtrar variables sensibles.

Integración

Los tools MCP se normalizan con un prefijo de servidor (ej: mcp__mi-servidor__mi-tool) y se tratan como tools normales. Pasan por el mismo sistema de permisos y presupuesto de tokens. En caso de conflicto de nombre, los built-in siempre ganan.

Un dato curioso: el timeout default para llamadas a tools MCP es de ~27.8 horas. Bastante generoso.

9. Sub-Agentes: agentes que lanzan agentes

El AgentTool permite a Claude Code lanzar sub-agentes especializados para delegación de tareas. Es lo que habilita el paralelismo y la especialización.

Tipos de agentes

Built-in: vienen integrados (Explore, Plan, general-purpose, etc.) con prompts generados dinámicamente.

Custom: definidos por el usuario en .claude/agents/ como archivos Markdown con frontmatter YAML. Soportan: nombre, descripción, lista de tools permitidos/denegados, override del modelo, nivel de esfuerzo, modo de permisos, máximo de turnos, scope de memoria, y servidores MCP requeridos.

Plugin: provistos por plugins instalados.

Modos de ejecución

Síncrono: el agente padre espera el resultado.

Background: el sub-agente corre independientemente. El padre continúa trabajando y recibe notificación cuando termina.

Worktree: crea un git worktree aislado. El sub-agente trabaja en una copia independiente del repositorio, los cambios quedan en un branch separado. Perfecto para tareas que podrían interferir con el trabajo del agente principal.

Forking: un sub-agente forkeado comparte el cache de lectura de archivos del padre, comparte el system prompt renderizado (para reusar el cache de la API), tiene su propio contexto de permisos, y puede comunicarse con otros agentes via SendMessageTool.

10. Hooks: automatización basada en eventos

Los hooks permiten ejecutar acciones automáticas cuando ocurren eventos específicos.

Tipos de hooks

Command Hook: ejecuta un comando shell, con timeout, ejecución async, y condiciones de filtrado.

Prompt Hook: ejecuta un prompt LLM con soporte para variables.

HTTP Hook: hace una petición POST a un endpoint, con headers y expansión segura de variables de entorno.

Agent Hook: lanza un agente de verificación con su propio prompt y modelo.

Eventos y condiciones

Los hooks se disparan en eventos como before_tool_call y after_tool_call, con matchers que filtran por tool. Las condiciones usan un mini-lenguaje de patrones:

Bash(git *)        → solo para comandos git
Read(*.ts)         → solo para archivos TypeScript
Write(src/**)      → solo para archivos en src/

11. React en la terminal

Claude Code renderiza su UI con un fork customizado de Ink, una librería que usa React para interfaces de terminal.

Implementa un React Reconciler propio, usa Yoga (el mismo motor de layout CSS Flexbox de React Native), output ANSI con colores y hyperlinks, diffing optimizado para minimizar re-renders, y focus management completo.

Hay más de 380 componentes React en la carpeta components/. Cada tool también sabe cómo renderizarse, lo que hace que añadir un tool nuevo sea autocontenido: define su lógica Y su UI en el mismo módulo.

12. Permisos: 5 capas de defensa

El sistema de permisos es lo que hace que Claude Code sea utilizable en producción sin miedo.

Capa 1 — Deny rules: antes de que Claude siquiera vea un tool, se filtran los que están en deny rules. Si hay un deny rule general, el tool ni aparece en el prompt. El modelo nunca sabe que existe.

Capa 2 — Validación de input: validación del schema con Zod y reglas específicas del tool. Rechaza inputs malformados antes de verificar permisos.

Capa 3 — Permisos del tool: lógica de permisos específica. Por ejemplo, el BashTool verifica path constraints y clasificación de seguridad del comando.

Capa 4 — Permission Rules: reglas configurables por el usuario: siempre permitir (ej: Bash(git status)), siempre denegar (ej: Bash(rm -rf *)), o siempre preguntar.

Capa 5 — Hook checkpoint: orquesta la decisión final, integra con el clasificador ML cuando está habilitado, y maneja la UI de confirmación al usuario.

Denial tracking

El sistema rastrea denegaciones consecutivas. Después de un umbral, cambia su estrategia para evitar loops infinitos donde el modelo sigue pidiendo permiso y el usuario sigue denegando.

Modos

  • default: pregunta al usuario para operaciones sensibles
  • auto: permite automáticamente usando un clasificador ML
  • bypass: permite todo (solo para desarrollo)

13. Features ocultas: qué está preparando Anthropic

Los feature flags revelan funcionalidades en desarrollo:

  • VOICE_MODE: modo de voz, interacción hablada con el agente
  • PROACTIVE / KAIROS: modo autónomo donde Claude actúa sin esperar instrucciones
  • AGENT_TRIGGERS: triggers automáticos con cron jobs para agentes
  • BRIDGE_MODE: integración bidireccional con IDEs
  • COORDINATOR_MODE: modo de coordinación de múltiples agentes
  • WEB_BROWSER_TOOL: navegador web integrado

Estas features están en el código pero se eliminan en compilación con bun:bundle para los builds públicos. Si el flag está desactivado, el código ni siquiera existe en el bundle que descargas.

Qué aprendemos de todo esto

Después de analizar los 1.902 archivos de código fuente, estas son las diferencias reales entre un demo de agente y un agente de producción:

El loop no es un while loop simple. Es un sistema con streaming anticipado, ejecución paralela de tools, auto-compactación, token budgeting, retry con backoff, y stop hooks.

La seguridad no es un if/else. Son 5 capas de permisos, 23 validadores solo para bash, clasificación de comandos, sandbox configurable, y denial tracking.

El prompt no es un string. Es un sistema de secciones cacheables con frontera dinámica, contexto memoizado, meta-cognición, y estimación de tokens por skill.

Los tools no son funciones. Son objetos con ciclo de vida completo: validación, permisos, ejecución, progress reporting, rendering, y presupuesto de resultado.

La extensibilidad no es un plugin system. Es una combinación de skills en Markdown, agentes custom, hooks basados en eventos, MCP para herramientas externas, y feature flags para dead code elimination.

La lección más importante: la complejidad de un agente de producción no está en el loop, está en todo lo que rodea al loop.

Este análisis está basado en el código fuente real de Claude Code v2.1.88. Todos los nombres de archivos, funciones, constantes y patrones mencionados son verificables en el source code extraído del source map publicado en npm.