Claude Code MODO DIOS

No es un tutorial de comanditos. Es entender como funciona Claude por dentro, codear tus propios Skills y MCPs, y dominar debugging en ArtisDoc como un profesional.

🧠 Como Piensa Claude

El Loop Principal

Claude Code no es magia. Es un loop que se repite hasta completar tu tarea:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CLAUDE CODE LOOP β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ INPUT │───▢│ THINK │───▢│ ACT │───▢│ OBSERVE β”‚ β”‚ β”‚ β”‚ (tu msg) β”‚ β”‚ (razona) β”‚ β”‚ (tools) β”‚ β”‚(resultado)β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ COMPLETE?│──── NO ────▢ vuelve a THINK β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ SI β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ RESPOND β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
🧠 Por que importa esto?

Cuando entendes el loop, podes guiar a Claude mejor. Si le das contexto claro en el INPUT, el THINK es mas preciso, el ACT usa las tools correctas, y llegas al resultado mas rapido.

Las Tools son sus Manos

Claude sin tools es solo texto. Con tools puede:

Tool Que hace Permiso?
Read Lee archivos del disco NO necesita
Glob Busca archivos por patron (*.java) NO necesita
Grep Busca texto dentro de archivos NO necesita
Edit Modifica archivos existentes SI necesita
Write Crea archivos nuevos SI necesita
Bash Ejecuta comandos en terminal SI necesita
Task Lanza sub-agentes para tareas complejas NO necesita
πŸ”₯ Pro tip para ArtisDoc

En vez de decir "busca el servicio de documentos", decile:
"busca DocumentService en backend/src usando Grep"
Asi le das pistas de QUE tool usar y DONDE buscar.

πŸ—οΈ Arquitectura de Claude Code

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CLAUDE CODE ARCHITECTURE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ TU INPUT │────▢│ CONTEXT BUILDER β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚CLAUDE.mdβ”‚ β”‚ Skills β”‚ β”‚ Hooks β”‚ β”‚ MCPs β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ CLAUDE API (Anthropic) β”‚ β”‚ β”‚ β”‚ (Sonnet 4 / Opus 4 / Haiku) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ TOOL EXECUTOR β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ Read β”‚ β”‚ Glob β”‚ β”‚ Grep β”‚ β”‚ Edit β”‚ β”‚Write β”‚ β”‚ Bash β”‚ β”‚ MCP β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β–Ό β–Ό β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚FILESYSTEMβ”‚ β”‚ TERMINAL β”‚ β”‚ MCP SERVERS β”‚ β”‚ β”‚ β”‚ (tu repo)β”‚ β”‚ (comandos) β”‚ β”‚ (externos) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Context Builder: La Clave

Antes de cada request a la API, Claude Code arma un "contexto" con:

  • CLAUDE.md - Instrucciones del proyecto (si existe)
  • Skills activos - Segun tu mensaje, activa skills relevantes
  • Hooks - Reglas que se ejecutan antes/despues de tools
  • MCP Tools - Tools adicionales de servidores externos
  • Historial - Mensajes anteriores de la conversacion
⚠️ Limite de Contexto

Claude tiene un limite de tokens (~200k). Si el contexto es muy grande, cosas viejas se "olvidan". Por eso es importante ser conciso y no llenar la conversacion de texto innecesario.

⚑ Skills: Que Son

Un Skill es un "Modo Experto"

Cuando activas un skill, Claude recibe instrucciones adicionales especificas para ese dominio. Es como darle un manual de experto antes de que empiece a trabajar.

❌ Sin Skill

Claude: "Voy a crear un servicio generico..."

No conoce tus patrones, hace lo que le parece

βœ… Con Skill de ArtisDoc

Claude: "Siguiendo el patron Controller→Transformer→Service→Repository..."

Conoce tu arquitectura, respeta convenciones

Como se Activan?

Hay dos formas:

Claude lee la description del skill y si tu mensaje matchea, lo activa solo:

.claude/skills/spring-patterns/SKILL.md
description: "Usa cuando necesites crear Controllers, Services o Repositories en el backend de ArtisDoc"

