Módulo 7: Remote Control y CLAUDE.md para Equipos

4. CLAUDE.md para Equipos — Estructura, Merge y Enforcement

4. CLAUDE.md para Equipos — Estructura, Merge y Enforcement

Descripción

Hasta ahora, CLAUDE.md ha sido tu documento personal. Lo escribes para tu proyecto, con tus preferencias, y Claude Code lo sigue. Funciona bien cuando eres el único developer. Pero cuando tres personas trabajan en el mismo repo, cada uno con su propio CLAUDE.md (o sin uno), el resultado es caos: archivos con tabs y spaces mezclados, funciones con y sin type hints, tests en diferentes frameworks, imports organizados de tres formas distintas. El código se ve como si lo hubieran escrito tres personas diferentes — porque tres agentes con reglas diferentes lo escribieron.

CLAUDE.md para equipos resuelve esto. Es un documento compartido que se commitea al repositorio y establece las reglas que todos los agentes respetan: convenciones de código, decisiones arquitectónicas, patrones prohibidos, requisitos de testing. Cuando alguien clona el repo, su Claude Code adopta automáticamente las reglas del equipo. No hay reunión de "alineación de estilo." No hay PR con 47 comentarios sobre formatting.

Esta cápsula cubre la estructura de un CLAUDE.md de equipo production-ready, la jerarquía de merge que permite reglas compartidas con overrides personales, el enforcement con hooks que validan compliance, y un template completo que puedes adaptar a tu equipo.


CLAUDE.md como Constitución

La metáfora correcta

No pienses en CLAUDE.md como un archivo de configuración. Un config file dice "usa port 3000." Una constitución dice "estos son nuestros valores, estas son las reglas, estas son las consecuencias de romperlas." Un CLAUDE.md de equipo es una constitución:

Config file:                    Constitución (CLAUDE.md):
─────────────                   ─────────────────────────
port: 3000                      Usamos TypeScript strict
debug: true                     No usamos any - nunca
log_level: info                 Tests unitarios para toda lógica de negocio
                                Cobertura mínima: 80%
                                Conventional commits obligatorio
                                No console.log en producción
                                Imports ordenados: stdlib > third-party > local

La diferencia: un config file describe parámetros técnicos. Una constitución describe expectativas de comportamiento. CLAUDE.md dice cómo debe comportarse el agente, qué patrones seguir, qué nunca hacer, y qué nivel de calidad se espera.

Por qué funciona como estándar

  1. Se commitea al repo → Todos lo tienen automáticamente
  2. Es declarativo → "qué hacer", no "cómo configurar"
  3. Es evolutivo → Se actualiza con PRs como cualquier otro archivo
  4. Es enforceable → Hooks pueden validar compliance
  5. Escala sin reuniones → Nuevo miembro clona, adopta, produce consistente

Estructura de un CLAUDE.md de Equipo

Secciones recomendadas

Un CLAUDE.md de equipo efectivo tiene estas secciones:

# CLAUDE.md — [Nombre del Proyecto]

## Contexto del Proyecto
Breve descripción de qué hace el proyecto, stack tecnológico,
y arquitectura de alto nivel.

## Convenciones de Código
Reglas de estilo, naming, formatting que todo código debe seguir.

## Arquitectura
Decisiones arquitectónicas vigentes. Patrones que usamos y por qué.

## Patrones Prohibidos
Lo que NUNCA debe hacerse. Anti-patterns específicos del proyecto.

## Testing
Requisitos de testing. Frameworks, cobertura, tipos de tests requeridos.

## Git y Workflow
Convenciones de commits, branches, PRs.

## Seguridad
Reglas de seguridad. Qué nunca exponer, cómo manejar secretos.

## Dependencias
Políticas de dependencias. Cuándo agregar, cómo evaluar, qué evitar.

Template production-ready

Este es un CLAUDE.md que puedes adaptar para tu equipo:

# CLAUDE.md — TaskFlow API

## Contexto del Proyecto
TaskFlow es una API REST para gestión de tareas colaborativas.
- Backend: Python 3.12 + FastAPI
- Base de datos: PostgreSQL 16 + SQLAlchemy 2.0 (async)
- Cache: Redis 7
- Auth: JWT con refresh tokens
- Tests: pytest + httpx
- Deploy: Docker + GitHub Actions

## Convenciones de Código

