---
name: notificaciones-multicanal
description: Sistema de notificaciones para el agente notificador-swl. Cubre configuración de canales (desktop, Telegram, WhatsApp, email, webhook), formato de mensaje por canal, priorización de eventos, rate limiting, templates, integración con claude-notifications-go y ejemplos de config.json.
version: "1.0.0"
herramientasPermitidas: [Read, Bash]
evolvable: true  # default para skill estandar
exclusiones:
  - "No cargar para notificaciones push del navegador al usuario final (Web Push API, PWA notifications) — para notificaciones al usuario en el frontend cargar `frontend-avanzado`."
  - "No cargar para alertas de monitoreo de sistemas en producción (Prometheus Alertmanager, PagerDuty, OpsGenie) — para alerting de observabilidad cargar `monitoring-alertas`."
  - "No cargar para envío masivo de correos de marketing o transaccionales a usuarios finales (SendGrid, Mailchimp, SES para millones de destinatarios) — para email marketing cargar el skill del proveedor correspondiente."
  - "No cargar para notificaciones en tiempo real dentro de la app de usuario (WebSockets, SSE para actualizar la UI) — para realtime en el cliente cargar `frontend-avanzado`."
---
# Notificaciones Multicanal — notificador-swl

## Cuándo NO cargar

- La tarea es notificaciones push del navegador al usuario final (Web Push, PWA): cargar `frontend-avanzado`.
- La tarea es alerting de monitoreo de sistemas (Prometheus Alertmanager, PagerDuty): cargar `monitoring-alertas`.
- La tarea es envío masivo de correos a usuarios finales (marketing, transaccional a millones): cargar el skill del proveedor de email.
- La tarea es actualizar la UI en tiempo real vía WebSockets o SSE: cargar `frontend-avanzado`.

## Visión General

El sistema de notificaciones multicanal permite que los agentes SWL comuniquen
eventos importantes al humano a través de múltiples canales, priorizando según
la urgencia y respetando el tiempo de atención del receptor.

El binario `claude-notifications-go` actúa como broker central:
recibe eventos via stdin (JSON) o HTTP local y los enruta al canal apropiado.

```
Agente SWL
    |
    v
claude-notifications-go  --> Desktop (nativo OS)
    |                    --> Telegram Bot
    |                    --> WhatsApp Business API
    |                    --> Email (SMTP)
    +-------------------> Webhook HTTP
```

---

## Reglas Obligatorias

1. **NUNCA hardcodear tokens en config.json** — usar siempre variables de entorno (`${TELEGRAM_BOT_TOKEN}`).
2. **La notificación es best-effort, NO bloqueante** — si falla, el hook NO debe fallar.
3. **SIEMPRE incluir `proyecto` en el payload** — sin él, es imposible filtrar en el historial.
4. **NUNCA usar prioridad `critico` para eventos rutinarios** — causa fatiga de alertas.
5. **SIEMPRE configurar horario No Molestar** — interrupciones fuera de horario son inaceptables.
6. **Canal email: máximo 1 vez por hora** — no para eventos de alta frecuencia.

---

## Priorización de Eventos

| Nivel | Canales activados | Ejemplos |
|-------|------------------|---------|
| `critico` | Todos los canales simultáneamente | Error irreversible, pérdida de datos |
| `urgente` | Desktop + Telegram (simultáneo) | human-action bloqueante |
| `alta` | Desktop + Telegram (secuencial) | checkpoint decision |
| `normal` | Canal primario únicamente | human-verify, progreso |
| `baja` | Solo log local | Métricas, telemetría interna |

### Mapeo evento a prioridad

```jsonc
{
  "mapeo": {
    "checkpoint.human-action":         "urgente",
    "checkpoint.decision":             "alta",
    "checkpoint.human-verify":         "normal",
    "error.critico":                   "critico",
    "error.recuperable":               "alta",
    "fase.completada":                 "normal",
    "alerta.seguridad":                "critico"
  }
}
```

---

## Integración con claude-notifications-go

### Envío desde hook (stdin)

```javascript
// hooks/notify.js
const { execSync } = require('child_process');

function notificar(evento) {
  const payload = JSON.stringify(evento);
  try {
    execSync('claude-notifications-go send', {
      input: payload,
      stdio: ['pipe', 'ignore', 'ignore'],
      timeout: 5000,
    });
  } catch {
    // Fallo silencioso — la notificación no es crítica para el flujo
  }
}

notificar({
  tipo: 'checkpoint.human-verify',
  proyecto: process.env.PROJECT_NAME,
  titulo: 'Slice 1 completado',
  resumen: 'CRUD de usuarios implementado y testeado.',
  accion_requerida: true,
});
```

