Skip to content
Back to skills

Wa Guardia

ASecurity

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.

  • 17 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 2, 2026
ai-agentspythongovueapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add CarlosCaPe/octorato --skill wa-guardia --agent claude-code

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.

Security grade badge for Wa Guardia
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/carloscape-wa-guardia/badge)](https://www.skillsdirectory.com/skills/carloscape-wa-guardia)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.