### Python
- Type hints obligatorios en TODAS las funciones (parámetros y retorno)
- Docstrings en formato Google para funciones públicas
- Nombres de variables descriptivos, no abreviaciones (user_repository, NO ur)
- Funciones de máximo 30 líneas. Si son más largas, extraer subfunciones
- Usar pathlib en lugar de os.path
- f-strings para interpolación, no .format() ni %

### Naming
- Archivos: snake_case (user_service.py)
- Clases: PascalCase (UserService)
- Funciones y variables: snake_case (get_user_by_id)
- Constantes: UPPER_SNAKE_CASE (MAX_RETRY_COUNT)
- Endpoints: kebab-case en URLs (/api/v1/user-tasks)

### Imports
Orden estricto, separado por líneas en blanco:
1. stdlib (os, sys, typing, datetime)
2. third-party (fastapi, sqlalchemy, pydantic)
3. local (app.models, app.services)

### Formatting
- ruff como linter y formatter
- Configuración en pyproject.toml (ya incluida en el repo)
- Ejecutar `ruff check --fix .` antes de cada commit

## Arquitectura

### Estructura de directorios
```text
app/
├── api/            # Routers de FastAPI (endpoints)
├── core/           # Configuración, seguridad, excepciones
├── models/         # SQLAlchemy models
├── schemas/        # Pydantic schemas (request/response)
├── services/       # Lógica de negocio
├── repositories/   # Acceso a datos (queries)
└── utils/          # Utilidades compartidas

Capas

  • Routers llaman a Services
  • Services llaman a Repositories
  • Repositories llaman a la DB
  • NUNCA un Router accede directamente a la DB
  • NUNCA un Repository contiene lógica de negocio

Patrones

  • Repository Pattern para acceso a datos
  • Dependency Injection via FastAPI Depends()
  • Pydantic para validación de entrada Y salida
  • Async/await para todas las operaciones de I/O

Patrones Prohibidos

  • NO usar any type en Python (typing.Any) sin justificación en comentario
  • NO queries SQL raw — siempre usar SQLAlchemy ORM
  • NO print() para logging — usar el logger configurado en app.core.logging
  • NO hardcodear URLs, puertos, o credenciales — usar variables de entorno
  • NO importar desde tests/ en código de producción
  • NO commit de archivos .env, credenciales, o tokens
  • NO usar datetime.now() — usar datetime.now(UTC) para consistencia
  • NO modificar archivos en alembic/versions/ manualmente — usar alembic revision

Testing

Requisitos

  • Cobertura mínima: 80% (enforced en CI)
  • Todo endpoint tiene al menos 1 test de happy path y 1 de error
  • Toda función de servicio tiene test unitario
  • Tests de integración para flujos completos (auth → create → read)

Convenciones

  • Archivos de test: test_[module].py en tests/
  • Fixtures compartidas en conftest.py
  • Factory pattern para crear objetos de test
  • No usar datos hardcodeados — usar factories o fixtures
  • Cada test es independiente — no depende del orden de ejecución

Frameworks

  • pytest como runner
  • httpx.AsyncClient para tests de endpoints
  • pytest-asyncio para tests async
  • factory-boy para factories de modelos

Git y Workflow

Commits

  • Conventional Commits: tipo(scope): descripción
  • Tipos: feat, fix, refactor, test, docs, chore, ci
  • Ejemplo: feat(auth): add JWT refresh token endpoint
  • Mensajes en inglés, imperativo, sin punto final
  • Máximo 72 caracteres en la primera línea

Branches

  • main: producción, siempre deployable
  • develop: integración
  • feature/xxx: nuevas features
  • fix/xxx: bug fixes
  • NUNCA force push a main o develop

Pull Requests

  • Requiere 1 review mínimo
  • CI debe pasar (tests + lint)
  • Descripción incluye: qué, por qué, y cómo testear

Seguridad

  • NUNCA commitear .env, API keys, tokens, o passwords
  • Variables sensibles van en variables de entorno
  • Passwords se hashean con bcrypt (nunca en texto plano)
  • JWT secrets mínimo 256 bits
  • Rate limiting activo en todos los endpoints públicos
  • Input validation con Pydantic en TODOS los endpoints
  • No exponer stack traces en respuestas de error (usar excepciones custom)

Dependencias

  • Evaluar antes de agregar: ¿vale la complejidad extra?
  • Preferir stdlib sobre third-party cuando es viable
  • Fijar versiones en requirements.txt (==, no >=)
  • Auditar dependencias con pip-audit mensualmente
  • No instalar paquetes de desarrollo en producción

### Puntos clave del template

1. **Contexto primero** — El agente necesita entender qué es el proyecto antes de las reglas
2. **Convenciones son específicas** — "Type hints obligatorios" no "intenta usar type hints"
3. **Prohibiciones son absolutas** — "NO" en mayúsculas, sin ambigüedad
4. **Testing es enforceable** — Cobertura mínima cuantificable, no "intenta testear"
5. **Seguridad es no negociable** — Las reglas de seguridad no tienen excepciones

---

## Jerarquía de Merge

### Los tres niveles de CLAUDE.md

Claude Code busca y combina CLAUDE.md de múltiples ubicaciones:

Nivel 1: Global (usuario) ~/.claude/CLAUDE.md → Preferencias personales que aplican a TODOS tus proyectos → Ej: "Siempre responde en español", "Prefiero explicaciones concisas"

Nivel 2: Proyecto (root del repo) ./CLAUDE.md → Estándar del equipo para este proyecto → Se commitea al repo → todos lo comparten → Ej: "TypeScript strict", "Conventional commits"

Nivel 3: Subdirectorio (módulo-específico) ./src/api/CLAUDE.md → Reglas específicas para un módulo del proyecto → Ej: "Endpoints siguen RESTful naming", "Validación con Pydantic"


### Regla de precedencia

**Más específico gana.** Si hay conflicto entre niveles:

Global dice: "Usa tabs" Proyecto dice: "Usa spaces (4)" Subdirectorio dice: "Usa spaces (2)"

Resultado cuando trabajas en ./src/api/: → Usa spaces (2) — subdirectorio gana

Resultado cuando trabajas en ./src/models/: → Usa spaces (4) — proyecto gana (no hay subdirectorio CLAUDE.md)

Resultado en otro proyecto sin CLAUDE.md: → Usa tabs — global gana (único nivel disponible)


### Merge en práctica

Claude Code no reemplaza niveles — los **combina**. Las reglas de todos los niveles aplicables se juntan, y solo se overridean las que explícitamente conflictúan:

Global CLAUDE.md:

  • Responde en español
  • Prefiere explicaciones concisas
  • Usa git conventional commits

Proyecto CLAUDE.md:

  • TypeScript strict
  • Tests con vitest
  • No console.log

Cuando Claude Code trabaja en este proyecto, sigue TODO: ✅ Responde en español (global) ✅ Explicaciones concisas (global) ✅ Conventional commits (global) ✅ TypeScript strict (proyecto) ✅ Tests con vitest (proyecto) ✅ No console.log (proyecto)


### CLAUDE.md en subdirectorios

Para proyectos grandes, puedes tener CLAUDE.md en subdirectorios con reglas específicas del módulo:

my-project/ ├── CLAUDE.md ← Reglas del proyecto ├── src/ │ ├── api/ │ │ ├── CLAUDE.md ← Reglas específicas de la API │ │ └── routes.py │ ├── models/ │ │ ├── CLAUDE.md ← Reglas específicas de modelos │ │ └── user.py │ └── utils/ │ └── helpers.py ← Solo reglas del proyecto (no hay subdir CLAUDE.md)


`src/api/CLAUDE.md`:
```markdown
## API-Specific Rules
- Endpoints use kebab-case URLs
- Every endpoint returns a Pydantic ResponseModel
- Error responses use app.core.exceptions, not raw HTTPException
- New endpoints require OpenAPI documentation