### Envío via HTTP local

```bash
curl -s -X POST http://localhost:19999/notify \
  -H "Content-Type: application/json" \
  -d '{
    "tipo": "checkpoint.decision",
    "proyecto": "sigaf-backend",
    "titulo": "Decision requerida: motor de base de datos",
    "prioridad": "alta"
  }'
```

### Comandos de gestión

```bash
claude-notifications-go start --config ~/.claude/notifications/config.json
claude-notifications-go status
claude-notifications-go test --canal telegram
claude-notifications-go log --ultimas 20
claude-notifications-go flush-queue
```

---

## Anti-patrones

- Enviar notificaciones de prioridad `critico` para eventos rutinarios (fatiga de alertas)
- Hardcodear tokens en `config.json` en lugar de usar variables de entorno
- No configurar el horario No Molestar (interrupciones fuera de horario)
- Fallar el hook si la notificación falla (la notificación es best-effort)
- Usar el canal email para eventos de alta frecuencia
- Omitir `proyecto` en el payload

---

Para configuración completa de canales (config.json), formato de mensaje por canal (Desktop, Telegram, WhatsApp, Email, Webhook), rate limiting, supresión de duplicados, templates de mensajes y flujo de diagnóstico, ver [recursos/configuracion-y-templates.md](recursos/configuracion-y-templates.md).

## Gotchas / Errores comunes no obvios

**El hook falla cuando `claude-notifications-go` no está en el PATH del proceso de Claude Code aunque esté instalado globalmente**: Claude Code ejecuta hooks con un PATH reducido (sin `~/.local/bin` ni `/usr/local/bin` en algunas configuraciones de shell). Si el binario está instalado fuera del PATH del sistema base, el `execSync('claude-notifications-go send')` lanza `ENOENT` y, si el catch está vacío como se recomienda, el hook silencia el error sin notificar nada. Causa: el PATH del proceso de hook depende del shell y la configuración del usuario, no del PATH interactivo. Fix: usar la ruta absoluta del binario: `which claude-notifications-go` para obtenerla y configurarla como variable en el hook, o añadir el directorio de instalación a `PATH` en el archivo de perfil del shell que Claude Code hereda.

**Los mensajes de Telegram con más de 4,096 caracteres son silenciosamente truncados por la API de Telegram sin error**: si el campo `resumen` del payload incluye stack traces o diffs largos, la API retorna `ok: true` pero el usuario recibe el mensaje cortado sin ningún indicador visual de que falta contenido. Causa: la API de Telegram Bot tiene un límite de 4,096 caracteres por mensaje en modo texto y 1,024 en modo caption. Fix: en el hook, truncar el `resumen` a 3,500 caracteres antes de enviar y agregar `"\n... [mensaje truncado]"` si se supera el límite. Alternativamente, enviar como archivo adjunto `.txt` para mensajes largos.

**El canal email falla silenciosamente cuando el servidor SMTP requiere TLS pero `claude-notifications-go` está configurado con `port: 25` (plaintext)**: la conexión se establece pero el servidor SMTP rechaza los comandos de autenticación sin TLS. El error del servidor (`534 Authentication required`) llega como respuesta SMTP pero `claude-notifications-go` lo registra en su log local, no lo propaga al hook. Causa: el puerto 25 es para relay servidor-a-servidor sin autenticación; los usuarios deben usar 587 (STARTTLS) o 465 (SSL/TLS). Fix: configurar `port: 587` con `tls: starttls` o `port: 465` con `tls: ssl` en `config.json` según el proveedor SMTP. Verificar con `claude-notifications-go test --canal email` que devuelve éxito.

**La prioridad `critico` activa todos los canales simultáneamente, y si el canal email tiene rate limiting de 1/hora, el segundo evento crítico en menos de una hora llega sin el correo aunque sí por Telegram y desktop**: el usuario recibe la notificación pero asume que "falta el email" es un fallo del sistema, cuando en realidad es el rate limiting configurado. Causa: el rate limiting por canal se aplica independientemente de la prioridad del evento. Fix: excluir el canal email del rate limiting para eventos de prioridad `critico`, ya que son raros por definición (si son frecuentes, el problema es el uso incorrecto de la prioridad). Documentar en el runbook qué canales tienen rate limiting para evitar confusión operacional.