Si decis "crea un endpoint para listar documentos", Claude detecta que necesita el skill y lo carga.

Podes invocar un skill directamente con slash command:

Terminal
# Invocar skill manualmente /spring-patterns crear endpoint GET /api/documents

πŸ”¬ Anatomia de un Skill

Estructura de SKILL.md

Todo skill vive en .claude/skills/NOMBRE/SKILL.md

.claude/skills/mi-skill/SKILL.md Markdown + YAML frontmatter
--- name: mi-skill # Identificador unico description: "Cuando usar este skill" # CRITICO: Claude usa esto para activar allowed-tools: Read, Grep, Edit # Tools que puede usar (whitelist) --- # Titulo del Skill Todo lo que escribas aca se inyecta en el contexto de Claude cuando el skill esta activo. ## Patrones Documenta patrones, ejemplos, reglas... ## Ejemplos ```java // Codigo de ejemplo que Claude va a seguir ```
🧠 Entendiendo allowed-tools

allowed-tools es una whitelist. Solo las tools listadas pueden usarse cuando el skill esta activo. Esto es por seguridad:

  • Read, Grep, Glob - Solo lectura, safe
  • Edit, Write - Puede modificar archivos
  • Bash(docker:*) - Solo comandos docker
  • Bash(npm:*) - Solo comandos npm

El Poder de la Description

La description es lo MAS importante. Claude la lee para decidir si activar el skill.

❌ Mala description
description: "Skill para el backend"

Muy vaga, se activa para cualquier cosa

βœ… Buena description
description: | "Usa cuando necesites crear, modificar o debuggear Controllers, Services, Repositories o Transformers en el backend Spring de ArtisDoc. Incluye patrones de arquitectura hexagonal."

Especifica, Claude sabe exactamente cuando usarlo

πŸ’» Codear tu Propio Skill

Vamos a crear un skill real para ArtisDoc: Debugging de Performance

Crear la estructura

Bash
mkdir -p .claude/skills/performance-debug touch .claude/skills/performance-debug/SKILL.md

Definir el frontmatter

.claude/skills/performance-debug/SKILL.md
--- name: performance-debug description: | "Usa para diagnosticar problemas de performance: - queries lentas - memory leaks - endpoints que tardan - problemas de N+1 - optimizacion de Elasticsearch" allowed-tools: Read, Grep, Glob, Bash(docker exec:*), Bash(curl:*), Bash(psql:*) ---

Documentar los patrones de diagnostico

.claude/skills/performance-debug/SKILL.md (continuacion)
# Performance Debugging - ArtisDoc ## Checklist de Diagnostico ### 1. Queries Lentas (PostgreSQL) ```sql -- Ver queries activas SELECT pid, now() - pg_stat_activity.query_start AS duration, query FROM pg_stat_activity WHERE state = 'active' AND query_start < now() - interval '5 seconds'; -- Habilitar logging de queries lentas ALTER SYSTEM SET log_min_duration_statement = 1000; -- 1 segundo SELECT pg_reload_conf(); ``` ### 2. Detectar N+1 en Hibernate Buscar en logs: ```bash grep -E "select.*from.*where.*id.*=" backend/backend.log | wc -l ``` Si hay muchos selects similares seguidos = N+1 ### 3. Memory del JVM ```bash # Ver heap usage docker exec artisdocv2_backend_1 jstat -gc $(pgrep java) 1000 5 ``` ### 4. Endpoints Lentos Usar actuator (si esta habilitado): ```bash curl http://localhost:8080/actuator/metrics/http.server.requests ``` ## Patrones Comunes en ArtisDoc | Sintoma | Causa Probable | Solucion | |---------|---------------|----------| | GET /documents lento | N+1 en pages | Agregar @EntityGraph | | Busqueda lenta | ES sin indice | Verificar mappings | | Upload timeout | Mongo GridFS | Chunked upload | | Login lento | LDAP timeout | Cache de auth |

Probarlo

Ahora cuando digas algo como:

Tu mensaje a Claude
"el endpoint de documentos tarda 10 segundos, ayudame a debuggear"