src/models/CLAUDE.md:

## Model-Specific Rules
- Every model has created_at and updated_at timestamps
- Soft delete with is_deleted flag, never hard delete
- Relationships use lazy="selectin" for async compatibility
- Migrations go through alembic, never manual schema changes

Enforcement: Hooks que Validan Compliance

El problema de "reglas sin dientes"

Un CLAUDE.md sin enforcement es una sugerencia. Claude Code lo respeta la mayoría del tiempo, pero los LLMs pueden cometer errores. Enforcement con hooks convierte las sugerencias en reglas:

Sin enforcement:
  CLAUDE.md dice "usa type hints" →
  Claude olvida en 3 de 20 funciones →
  Code review lo detecta (quizás)

Con enforcement:
  CLAUDE.md dice "usa type hints" →
  Hook PostToolUse ejecuta mypy después de cada edición →
  Claude recibe el error y corrige inmediatamente →
  100% compliance

Hook: Validar type hints después de edición

scripts/hooks/enforce-type-hints.sh:

#!/bin/bash

INPUT=$(cat -)

FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')

if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then
    exit 0
fi

if [[ "$FILE" != *.py ]]; then
    exit 0
fi

if command -v mypy &> /dev/null; then
    MYPY_RESULT=$(mypy "$FILE" --ignore-missing-imports --no-error-summary 2>&1)
    MYPY_EXIT=$?

    if [ $MYPY_EXIT -ne 0 ]; then
        MISSING_HINTS=$(echo "$MYPY_RESULT" | grep -c "missing return type\|no type annotation")
        if [ "$MISSING_HINTS" -gt 0 ]; then
            echo "CLAUDE.md VIOLATION: Missing type hints in $FILE"
            echo "$MYPY_RESULT" | grep "missing return type\|no type annotation" | head -5
            exit 1
        fi
    fi
