{
  "descripcion": "Configuración centralizada de hooks SWL. Define el evento, matcher y metadata de cada hook para registro automático en settings.json del runtime destino.",
  "prioridad_hooks": {
    "descripcion": "Orden de precedencia cuando múltiples hooks coinciden. Mayor prioridad gana.",
    "orden": [
      "settings.local.json (proyecto, no versionado — máxima prioridad)",
      "settings.json (proyecto, versionado — hooks SWL se registran aquí)",
      "~/.claude/settings.json (global del usuario — menor prioridad)"
    ],
    "regla": "Los hooks SWL SOLO se registran a nivel proyecto. Si existen a nivel global, el doctor los elimina para evitar ejecución duplicada."
  },
  "opciones_avanzadas_hooks": {
    "descripcion": "Campos opcionales soportados por Claude Code en cada hook entry.",
    "timeout": "Tiempo máximo en segundos antes de abortar el hook (default: 60)",
    "async": "Si true, el hook no bloquea la ejecución — corre en background (default: false)",
    "once": "Si true, el hook se ejecuta solo una vez por sesión (default: false)"
  },
  "riskThresholds": {
    "allow": 0.35,
    "review": 0.60,
    "confirm": 0.85
  },
  "costBudget": {
    "maxUsd": 10.0,
    "maxTokens": 500000,
    "alertAt": 0.80
  },
  "circuitBreaker": {
    "maxConsecutiveFailures": 3,
    "halfOpenCooldownMs": 300000,
    "auditThreshold": 10
  },
  "hooks": {
    "escaneo-secretos.js": {
      "event": "PreToolUse",
      "matcher": "Write|Edit",
      "description": "Bloquea escritura de archivos con secretos hardcodeados",
      "blocking": true,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "block"
    },
    "proteccion-rutas.js": {
      "event": "PreToolUse",
      "matcher": "Write|Edit",
      "description": "Previene path traversal y escritura fuera del proyecto",
      "blocking": true,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "block"
    },
    "calidad-pre-commit.js": {
      "event": "PreToolUse",
      "matcher": "Bash",
      "description": "Gate de calidad pre-commit (debug stmts, type hints, TODOs)",
      "blocking": true,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "warn"
    },
    "linea-estado.js": {
      "event": "PostToolUse",
      "matcher": "",
      "description": "Muestra linea de estado con modelo, tarea y porcentaje de contexto",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "monitor-contexto.js": {
      "event": "PostToolUse",
      "matcher": "",
      "description": "Alerta cuando el contexto supera umbrales de saturacion (65% warning, 75% critical)",
      "blocking": false,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "warn"
    },
    "extraccion-aprendizajes.js": {
      "event": "PostToolUse",
      "matcher": "Bash|Write|Edit",
      "description": "Captura aprendizajes automaticamente de la actividad de la sesion",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "skip"
    },
    "sugerir-regenerar-inventario.js": {
      "event": "PostToolUse",
      "matcher": "Write|Edit|MultiEdit",
      "description": "Sugiere regenerar INVENTARIO.md cuando el agente toca agentes/, habilidades/, comandos/swl/, hooks/ o reglas/. Cooldown 30 min para evitar spam.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "degradacion-instintos.js": {
      "event": "PostToolUse",
      "matcher": "Bash|Write|Edit",
      "description": "Degrada instintos contradichos por evidencia negativa en la sesion",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "skip"
    },
    "risk-scoring.js": {
      "event": "PreToolUse",
      "matcher": "",
      "description": "Scoring de riesgo compuesto para operaciones — bloquea operaciones peligrosas",
      "blocking": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "warn"
    },
    "tracking-costos.js": {
      "event": "PostToolUse",
      "matcher": "",
      "description": "Registra tokens estimados y costo por sesion en .planning/METRICAS.md",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "inyeccion-contexto.js": {
      "event": "PostToolUse",
      "matcher": "",
      "description": "Inyecta contexto de sesion anterior automaticamente al inicio de nueva sesion",
      "blocking": false,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "skip"
    },
    "auto-consolidacion.js": {
      "event": "PostToolUse",
      "matcher": "",
      "description": "Sugiere /swl:aprender cuando hay >= 24h y >= 5 sesiones nuevas sin consolidar (patrón autoDream)",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "skip"
    },
    "auto-background.js": {
      "event": "PreToolUse",
      "matcher": "Bash",
      "description": "Sugiere run_in_background para comandos lentos (npm install, cargo build, docker build, etc.)",
      "blocking": false,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "resumen-sesion.js": {
      "event": "Stop",
      "matcher": "",
      "description": "Imprime resumen de sesión SWL al terminar: agentes, skills, comandos, tokens y costo",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "actualizar-perfil-usuario.js": {
      "event": "Stop",
      "matcher": "",
      "description": "Detecta señales de corrección/preferencia del usuario y acumula un dirty-bit en .planning/perfil-usuario/. Emite nudge a perfilador-usuario-swl cuando cruza el umbral (default 3 señales).",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "metricas-evolucion.js": {
      "event": "Stop",
      "matcher": "",
      "description": "Consolida métricas del ciclo de evolución (nudges accionados/pendientes, instintos, fallos de agentes, evoluciones aplicadas/revertidas) y actualiza .planning/evolucion/metricas.json con health_score compuesto. Dispara escalamiento a alertas persistentes si >=5 nudges del mismo tipo ignorados en 14d.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "rotar-audit-auto.js": {
      "event": "Stop",
      "matcher": "",
      "description": "Rotación automática de logs de auditoría (.planning/audit.jsonl y audit-merkle.jsonl) cuando superan 5 MB. Invoca scripts/rotar-audit-logs.js con retención de 30 días, comprime a .gz mensual y preserva cadena Merkle. Desactivable con SWL_AUDIT_ROTATE_OFF=1. Configurable con SWL_AUDIT_ROTATE_UMBRAL_MB y SWL_AUDIT_ROTATE_DIAS. Cooldown de 6 horas para evitar ejecución repetida.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "auto-evolucion.js": {
      "event": "SubagentStop",
      "matcher": "",
      "description": "Registra cada terminación de subagente SWL en .planning/auto-evolucion/agentes.jsonl y emite nudge a /swl:evolucionar cuando un agente acumula fallos o volumen de runs (ventana 14 días, throttle 24h).",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "telemetria-agentes.js": {
      "event": "PostToolUse",
      "matcher": "Agent",
      "description": "Registra traza OTLP-lite por cada invocación de agente SWL en .planning/traces/",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "audit-trail.js": {
      "event": "PostToolUse",
      "matcher": "",
      "description": "Registra cada tool call en .planning/audit.jsonl para auditoría y cumplimiento",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "registro-turnos.js": {
      "event": "PostToolUse",
      "matcher": "",
      "description": "Persiste cada turn en .planning/sessions/{id}/turns.jsonl con sanitización PII (OPT-IN: SWL_REGISTRO_TURNOS=1)",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "agente-lifecycle.js": {
      "event": "SubagentStop",
      "matcher": "",
      "description": "Emite eventos de ciclo de vida al event-bus y actualiza execution-state al finalizar cada agente SWL",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "grafo-contexto.js": {
      "event": "PreToolUse",
      "matcher": "Glob|Grep|Read",
      "description": "Inyecta resumen del grafo de dependencias SWL antes de búsquedas de archivos — reduce tool calls ~71x. Opt-in: silencioso si .planning/graph.json no existe.",
      "blocking": false,
      "async": false,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "calidad-typescript.js": {
      "event": "PreToolUse",
      "matcher": "Bash",
      "description": "Verifica calidad TypeScript en archivos staged antes de git commit: any explícito, @ts-ignore sin justificación, double cast, tsc --noEmit",
      "blocking": true,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "warn"
    },
    "clasificador-mensajes.js": {
      "event": "UserPromptSubmit",
      "matcher": "",
      "description": "Clasifica intención del mensaje del usuario e inyecta hints de routing para el orquestador (decisión, bug, requisito, arquitectura, etc.)",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "graph-update.js": {
      "event": "PostToolUse",
      "matcher": "Write|Edit",
      "description": "Actualiza el grafo de code-review-graph automáticamente después de cada modificación de archivo",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "preservar-estado-pre-compact.js": {
      "event": "PreCompact",
      "matcher": "",
      "description": "Preserva execution-state.json y task-queue.json antes de compactación de contexto para asegurar continuidad del plan",
      "blocking": false,
      "maxConsecutiveFailures": 3,
      "degradeOnFailure": "skip"
    },
    "check-update.js": {
      "event": "UserPromptSubmit",
      "matcher": "",
      "description": "Detecta actualizaciones disponibles de swl-ses comparando versión local vs npm registry (throttled 24h)",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "guardrail-modelo.js": {
      "event": "PreToolUse",
      "matcher": "Task|Agent",
      "description": "Guardrail semántico observacional: registra subagentes que podrían ejecutarse con un modelo menos costoso. Opt-in: SWL_GUARDRAIL_MODELO=1. Modo observacional — nunca bloquea.",
      "blocking": false,
      "async": false,
      "optIn": "SWL_GUARDRAIL_MODELO",
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "notificacion-sesion-stop.js": {
      "event": "Stop",
      "matcher": "",
      "description": "Al terminar un turno con >=10 tool calls envía al gateway una notificación con contexto: modelo, llamadas, tokens, costo, archivos modificados y último tramo del transcript. Opt-in: requiere gateway habilitado en manifiestos/gateway-config.json. Opt-out: SWL_NOTIFICAR_STOP=0.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "captura-feedback-usuario.js": {
      "event": "UserPromptSubmit",
      "matcher": "",
      "description": "Detecta correcciones explícitas del usuario (no hagas X, prefiero Y, recuerda Z, nunca W) y las encola en .planning/evolucion/feedback-queue.jsonl para consumo por perfilador-usuario-swl y el ciclo AGP. Patrones regex en español e inglés. Opt-out: SWL_CAPTURAR_FEEDBACK=0.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "inbox-aviso.js": {
      "event": "UserPromptSubmit",
      "matcher": "",
      "description": "Avisa cuando hay comandos pendientes en .planning/inbox/ enviados desde canales externos (Telegram vía gateway con relay). Inyecta additionalContext para que Claude sugiera ejecutar /swl:inbox. Opt-out: SWL_INBOX_AVISO=0.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "aiisms-detector.js": {
      "event": "PostToolUse",
      "matcher": "Write|Edit|MultiEdit",
      "description": "Ejecuta detector portable Python contra archivos .md recién modificados y emite nudge a .planning/evolucion/nudges.jsonl si encuentra al menos un AI-ism P0. No bloquea. Requiere Python 3.10+. Respeta auto-referencia (habilidades/estilo-sin-ai-isms/), .planning/, temp/, node_modules/. Opt-out: SWL_AIISMS_HOOK=0.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "notificacion-telegram.js": {
      "event": "Stop",
      "matcher": "",
      "description": "Envía notificación Telegram al terminar un turno. Muestra último mensaje del asistente, proyecto y estado. Best-effort: siempre exit 0. Requiere ~/.claude/notifications/.env con TELEGRAM_BOT_TOKEN y TELEGRAM_CHAT_ID. Opt-out: SWL_NOTIFICACIONES_TELEGRAM=0.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "notificacion-telegram-notification.js": {
      "event": "Notification",
      "matcher": "",
      "description": "Envía notificación Telegram cuando Claude espera respuesta del usuario (permisos, idle, atención requerida). Best-effort: siempre exit 0. Comparte implementación con notificacion-telegram.js. Opt-out: SWL_NOTIFICACIONES_TELEGRAM=0.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "notificacion-telegram-subagent.js": {
      "event": "SubagentStop",
      "matcher": "",
      "description": "Envía notificación Telegram cuando un subagente termina su turno. Best-effort: siempre exit 0. Comparte implementación con notificacion-telegram.js. Opt-out: SWL_NOTIFICACIONES_TELEGRAM=0.",
      "blocking": false,
      "async": true,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    },
    "auto-restaurar-settings.js": {
      "event": "SessionStart",
      "matcher": "",
      "description": "Al inicio de cada sesión verifica que ~/.claude/settings.json contiene los hooks SWL registrados en ~/.claude/notifications/baseline-hooks.json. Si falta alguno, los restaura preservando todos los hooks ajenos al baseline. Backup obligatorio antes de cada modificación. Opt-out: SWL_NOTIFICACIONES_TELEGRAM=0.",
      "blocking": false,
      "async": false,
      "maxConsecutiveFailures": 5,
      "degradeOnFailure": "skip"
    }
  }
}