Claude va a activar el skill y seguir los patrones de diagnostico que definiste.

βœ… Skill Creado!

El skill ya esta listo. Claude lo va a detectar automaticamente cuando hables de performance, queries lentas, memory, etc.

🎯 Patrones Avanzados de Skills

Skill con Templates de Codigo

Podes incluir templates que Claude va a copiar/adaptar:

.claude/skills/spring-patterns/SKILL.md
## Template: Nuevo Endpoint CRUD ### Controller ```java @RestController @RequestMapping("/api/v1/{entities}") @RequiredArgsConstructor public class {Entity}Controller { private final {Entity}Service service; private final {Entity}Transformer transformer; @GetMapping public ResponseEntity<List<{Entity}DTO>> list() { return ResponseEntity.ok( transformer.toDTOList(service.findAll()) ); } @GetMapping("/{id}") public ResponseEntity<{Entity}DTO> getById(@PathVariable Long id) { return service.findById(id) .map(transformer::toDTO) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @PostMapping public ResponseEntity<{Entity}DTO> create(@Valid @RequestBody {Entity}CreateDTO dto) { {Entity} entity = transformer.toEntity(dto); {Entity} saved = service.save(entity); return ResponseEntity.status(HttpStatus.CREATED) .body(transformer.toDTO(saved)); } } ``` IMPORTANTE: Reemplazar {Entity} y {entities} con el nombre real. Ejemplo: Document/documents, User/users

Skill con Reglas de Negocio

Documenta reglas que Claude debe respetar:

.claude/skills/artisdoc-rules/SKILL.md
## Reglas de Negocio - ArtisDoc ### Documentos 1. Un documento SIEMPRE debe tener un usuario owner 2. El estado inicial es DRAFT, nunca APPROVED 3. Solo usuarios con rol APPROVER pueden cambiar a APPROVED 4. Documentos con status APPROVED no se pueden eliminar (soft delete) ### Permisos 1. Herencia: Usuario hereda permisos de sus grupos 2. Denegacion explicita: DENY > ALLOW 3. Admin bypasea todo excepto documentos LOCKED ### OCR 1. Solo procesar PDFs y imagenes (png, jpg, tiff) 2. Tamano maximo: 50MB por archivo 3. Si OCR falla 3 veces, marcar como FAILED y notificar CLAUDE: Siempre verificar estas reglas antes de implementar logica de negocio
πŸ”₯ Pro tip: Skills Compuestos

Podes tener un skill que referencie otros skills. Por ejemplo, un skill "feature-completa" que incluya patrones de backend, frontend y tests.

πŸ”Œ MCP: Model Context Protocol

Que Problema Resuelve?

Claude por defecto solo puede leer archivos locales. Pero que pasa si necesitas que consulte tu base de datos? O tu Jira? O Slack?

MCP es un protocolo que permite conectar Claude con servicios externos a traves de "servidores MCP" que exponen tools adicionales.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ MCP ARCHITECTURE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ CLAUDE CODE │◄────────────────────▢│ MCP SERVER (proceso) β”‚ β”‚ β”‚ β”‚ (client) β”‚ JSON-RPC stdio β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ Tools expuestas β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - query_database β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - list_tables β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - run_migration β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ PostgreSQL / Mongo β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ / Jira / Slack / β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ cualquier servicio β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Como se Configura?

En el archivo .mcp.json en la raiz del proyecto:

.mcp.json JSON
{ "mcpServers": { "artis-db": { "type": "stdio", "command": "npx", "args": ["-y", "@bytebase/dbhub", "--dsn", "${ARTIS_DB_DSN}"], "description": "PostgreSQL de ArtisDoc" } } }

Cuando Claude Code inicia, levanta el proceso npx @bytebase/dbhub y se comunica via stdin/stdout.

πŸ“‘ El Protocolo MCP

JSON-RPC sobre stdio

MCP usa JSON-RPC 2.0. Los mensajes van por stdin/stdout del proceso:

JSON-RPC Request (Claude β†’ Server)
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "query_database", "arguments": { "sql": "SELECT * FROM documents LIMIT 10" } } }
JSON-RPC Response (Server β†’ Claude)
{ "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "| id | title | status |\n|---|---|---|\n| 1 | Factura | APPROVED |" } ] } }

Lifecycle de un MCP Server

initialize
β†’
tools/list
β†’
tools/call
β†’
... (repeat)
Metodo Quien llama Que hace
initialize Claude Handshake inicial, intercambia capacidades
tools/list Claude Pide lista de tools disponibles
tools/call Claude Ejecuta una tool especifica
resources/list Claude Lista recursos estaticos (opcional)

πŸ› οΈ Codear tu MCP Server

Vamos a crear un MCP server simple para ArtisDoc que consulte el estado del sistema:

Setup del proyecto

Bash
mkdir artis-mcp-server && cd artis-mcp-server npm init -y npm install @modelcontextprotocol/sdk

Crear el servidor

index.js JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; // Crear servidor MCP const server = new Server( { name: 'artis-status', version: '1.0.0' }, { capabilities: { tools: {} } } ); // Definir las tools disponibles server.setRequestHandler('tools/list', async () => ({ tools: [ { name: 'check_services', description: 'Verifica el estado de los servicios de ArtisDoc (backend, mongo, postgres, rabbit)', inputSchema: { type: 'object', properties: {} } }, { name: 'check_queues', description: 'Muestra el estado de las colas de RabbitMQ', inputSchema: { type: 'object', properties: {} } }, { name: 'recent_errors', description: 'Obtiene los ultimos errores del log del backend', inputSchema: { type: 'object', properties: { lines: { type: 'number', description: 'Cantidad de lineas (default 50)' } } } } ] })); // Implementar cada tool server.setRequestHandler('tools/call', async (request) => { const { name, arguments: args } = request.params; switch (name) { case 'check_services': return await checkServices(); case 'check_queues': return await checkQueues(); case 'recent_errors': return await recentErrors(args.lines || 50); default: throw new Error(`Tool not found: ${name}`); } }); // Implementaciones import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); async function checkServices() { const services = ['postgres', 'mongo', 'backend', 'rabbitmq']; const results = []; for (const svc of services) { try { const { stdout } = await execAsync( `docker ps --filter "name=${svc}" --format "{{.Status}}"` ); results.push(`${svc}: ${stdout.trim() || 'NOT RUNNING'}`); } catch (e) { results.push(`${svc}: ERROR - ${e.message}`); } } return { content: [{ type: 'text', text: results.join('\n') }] }; } async function checkQueues() { try { const { stdout } = await execAsync( 'curl -s -u guest:guest http://localhost:15672/api/queues | jq ".[] | {name, messages, consumers}"' ); return { content: [{ type: 'text', text: stdout || 'No queues found' }] }; } catch (e) { return { content: [{ type: 'text', text: `Error: ${e.message}` }] }; } } async function recentErrors(lines) { try { const { stdout } = await execAsync( `grep -i "error\\|exception" backend/backend.log | tail -${lines}` ); return { content: [{ type: 'text', text: stdout || 'No errors found' }] }; } catch (e) { return { content: [{ type: 'text', text: `Error: ${e.message}` }] }; } } // Iniciar servidor const transport = new StdioServerTransport(); await server.connect(transport);

Registrarlo en .mcp.json

.mcp.json
{ "mcpServers": { "artis-status": { "type": "stdio", "command": "node", "args": ["./artis-mcp-server/index.js"], "description": "Estado y diagnostico de ArtisDoc" } } }

Usarlo!

Ahora podes decirle a Claude:

Tu mensaje
"usa check_services para ver si todo esta andando" "muestrame los errores recientes del backend" "como estan las colas de rabbit?"
βœ… MCP Server Creado!

Ahora Claude tiene 3 tools nuevas especificas para ArtisDoc. Podes agregar mas tools para cualquier cosa: GitLab, Elasticsearch, APIs internas, etc.

πŸͺ Sistema de Hooks

Que son los Hooks?

Los hooks son scripts que se ejecutan antes o despues de que Claude use una tool. Sirven para validar, loggear, o bloquear acciones.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ HOOK LIFECYCLE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ Tu mensaje β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Claude decide β”‚ β”‚ β”‚ β”‚ usar Edit tool β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ PRE-TOOL HOOK │────▢│ Valida cambios β”‚ β”‚ β”‚ β”‚ (before Edit) β”‚ β”‚ Puede BLOQUEAR β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό (si pasa) β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ EJECUTA EDIT β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ POST-TOOL HOOK │────▢│ Loggea cambios β”‚ β”‚ β”‚ β”‚ (after Edit) β”‚ β”‚ Notifica, etc β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Configuracion en settings.json

.claude/settings.json
{ "hooks": { "pre-tool-use": [ { "matcher": "Bash", "command": ".claude/hooks/validate-bash.sh" }, { "matcher": "Edit", "command": ".claude/hooks/validate-edit.sh" } ], "post-tool-use": [ { "matcher": "*", "command": ".claude/hooks/log-all.sh" } ] } }
Campo Descripcion
matcher Nombre de la tool a interceptar (* = todas)
command Script a ejecutar (recibe JSON en stdin)

El script recibe JSON

El hook recibe info de la tool en stdin:

JSON (stdin al hook)
{ "tool": "Bash", "input": { "command": "git push --force" } }

Para bloquear: El script debe salir con codigo != 0 y escribir en stderr.

πŸ›‘οΈ Hooks para ArtisDoc

Hook: Bloquear comandos peligrosos

.claude/hooks/validate-bash.sh Bash
#!/bin/bash # Lee el JSON de stdin INPUT=$(cat) COMMAND=$(echo "$INPUT" | jq -r '.input.command') # Comandos prohibidos if echo "$COMMAND" | grep -qE "(--force|--hard|drop table|truncate|rm -rf)"; then echo "❌ BLOQUEADO: Comando peligroso detectado: $COMMAND" >&2 exit 1 fi # No permitir push a main/master if echo "$COMMAND" | grep -qE "git push.*(main|master)"; then echo "❌ BLOQUEADO: No se permite push directo a main/master" >&2 exit 1 fi # Si llega aca, todo OK exit 0

Hook: Validar ediciones en archivos criticos

.claude/hooks/validate-edit.sh Bash
#!/bin/bash INPUT=$(cat) FILE=$(echo "$INPUT" | jq -r '.input.file_path') # Archivos protegidos que requieren confirmacion manual PROTECTED=( "application.properties" "application-prod.properties" "docker-compose.yml" "pom.xml" ) for p in "${PROTECTED[@]}"; do if [[ "$FILE" == *"$p"* ]]; then echo "⚠️ ARCHIVO PROTEGIDO: $FILE" >&2 echo "Requiere revision manual. Usa 'y' para continuar." >&2 # Exit 0 pero con warning (no bloquea, solo avisa) fi done exit 0

Hook: Loggear todas las acciones

.claude/hooks/log-all.sh Bash
#!/bin/bash INPUT=$(cat) TOOL=$(echo "$INPUT" | jq -r '.tool') TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') LOG_FILE=".claude/activity.log" # Loggear la accion echo "[$TIMESTAMP] Tool: $TOOL" >> "$LOG_FILE" echo "$INPUT" | jq -c '.' >> "$LOG_FILE" echo "---" >> "$LOG_FILE" exit 0

Esto crea un log de todo lo que Claude hace. Util para auditar o debuggear.

πŸ” Debugging: OCR No Procesa

πŸ› Escenario: Los documentos quedan en "PENDING" para siempre
Subiste un PDF pero nunca pasa a "COMPLETED". El documento queda en estado OCR_PENDING.

Como pedirle a Claude que lo debuggee:

Tu mensaje a Claude
El OCR no procesa documentos. Subi un PDF hace 1 hora y sigue en PENDING. Necesito que: 1. Verifiques si el servicio OCR esta corriendo 2. Revises si hay mensajes en la cola de RabbitMQ 3. Busques errores en los logs del OCR 4. Me digas cual es el problema y como solucionarlo

Lo que Claude va a hacer:

Verificar contenedor OCR

docker ps | grep ocr # Si no aparece, el servicio esta caido

Revisar cola RabbitMQ

curl -s -u guest:guest http://localhost:15672/api/queues/%2F/ocr.queue | jq '{messages, consumers}' # messages > 0 y consumers = 0 significa que nadie consume

Buscar errores en logs

docker logs artisdocv2_ocr_1 --tail 100 2>&1 | grep -i "error\|exception\|failed"

Verificar conexion MongoDB (donde se guardan los archivos)

docker exec artisdocv2_mongo_1 mongo --eval "db.fs.files.find().limit(1)"
πŸ’‘ Solucion comun

El 80% de las veces es que el contenedor OCR se cayo. Solucion: docker-compose up -d ocr

πŸ’₯ Debugging: Error 500 en Produccion

πŸ”₯ Escenario: GET /api/documents devuelve 500
En produccion, el endpoint de documentos empezo a fallar. Los usuarios no pueden ver sus documentos.
Tu mensaje a Claude
Tenemos un error 500 en produccion en GET /api/documents. El error empezo hace 30 minutos. Ayudame a: 1. Encontrar el stack trace en los logs 2. Identificar la causa raiz 3. Proponer una solucion

Workflow de debugging:

Paso 1: Buscar el error en logs
# Buscar errores recientes grep -A 20 "ERROR.*DocumentController\|Exception.*document" backend/backend.log | tail -50
Paso 2: Verificar conexion a DB
# PostgreSQL respondiendo? docker exec artisdocv2_postgres_1 psql -U postgres -c "SELECT 1" # Conexiones activas (si hay muchas puede ser pool agotado) docker exec artisdocv2_postgres_1 psql -U postgres -c "SELECT count(*) FROM pg_stat_activity"
Paso 3: Revisar memoria JVM
# Ver si hay OutOfMemory grep -i "OutOfMemory\|heap\|GC" backend/backend.log | tail -20
⚠️ Errores comunes en ArtisDoc
Error Causa probable Solucion
Connection refused PostgreSQL caido docker-compose up -d postgres
Pool exhausted Muchas conexiones Reiniciar backend o aumentar pool
OutOfMemoryError Heap lleno Aumentar -Xmx en JAVA_OPTS
LazyInitializationException Sesion Hibernate cerrada Agregar @Transactional o fetch eager

🐰 Debugging: RabbitMQ Muerto

πŸ“­ Escenario: Las notificaciones no llegan
Los usuarios no reciben emails de notificacion cuando sus documentos se aprueban.
Diagnostico rapido
# 1. RabbitMQ esta vivo? docker ps | grep rabbit curl -s http://localhost:15672/api/overview | jq '.message_stats' # 2. Hay mensajes acumulados? curl -s -u guest:guest http://localhost:15672/api/queues | jq '.[] | {name, messages, consumers}' # 3. El consumidor esta conectado? curl -s -u guest:guest http://localhost:15672/api/consumers | jq '.[].consumer_tag' # 4. Ver mensajes en la cola curl -s -u guest:guest -X POST http://localhost:15672/api/queues/%2F/notification.queue/get \ -H "content-type: application/json" \ -d '{"count":5,"ackmode":"ack_requeue_true","encoding":"auto"}'
πŸ”₯ Si hay mensajes pero 0 consumers

El servicio que consume la cola se cayo. Verificar que el backend este corriendo y revisar logs por errores de conexion a Rabbit.

πŸ…°οΈ Debugging: Angular No Muestra Datos

😡 Escenario: La tabla de documentos esta vacia
El frontend carga pero la lista de documentos no muestra nada. No hay errores en consola.
Tu mensaje a Claude
La tabla de documentos no muestra nada. El backend devuelve datos (probe con curl y funciona). Pero el frontend muestra la tabla vacia. Debuggealo.

Checklist de Claude:

1. Verificar la llamada HTTP
// Buscar el servicio que hace la llamada grep -r "documents" frontend/src/app --include="*.service.ts" -l // Ver como mapea la respuesta grep -A 10 "getDocuments" frontend/src/app/services/document.service.ts
2. Verificar el componente
// El componente se suscribe correctamente? grep -A 15 "ngOnInit" frontend/src/app/documents/document-list.component.ts // El template usa la variable correcta? grep -E "\*ngFor|async" frontend/src/app/documents/document-list.component.html
❌ Error comun
// Se olvido el subscribe this.documentService.getDocuments();
βœ… Correcto
this.documentService.getDocuments() .subscribe(docs => this.documents = docs);
🧠 Tip: Respuesta con estructura diferente

A veces el backend devuelve { data: [...] } pero el frontend espera [...]. Verificar el mapeo en el service.

⚑ Workflows Modo Dios

Multi-file Refactor

Cuando necesitas cambiar algo en muchos archivos:

Tu mensaje
Necesito renombrar "DocumentoService" a "DocumentService" en todo el proyecto. Incluye: - Nombre de clase - Imports - Inyecciones - Referencias en tests Hazlo archivo por archivo y mostrame cada cambio antes de aplicarlo.

Claude va a:

  1. Buscar todas las referencias con Grep
  2. Listar los archivos afectados
  3. Editar cada uno mostrando el diff
  4. Verificar que compila despues de cada cambio

Investigacion de Codebase

Para entender como funciona algo:

Tu mensaje
Explicame el flujo completo de cuando un usuario sube un documento: 1. Desde que hace click en "Subir" en el frontend 2. Pasando por el controller 3. Como se guarda en MongoDB 4. Como se encola para OCR 5. Como se notifica cuando termina Trazame el codigo real, no me cuentes teoria.

Claude va a seguir el flujo archivo por archivo, mostrandote el codigo relevante.

Generar Feature Completa

Tu mensaje
Crea la feature "Favoritos" para que los usuarios puedan marcar documentos como favoritos. Incluye: - Migracion de base de datos (tabla user_favorites) - Entity JPA - Repository - Service con metodos: addFavorite, removeFavorite, getFavorites - Controller REST con endpoints - Tests unitarios del service - Componente Angular con lista de favoritos - Boton de estrella en cada documento Sigue los patrones existentes del proyecto.

πŸ”„ Refactor Masivo

πŸ—οΈ Escenario: Controller de 800 lineas
DocumentController.java tiene 800 lineas y mezcla logica de negocio con HTTP.
Tu mensaje
DocumentController.java tiene 800 lineas y es un desastre. Necesito que: 1. Analices que hace cada metodo 2. Extraigas la logica de negocio a DocumentService 3. El controller solo debe manejar HTTP (request/response) 4. Crees un DocumentTransformer para mapear Entity <-> DTO 5. No rompas nada - los tests existentes deben seguir pasando Hacelo paso a paso, un metodo a la vez.
Analizar
β†’
Extraer Service
β†’
Crear Transformer
β†’
Refactor Controller
β†’
Run Tests

πŸ§ͺ TDD con Claude

El Ciclo RED-GREEN-REFACTOR

RED: Test que falla
β†’
GREEN: Codigo minimo
β†’
REFACTOR: Limpiar
Tu mensaje para TDD
Vamos a implementar la validacion de documentos con TDD. Reglas: - Un documento no puede tener titulo vacio - El titulo debe tener minimo 5 caracteres - No puede haber caracteres especiales en el titulo Empeza escribiendo el test que falla (RED). Despues escribi el codigo minimo para que pase (GREEN). Despues refactorizamos si hace falta.

Claude genera:

DocumentValidatorTest.java RED
@Test void shouldRejectEmptyTitle() { Document doc = new Document(); doc.setTitle(""); ValidationResult result = validator.validate(doc); assertThat(result.isValid()).isFalse(); assertThat(result.getErrors()).contains("Title cannot be empty"); }
DocumentValidator.java GREEN
public ValidationResult validate(Document doc) { List<String> errors = new ArrayList<>(); if (doc.getTitle() == null || doc.getTitle().isEmpty()) { errors.add("Title cannot be empty"); } return new ValidationResult(errors.isEmpty(), errors); }
βœ… Tip: Pedi que corra los tests

Despues de cada paso, podes decirle: "correr mvn test para verificar". Asi te aseguras que el ciclo TDD se respeta.