fi

exit 0

Hook: Validar que no se usen patrones prohibidos

scripts/hooks/enforce-forbidden-patterns.sh:

#!/bin/bash

INPUT=$(cat -)

FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')

if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then
    exit 0
fi

if [[ "$FILE" == *.py ]]; then
    if grep -n "print(" "$FILE" | grep -v "^#" | grep -v "# noqa" > /dev/null 2>&1; then
        LINES=$(grep -n "print(" "$FILE" | grep -v "^#" | grep -v "# noqa" | head -5)
        echo "CLAUDE.md VIOLATION: print() found in $FILE"
        echo "Use logger instead. Found:"
        echo "$LINES"
        exit 1
    fi

    if grep -n "datetime.now()" "$FILE" | grep -v "now(UTC)" > /dev/null 2>&1; then
        echo "CLAUDE.md VIOLATION: datetime.now() without UTC in $FILE"
        echo "Use datetime.now(UTC) for timezone consistency"
        exit 1
    fi

    if grep -n "typing.Any" "$FILE" > /dev/null 2>&1; then
        ANY_COUNT=$(grep -c "typing.Any\|from typing import.*Any" "$FILE")
        JUSTIFIED=$(grep -c "# justified:" "$FILE")
        if [ "$ANY_COUNT" -gt "$JUSTIFIED" ]; then
            echo "CLAUDE.md VIOLATION: typing.Any without justification in $FILE"
            echo "Add '# justified: reason' comment for each use of Any"
            exit 1
        fi
    fi
fi

if [[ "$FILE" == *.ts ]] || [[ "$FILE" == *.tsx ]]; then
    if grep -n "console\.log\|console\.warn\|console\.error" "$FILE" | grep -v "// debug" > /dev/null 2>&1; then
        echo "CLAUDE.md VIOLATION: console.log found in $FILE"
        echo "Use the project logger instead"
        exit 1
    fi

    if grep -n ": any" "$FILE" | grep -v "// justified" > /dev/null 2>&1; then
        echo "CLAUDE.md VIOLATION: 'any' type found in $FILE"
        exit 1
    fi
fi

exit 0

Hook: Validar convenciones de naming

scripts/hooks/enforce-naming.sh:

#!/bin/bash

INPUT=$(cat -)

FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')

if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then
    exit 0
fi

BASENAME=$(basename "$FILE")

if [[ "$FILE" == *.py ]]; then
    if ! echo "$BASENAME" | grep -qE "^[a-z][a-z0-9_]*\.py$"; then
        echo "CLAUDE.md VIOLATION: Python filename must be snake_case"
        echo "File: $BASENAME"
        echo "Expected: snake_case.py"
        exit 1
    fi
fi

if [[ "$FILE" == *.ts ]] || [[ "$FILE" == *.tsx ]]; then
    if echo "$BASENAME" | grep -qE "^[A-Z]"; then
        : # PascalCase components are OK in React
    elif ! echo "$BASENAME" | grep -qE "^[a-z][a-z0-9-]*\.(ts|tsx)$"; then
        echo "CLAUDE.md VIOLATION: TypeScript filename must be kebab-case"
        echo "File: $BASENAME"
        exit 1
    fi
fi

