Watch mode over a messaging chat. Arms a watcher when a turn closes waiting on a reply from a third party, and reads what is pending when work on an arm resumes. Use it when sending a message that expects an answer, when the operator asks to read a chat, or when starting work on an arm with a live chat channel.
Installs into .claude/skills of the current project.
Are you the author of Wa Guardia?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/carloscape-wa-guardia)
---
name: wa-guardia
description: "Watch mode over a messaging chat. Arms a watcher when a turn closes waiting on a reply from a third party, and reads what is pending when work on an arm resumes. Use it when sending a message that expects an answer, when the operator asks to read a chat, or when starting work on an arm with a live chat channel."
---
# Guardia de chat
Esperar una respuesta y acordarse de ir a verla son dos cosas distintas. La
segunda es disciplina, y la disciplina se salta bajo carga: el mensaje llega,
nadie lo mira, y el operador se entera horas despues. La guardia convierte esa
espera en un reflejo con condicion de disparo escrita.
## Quien es el dueño de que (leelo antes de tocar nada)
**`wa-sin-respuesta.py` es el dueño de la vigilancia durable.** Corre como timer
de systemd, fuera de cualquier sesion, y alerta por correo cuando un mensaje de
cliente pasa el umbral sin respuesta. Si un canal importa de verdad, va en la
seccion `vigilancia` de `company/config/wa-puentes.json`. Una sesion no es
infraestructura: se cierra, y con ella se apaga cualquier vigilancia colgada de
ella.
**Este skill es la capa de sesion**, y contesta otra pregunta: *ponme al dia
ahora*. Sin umbral, sin alerta, sin sobrevivir al cierre. No sustituye al vigia
y no debe convertirse en un segundo hogar del mismo concepto.
| | Vigia (`wa-sin-respuesta.py`) | Guardia de sesion (`wa-guardia.py`) |
|---|---|---|
| Pregunta | ¿se quedo alguien sin respuesta? | ¿que me deben contestar ahora? |
| Vive en | timer de systemd | la sesion viva |
| Avisa por | correo, al pasar el umbral | linea en el chat, al instante |
| Sobrevive al cierre | si | no |
| Insiste | si, por peldaños | no, es una foto |
**El vigia RE-ESCALA, no avisa una sola vez.** El anti-repeticion va por clave,
y la clave lleva pegado el peldaño de espera (`escalon` en
`wa-sin-respuesta.py`): sube en 1 h, 4 h y 24 h, y de ahi uno por dia. Al cruzar
un peldaño la clave cambia y el mismo silencio vuelve a contar como nuevo. Antes
la clave era el id pelado, asi que un pendiente avisado una vez se callaba para
siempre mientras el cliente no volviera a escribir: se encontro un chat con 7
dias de silencio saliendo como `(ya avisado)` en cada vuelta del timer.
**Un mensaje de ausencia no arranca el reloj.** `no_espera` une los dos motivos
por los que un entrante no deja a nadie esperando: cierra la conversacion
(`es_acuse`) o lo escribio una maquina (`es_auto_wa`, el gemelo de las
`FRASES_AUTO` del correo). El ancla se poda con esa puerta, porque un away
message de WhatsApp Business ronda los cien caracteres y `es_acuse` exige menos
de 25: quedaba de ancla y la alerta reportaba SU edad en vez de la de la
pregunta viva.
**La logica compartida se importa, no se copia.** El filtro de acuses (que un
"gracias" no es un pendiente) y la ruta de los puentes viven en el vigia y en su
config; `wa-guardia.py` los importa. Dos copias de esa regla se separan con el
primer ajuste, y entonces los dos mecanismos empiezan a contradecirse.
## Cuando se arma (condicion, no capricho)
**Se arma cuando el turno cierra con algo pendiente de un tercero.** Esa es toda
la regla. Casos tipicos: mande un mensaje que pide respuesta, mande un correo que
espera acuse, deje una pregunta abierta en un grupo, subi algo que alguien tiene
que revisar.
Y el primer movimiento no es el Monitor, es preguntar **si ese chat ya tiene
vigilancia durable**. Si no la tiene, el arreglo de fondo es agregarlo a la
config del vigia; el Monitor solo cubre el rato de la sesion. Poner un parche de
sesion sobre un canal que deberia estar vigilado siempre es tratar el sintoma.
`wa-guardia.py` lo dice en cada corrida, en la linea `vigilancia durable:`.
**No se arma** cuando no hay espera. Un watcher permanente sin nada que esperar
es ruido que cuesta tokens y entrena al operador a ignorar las notificaciones,
que es peor que no tenerlas. La directiva del operador, 2026-08-04: *"al menos
cuando esperemos algo, si no pues no"*.
Antes de cerrar un turno, la pregunta es una: **¿queda alguien a quien le toca
contestar?** Si si, se arma antes de responder. Si no, no.
## Cuando se lee (sin que lo pidan)
Al **empezar a trabajar con un arm** que tiene canal de chat vivo, y siempre que
el operador pida leer el chat, lo primero es el reporte de pendientes. Entrar a
trabajar sin saber que llego mientras tanto es arrancar a ciegas, y el riesgo
concreto es contestar algo que ya se resolvio o pedir algo que ya mandaron.
## Mecanismo
`~/.claude/scripts/wa-guardia.py` lee la base del puente en modo **solo lectura**.
Nunca escribe ni manda.
# que me deben contestar (lo entrante despues de MI ultimo envio)
python3 ~/.claude/scripts/wa-guardia.py <chat_jid> [--puente soporte|personal]
# ventana fija, para auditar hacia atras
python3 ~/.claude/scripts/wa-guardia.py <chat_jid> --horas 24
# vigilancia continua: una linea por mensaje nuevo, no termina
python3 ~/.claude/scripts/wa-guardia.py <chat_jid> --vigilar --intervalo 60
El modo por omision corta **desde mi ultimo envio**, no desde una ventana de
horas fijada a mano. Una ventana siempre queda corta (se pierde lo de anteayer) o
larga (repite lo ya contestado); "desde que hable yo" es la unica linea que
responde de verdad a "que me deben".
Para vigilar, colgarlo de un `Monitor` con `persistent: true`. Cada mensaje nuevo
llega como notificacion sin tener que sondear.
## Reglas de uso
1. **Valida contra un caso conocido antes de confiar en el silencio.** "Sin
mensajes nuevos" y "la consulta esta rota" se ven igual. Corre el modo
`--horas` sobre un periodo donde SI hubo mensajes: si los trae, el silencio es
real. Sin ese control positivo no se reporta "no hay nada".
2. **El JID del chat vive en la memoria del arm, no aqui.** Este skill es
generico; que grupo vigilar es dato del cliente.
3. **Elige el puente correcto.** Un chat de cliente vive en el puente de soporte;
el personal es del operador. Ver `feedback_support_channel_not_personal`.
4. **La guardia avisa, no contesta.** Un mensaje entrante no se responde solo:
se reporta al operador con quien escribio y que dijo. Contestar en automatico
a un cliente no esta autorizado por existir un watcher.
5. **Bajala cuando llego lo que esperabas.** `TaskStop` sobre el monitor. Una
guardia que sobrevive a su espera es la que enseña a ignorar avisos.
## Como sabe el hook que "mande algo"
`d__stop__wa-guardia.py` (Stop, regla `FLOW.wa-guardia-on-pending`) NO se fia de
`messages.is_from_me`. Esa columna solo dice "salio de esta cuenta", y eso
incluye lo que el operador escribe desde su telefono: pedir guardia por un
mensaje que el mando a mano es un falso positivo, y los falsos positivos enseñan
a ignorar el aviso, que es peor que no tenerlo.
La fuente es la tabla **`api_sends`**, que el puente escribe solo cuando el
envio paso por su API, o sea cuando lo mando el agente. Un puente sin esa tabla
no puede distinguir agente de humano y por diseño **no aporta candidatos**:
callar es correcto, inventar avisos desde `is_from_me` es el bug que esto
arregla. Hoy la tiene el puente de soporte; el personal no.
No cuentan como espera los latidos de salud (contenido `latido-...`).
## Que NO ve
Solo ve lo que el puente haya guardado. Un grupo sin mensajes no tiene renglon en
la tabla `chats` y es invisible, y los nombres de contacto no estan en la base:
la base guarda identificadores, no personas. Para saber quien es quien hay que
preguntar al grupo o mirar el telefono. Ver
`feedback_identifier_is_not_a_person`.