exit 0

settings.json con todos los enforcement hooks

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/hooks/enforce-forbidden-patterns.sh"
          },
          {
            "type": "command",
            "command": "./scripts/hooks/enforce-naming.sh"
          },
          {
            "type": "command",
            "command": "./scripts/hooks/enforce-type-hints.sh"
          }
        ]
      }
    ]
  }
}

Onboarding: Nuevos Miembros Adoptan el Estándar Automáticamente

El flujo ideal

Nuevo developer se une al equipo:

1. git clone repo-url          → Obtiene CLAUDE.md + settings.json + hook scripts
2. Abre Claude Code            → SessionStart hook verifica entorno
3. Escribe código              → Hooks validan compliance en tiempo real
4. Hace commit                 → Conventional commits, lint pasa
5. Crea PR                     → CI valida cobertura, linting, types

Resultado: código consistente desde el primer commit.
Sin documentos de 20 páginas. Sin reuniones de "cómo configurar."

Checklist de onboarding con CLAUDE.md

Lo que tu repositorio necesita para onboarding automático:

✅ CLAUDE.md en el root del repo (constitución del equipo)
✅ .claude/settings.json con hooks de enforcement
✅ scripts/hooks/ con todos los scripts de validación
✅ pyproject.toml / .eslintrc configurados (linter del proyecto)
✅ .github/CONTRIBUTING.md con link al CLAUDE.md
✅ Todos los scripts de hooks con chmod +x (ejecutables)

Script de verificación de onboarding

scripts/verify-setup.sh:

#!/bin/bash

echo "=== Verificación de Setup de Equipo ==="
ERRORS=0

if [ ! -f "CLAUDE.md" ]; then
    echo "❌ CLAUDE.md no encontrado en el root"
    ERRORS=$((ERRORS + 1))
else
    echo "✅ CLAUDE.md presente"
fi

if [ ! -f ".claude/settings.json" ]; then
    echo "❌ .claude/settings.json no encontrado"
    ERRORS=$((ERRORS + 1))
else
    if jq -e '.hooks' .claude/settings.json > /dev/null 2>&1; then
        echo "✅ settings.json con hooks configurados"
    else
        echo "⚠️ settings.json sin hooks"
    fi
fi

if [ -d "scripts/hooks" ]; then
    HOOK_COUNT=$(ls scripts/hooks/*.sh 2>/dev/null | wc -l | tr -d ' ')
    EXECUTABLE=$(find scripts/hooks/ -name "*.sh" -perm +111 2>/dev/null | wc -l | tr -d ' ')
    echo "✅ $HOOK_COUNT hook scripts ($EXECUTABLE ejecutables)"

    if [ "$HOOK_COUNT" -ne "$EXECUTABLE" ]; then
        echo "⚠️ Algunos scripts no son ejecutables"
        echo "  Fix: chmod +x scripts/hooks/*.sh"
    fi
else
    echo "❌ scripts/hooks/ no encontrado"
    ERRORS=$((ERRORS + 1))
fi

if command -v ruff &> /dev/null; then
    echo "✅ ruff instalado"
elif command -v npx &> /dev/null && npx eslint --version > /dev/null 2>&1; then
    echo "✅ eslint instalado"
else
    echo "⚠️ No se encontró linter (ruff o eslint)"
fi

if command -v jq &> /dev/null; then
    echo "✅ jq instalado"
else
    echo "❌ jq no instalado (requerido por hooks)"
    ERRORS=$((ERRORS + 1))
fi

echo ""
if [ $ERRORS -eq 0 ]; then
    echo "✅ Setup completo. Estás listo para trabajar."
else
    echo "❌ $ERRORS problemas encontrados. Revisa los errores arriba."
fi

exit $ERRORS

Mantenimiento del CLAUDE.md

Cuándo actualizar

SeñalAcción
Nuevo framework adoptadoAgregar a "Convenciones de Código"
Bug recurrente en PRsAgregar a "Patrones Prohibidos"
Nueva decisión arquitectónicaAgregar a "Arquitectura"
Revisión trimestralVerificar que todo sigue vigente
Nuevo miembro reporta confusiónClarificar la sección ambigua

Proceso de actualización

1. Crear branch: git checkout -b update/claude-md-conventions
2. Editar CLAUDE.md
3. Actualizar hooks si las reglas nuevas necesitan enforcement
4. Crear PR con descripción del cambio
5. Review del equipo (al menos 2 approvals para cambios de constitución)
6. Merge a main
7. Todos los miembros obtienen los cambios con git pull

Antipatrones de CLAUDE.md

❌ CLAUDE.md de 500+ líneas
   → Demasiado largo. Claude Code puede perder instrucciones.
   → Mantén < 200 líneas. Usa subdirectory CLAUDE.md para detalles.

❌ Reglas vagas: "Escribe buen código"
   → No actionable. ¿Qué es "bueno"?
   → Específico: "Funciones de máximo 30 líneas"

❌ Reglas que nunca se revisan
   → Se acumulan y contradicen.
   → Revisión trimestral con el equipo.

❌ Reglas sin enforcement
   → Se ignoran gradualmente.
   → Si es importante, agrega un hook que lo valide.

❌ No permitir overrides personales
   → Frustra a developers experimentados.
   → Usa la jerarquía: equipo establece mínimos, personal puede ser más estricto.

Troubleshooting

"Claude Code ignora algunas reglas del CLAUDE.md"

Causa: El CLAUDE.md es demasiado largo o las reglas son ambiguas. Los LLMs pueden perder instrucciones en documentos largos.

Solución: Mantén el CLAUDE.md conciso (< 200 líneas). Prioriza las reglas más importantes al inicio del archivo. Usa enforcement hooks para las reglas críticas:

wc -l CLAUDE.md
# Si > 200, refactoriza: mueve detalles a subdirectory CLAUDE.md

"Conflicto entre CLAUDE.md global y de proyecto"

Causa: Tu CLAUDE.md global dice algo que contradice el del proyecto.

Solución: La regla es clara: proyecto gana sobre global. Si tu global dice "usa tabs" pero el proyecto dice "usa spaces", el proyecto prevalece. Si el conflicto es frecuente, ajusta tu global para ser más genérico:

# ~/.claude/CLAUDE.md (global) — BUENO
Responde en español.
Explicaciones concisas.
Conventional commits.

# ~/.claude/CLAUDE.md (global) — MALO
Usa tabs para indentación.        ← Esto conflictuará con proyectos que usan spaces
Siempre usa React.                ← No aplica a proyectos Python
Tests con Jest.                   ← No aplica a todos los proyectos

"Los hooks de enforcement son muy lentos"

Causa: Hooks como mypy o eslint sobre archivos grandes tardan varios segundos, y se ejecutan en cada edición.

Solución: Haz los hooks incrementales — solo verifican el archivo editado, no todo el proyecto:

# MAL: verifica todo el proyecto
mypy src/

# BIEN: verifica solo el archivo editado
mypy "$FILE" --ignore-missing-imports

"Un developer necesita una excepción a la regla"

Causa: Hay un caso legítimo donde la regla no aplica.

Solución: Usa comentarios de excepción que los hooks reconocen:

from typing import Any  # justified: third-party lib returns untyped data

print("Debug info")  # noqa: debugging, remove before merge

Configura los hooks para respetar estos marcadores (como se mostró en enforce-forbidden-patterns.sh).

"El CLAUDE.md de un subdirectorio contradice al del proyecto"

Causa: Reglas conflictivas entre niveles.

Solución: El subdirectorio gana para archivos dentro de él. Si el conflicto es un error, resolverlo en PR. Si es intencional, documentar por qué:

# src/legacy/CLAUDE.md
## Excepciones para código legacy
- Se permite typing.Any sin justificación (código pre-typing era)
- Cobertura mínima: 50% (no 80% como el resto del proyecto)
- Razón: módulo en proceso de migración, no invertir en tests completos

Comparación: CLAUDE.md Rígido vs Flexible con Overrides

AspectoRígido (solo proyecto)Flexible (con overrides personales)
SetupSimple: un solo CLAUDE.mdMás complejo: múltiples niveles
ConsistenciaMáxima: todos siguen exactamente las mismas reglasAlta: misma base, variaciones controladas
Satisfacción del equipoPuede frustrar a developers experimentadosAlta: respeta preferencias personales
OnboardingMuy simple: clonar = listoSimple: clonar = base, personalizar = opcional
MantenimientoBajo: un archivoMedio: vigilar que overrides no rompan el estándar
EnforcementDirecto: hooks validan contra un solo documentoNecesita entender la jerarquía
Ideal paraEquipos pequeños, proyectos críticosEquipos medianos+, diversidad de experiencia
RiesgoDemasiada rigidez → resistenciaDemasiada flexibilidad → inconsistencia

Recomendación: Empieza con CLAUDE.md de proyecto (rígido). Cuando el equipo crezca o developers experimenten fricción, introduce overrides personales con la jerarquía de merge. Mantén las reglas de seguridad y arquitectura sin override; permite overrides en preferencias de estilo.


Ejercicios

Ejercicio 1: CLAUDE.md mínimo viable (Fácil)

Escribe un CLAUDE.md de equipo con exactamente 5 reglas que cubran: lenguaje, naming, testing, una prohibición, y una convención de git.

Ver solución
# CLAUDE.md — Mi Proyecto

## Convenciones
- Python 3.12 con type hints obligatorios en todas las funciones
- snake_case para archivos y funciones, PascalCase para clases

## Testing
- pytest para todos los tests, cobertura mínima 80%

## Prohibido
- NO usar print() para logging — usar structlog

## Git
- Conventional commits: tipo(scope): descripción en inglés

Cinco reglas claras, específicas, y actionables. Un agente que lee esto sabe exactamente qué hacer.

Ejercicio 2: Jerarquía de merge (Fácil)

Dados estos tres CLAUDE.md, ¿qué reglas sigue Claude Code cuando edita src/api/routes.py?

Global (~/.claude/CLAUDE.md):

  • Responde en español
  • Usa tabs

Proyecto (./CLAUDE.md):

  • Usa spaces (4)
  • Tests con pytest

Subdirectorio (./src/api/CLAUDE.md):

  • Endpoints retornan ResponseModel
  • Usa spaces (2)
Ver solución

Para src/api/routes.py, Claude Code sigue:

  1. Responde en español ← Global (no conflictúa con nada)
  2. Usa spaces (2) ← Subdirectorio (overrides proyecto que dice 4, que overrides global que dice tabs)
  3. Tests con pytest ← Proyecto (no conflictúa)
  4. Endpoints retornan ResponseModel ← Subdirectorio (regla adicional)

La regla "Usa tabs" del global queda completamente overrideada por "Usa spaces (4)" del proyecto, que a su vez queda overrideada por "Usa spaces (2)" del subdirectorio.

Si Claude edita un archivo en src/models/ (sin CLAUDE.md de subdirectorio), usaría spaces (4) del proyecto.

Ejercicio 3: Hook de enforcement para imports (Medio)

Crea un hook PostToolUse que valide que los imports en archivos Python siguen el orden correcto: stdlib → third-party → local. Reporta una violación (exit 1) si el orden es incorrecto.

Ver solución

scripts/hooks/enforce-import-order.sh:

#!/bin/bash

INPUT=$(cat -)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')

if [ -z "$FILE" ] || [ ! -f "$FILE" ] || [[ "$FILE" != *.py ]]; then
    exit 0
fi

if command -v ruff &> /dev/null; then
    IMPORT_CHECK=$(ruff check "$FILE" --select I --no-fix 2>&1)
    if [ $? -ne 0 ]; then
        echo "CLAUDE.md VIOLATION: Import order incorrect in $FILE"
        echo "Expected: stdlib > third-party > local"
        echo "$IMPORT_CHECK" | head -5
        echo ""
        echo "Fix: ruff check --select I --fix $FILE"
        exit 1
    fi
fi

exit 0

Este hook usa ruff con la regla I (isort) para validar el orden de imports. Si ruff no está disponible, el hook pasa silenciosamente (exit 0).

Ejercicio 4: CLAUDE.md con subdirectorios (Medio)

Diseña una estructura de CLAUDE.md para un proyecto fullstack con frontend/ (React + TypeScript) y backend/ (Python + FastAPI). El CLAUDE.md raíz define reglas comunes, y cada subdirectorio define reglas específicas de su stack.

Ver solución

./CLAUDE.md (raíz):

# CLAUDE.md — FullStack App

## General
- Git conventional commits en inglés
- No hardcodear URLs o credenciales
- Variables sensibles en .env (never commit .env)

## Code Quality
- Cobertura de tests mínima: 80%
- No TODO sin issue asociado: "TODO(#123): descripción"
- Funciones de máximo 30 líneas

./frontend/CLAUDE.md:

## Frontend Rules
- TypeScript strict mode, no `any`
- React functional components only (no class components)
- Styling with Tailwind CSS utility classes
- Tests with Vitest + React Testing Library
- File naming: PascalCase for components, kebab-case for utils
- Imports: react > third-party > @/components > @/utils > relative

./backend/CLAUDE.md:

## Backend Rules
- Python 3.12 with type hints on all functions
- FastAPI with async endpoints
- SQLAlchemy 2.0 async ORM (no raw SQL)
- Tests with pytest + httpx.AsyncClient
- File naming: snake_case
- Logging with structlog (no print())
- Pydantic v2 for all request/response schemas

Ejercicio 5: Sistema de enforcement completo (Difícil)

Crea un settings.json que combine enforcement de CLAUDE.md con approval flows: PostToolUse hooks validan reglas del CLAUDE.md, y PreToolUse hooks bloquean commits que no siguen conventional commits.

Ver solución

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/hooks/validate-commit-message.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/hooks/enforce-forbidden-patterns.sh"
          },
          {
            "type": "command",
            "command": "./scripts/hooks/enforce-import-order.sh"
          }
        ]
      }
    ]
  }
}

scripts/hooks/validate-commit-message.sh:

#!/bin/bash

INPUT=$(cat -)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

if ! echo "$COMMAND" | grep -q "git commit"; then
    exit 0
fi

COMMIT_MSG=$(echo "$COMMAND" | grep -oP '(?<=-m ")[^"]*' | head -1)
if [ -z "$COMMIT_MSG" ]; then
    COMMIT_MSG=$(echo "$COMMAND" | grep -oP "(?<=-m ')[^']*" | head -1)
fi

if [ -z "$COMMIT_MSG" ]; then
    exit 0
fi

PATTERN="^(feat|fix|refactor|test|docs|chore|ci|perf|style)\(.+\): .+"

if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
    echo "CLAUDE.md VIOLATION: Commit message must follow Conventional Commits"
    echo "Format: type(scope): description"
    echo "Types: feat, fix, refactor, test, docs, chore, ci, perf, style"
    echo "Got: $COMMIT_MSG"
    exit 2
fi

exit 0

Resumen

  • CLAUDE.md para equipos es una constitución, no un config file — define comportamiento, valores, y restricciones que todos los agentes respetan
  • Un CLAUDE.md efectivo tiene secciones claras: contexto, convenciones, arquitectura, prohibiciones, testing, git, seguridad
  • La jerarquía de merge (global < proyecto < subdirectorio) permite reglas compartidas con espacio para overrides en módulos específicos
  • Enforcement con hooks convierte las reglas del CLAUDE.md en validaciones automáticas: PostToolUse verifica compliance después de cada edición
  • El onboarding automático es el beneficio más tangible: clonar el repo = adoptar el estándar, sin configuración manual
  • Mantén el CLAUDE.md conciso (< 200 líneas), específico (reglas actionables), y actualizado (revisión trimestral)
  • Las prohibiciones son absolutas y específicas — "NO usar print()" no "evita print() si puedes"
  • Hooks de enforcement respetan marcadores de excepción (# justified:, # noqa:) para casos legítimos
  • Subdirectory CLAUDE.md permite reglas específicas por módulo sin sobrecargar el CLAUDE.md raíz

Recursos Adicionales

  1. Claude Code CLAUDE.md Memory — Documentación oficial de CLAUDE.md, niveles y merge
  2. Claude Code Settings — Configuración de settings.json para enforcement
  3. Claude Code Hooks — Hooks PostToolUse para validación de compliance
  4. Claude Code Best Practices — Buenas prácticas de CLAUDE.md
  5. Claude Code Tips and Tricks — Tips para CLAUDE.md efectivos
  6. Conventional Commits — Especificación de conventional commits
  7. ruff — Python Linter — Linter y formatter para Python usado en enforcement
  8. Google Python Style Guide — Referencia de estilo que complementa CLAUDE.md

Siguiente cápsula: En la cápsula 05 (Proyecto) construirás un setup completo de equipo integrando todo lo aprendido: un CLAUDE.md production-ready para un equipo de 3 personas, remote control configurado, approval flows para operaciones destructivas, hooks de enforcement, y un checklist de onboarding. El setup completo que llevarás al proyecto integrador del Módulo 8.