Founding Member: $499/mes de por vida
Calidad de vida

Barrendero de procesos huérfanos

Dos hooks (ganchos de automatización) para tu Mac: uno barre al abrir y cerrar sesión los procesos de trabajo que tu asistente dejó huérfanos (ffmpeg, navegador sin pantalla, servidor de desarrollo) y otro avisa antes de lanzar un comando con fuente infinita sin límite de tiempo.

HookPremiumCalidad de vidaenergia y sesion

🌱 Empieza aquí · Barrendero de procesos huérfanos

Esta semilla le pone a tu asistente dos ayudantes. El Barrendero cierra, al abrir y al cerrar cada sesión, los procesos de trabajo que quedaron vivos sin dueño (videos de prueba, navegadores sin pantalla, servidores de desarrollo). La Alarma le avisa a tu asistente antes de lanzar un comando que nunca terminaría solo.

Para instalarla

Abre esta carpeta con Claude Code y dile a tu asistente:

"Siembra esta semilla 🌱"

Con eso basta de tu parte. Tu asistente hace todo lo demás y al final te dice cómo comprobar que quedó funcionando. Vas a ver algunas palabras en inglés en la pantalla; ni caso, él te guía.

¿Otras formas de pedírselo? "instala esta semilla", "pon a funcionar el barrendero", "haz el setup de esto". Te entiende igual.


Para el asistente que siembra 🤖

Este componente son dos hooks (ganchos de automatización) de Claude Code más un ayudante opcional:

  • kernel/barrendero-procesos-huerfanos.sh: se registra en SessionStart y SessionEnd. Solo actúa en macOS; en Linux y Windows sale sin hacer nada.
  • kernel/alarma-fuente-infinita.sh: se registra en PreToolUse con matcher Bash. Funciona en macOS, Linux y Windows con Git Bash. Necesita jq.
  • kernel/carpeta-top.py: lo llama el Barrendero; no se registra. Necesita python3.
  • kernel/hooks.ejemplo.json: el bloque de registro.

Corre todos los comandos desde esta carpeta (la de la semilla). No registres nada más allá de lo que dice este documento.

1. Revisa los requisitos

for h in bash jq python3 ps pgrep lsof; do command -v "$h" >/dev/null && echo "OK $h" || echo "FALTA $h"; done; uname

Salida esperada en macOS: seis líneas OK y Darwin. Si falta jq, la Alarma no podrá leer los comandos (sale callada); instálalo con el gestor de paquetes de la persona (por ejemplo brew install jq) o avísale. Si falta python3, todo funciona salvo el nombre de la carpeta de la nube.

2. Copia los scripts

macOS / Linux / Windows con Git Bash:

DESTINO="$HOME/.claude/hooks"
mkdir -p "$DESTINO"
cp kernel/barrendero-procesos-huerfanos.sh kernel/alarma-fuente-infinita.sh kernel/carpeta-top.py "$DESTINO/"
chmod +x "$DESTINO/barrendero-procesos-huerfanos.sh" "$DESTINO/alarma-fuente-infinita.sh" "$DESTINO/carpeta-top.py"

Windows con PowerShell (solo tiene sentido para la Alarma; el Barrendero no actúa fuera de macOS):

$Destino = "$HOME\.claude\hooks"
New-Item -ItemType Directory -Force -Path $Destino | Out-Null
Copy-Item kernel\barrendero-procesos-huerfanos.sh, kernel\alarma-fuente-infinita.sh, kernel\carpeta-top.py -Destination $Destino

En Windows los ganchos se ejecutan con bash, así que la persona necesita Git Bash y jq.

carpeta-top.py debe quedar en la misma carpeta que el Barrendero: él lo busca ahí.

3. Registra los ganchos en settings.json

El archivo es ~/.claude/settings.json. Si ya tiene una sección hooks, hay que fusionar sin borrar lo que exista. Este bloque hace un respaldo y agrega las tres entradas de kernel/hooks.ejemplo.json al final de cada lista. Si los ganchos ya estaban registrados (por ejemplo, porque el bloque ya se corrió antes), no agrega nada para no duplicarlos:

AJUSTES="$HOME/.claude/settings.json"
EJEMPLO="kernel/hooks.ejemplo.json"
mkdir -p "$HOME/.claude"
[ -f "$AJUSTES" ] || echo '{}' > "$AJUSTES"
if jq -e '[.hooks[]?[]?.hooks[]?.command] | any(test("barrendero-procesos-huerfanos|alarma-fuente-infinita"))' "$AJUSTES" >/dev/null 2>&1; then
  echo "Ya estaban registrados; no se agregó nada."
else
  cp "$AJUSTES" "$AJUSTES.respaldo-barrendero"
  jq -s '.[0] as $a | .[1] as $b
    | $a | .hooks = (reduce ($b.hooks | keys[]) as $k (($a.hooks // {}); .[$k] = ((.[$k] // []) + $b.hooks[$k])))' \
    "$AJUSTES" "$EJEMPLO" > "$AJUSTES.nuevo" && mv "$AJUSTES.nuevo" "$AJUSTES"
fi
jq -e . "$AJUSTES" >/dev/null; echo "exit=$?"

Salida esperada: exit=0 (y, si ya estaban, la línea Ya estaban registrados; no se agregó nada.). Si algo sale mal, el original quedó en ~/.claude/settings.json.respaldo-barrendero. Si no hay jq, abre el archivo y agrega a mano el contenido de kernel/hooks.ejemplo.json dentro de hooks, sin reemplazar las listas que ya existan. Los ganchos nuevos se cargan en la siguiente sesión.

Los tiempos límite del bloque son los del original: 15 segundos para el Barrendero (en el peor caso espera 5 s de signos vitales y 5 s entre olas de cierre) y 5 segundos para la Alarma.

4. Opcional: la carpeta de tu nube

Si la persona sincroniza una carpeta con la nube y quiere que el aviso de sospechoso nombre la carpeta culpable, define estas variables donde su sesión las herede (por ejemplo en la sección env de ~/.claude/settings.json):

  • BARRENDERO_NUBE → <TU-CARPETA-EN-LA-NUBE>: la ruta completa de la carpeta sincronizada (en macOS los clientes de nube suelen vivir dentro de ~/Library/). Puede empezar con ~/; el Barrendero lo cambia por la carpeta de la persona.
  • BARRENDERO_NUBE_PROCESOS → expresión regular con los nombres del proceso que sincroniza. Por defecto fileproviderd. Si su cliente de nube tiene proceso propio, agrégalo: fileproviderd|<NOMBRE-DEL-CLIENTE-DE-NUBE>.

Sin BARRENDERO_NUBE, el aviso dice sin carpeta configurada y todo lo demás funciona igual.

Otras variables, también opcionales: BARRENDERO_LOG_DIR (carpeta de la bitácora, por defecto ~/.claude/hooks/logs) y BARRENDERO_CARPETA_TOP (ruta de carpeta-top.py si lo guardas en otro lado).

5. Verificación post-siembra (obligatoria)

a) Los archivos quedaron en su lugar:

DESTINO="$HOME/.claude/hooks"
ls -la "$DESTINO/barrendero-procesos-huerfanos.sh" "$DESTINO/alarma-fuente-infinita.sh" "$DESTINO/carpeta-top.py"; echo "exit=$?"
jq '[.hooks.SessionStart[]?.hooks[]?.command, .hooks.SessionEnd[]?.hooks[]?.command, .hooks.PreToolUse[]?.hooks[]?.command] | map(select(test("barrendero|alarma-fuente")))' "$HOME/.claude/settings.json"

Salida esperada: tres líneas con los archivos (con permiso x), exit=0, y una lista con tres comandos: dos del Barrendero y uno de la Alarma.

b) La Alarma avisa y calla cuando debe (simula el evento que manda Claude Code):

ALARMA="$HOME/.claude/hooks/alarma-fuente-infinita.sh"
echo '{"tool_name":"Bash","tool_input":{"command":"ffmpeg -f lavfi -i anullsrc -shortest prueba.wav"}}' | bash "$ALARMA"; echo "exit=$?"
echo '{"tool_name":"Bash","tool_input":{"command":"ffmpeg -f lavfi -i anullsrc -t 5 prueba.wav"}}' | bash "$ALARMA"; echo "exit=$?"

Salida esperada: el primero imprime un JSON {"systemMessage":"⏱️ Este comando usa una FUENTE INFINITA…"} y exit=0; el segundo (ya trae -t 5) no imprime nada más que exit=0.

c) El Barrendero ve lo que cerraría, sin cerrar nada (solo macOS):

BARRENDERO="$HOME/.claude/hooks/barrendero-procesos-huerfanos.sh"
bash "$BARRENDERO" --dry-run; echo "exit=$?"

Salida esperada en macOS: DRY-RUN: 0 candidatos a barrer (o líneas DRY-RUN mataría: <pid>|<edad>|<comando> si de verdad hay huérfanos viejos) y exit=0. En Linux o Windows no imprime nada y da exit=0: es lo correcto. Si aparecen candidatos, muéstraselos a la persona antes de la siguiente sesión, porque ahí sí se cerrarían.

d) Prueba con señuelo (solo macOS, opcional pero recomendada). Crea un proceso huérfano falso con nombre de herramienta de trabajo y confirma que el Barrendero lo reconoce. Usa --dry-run, así que no cierra nada; el bloque limpia el señuelo al final:

BARRENDERO="$HOME/.claude/hooks/barrendero-procesos-huerfanos.sh"
SENUELO="$(mktemp -d)"
cp /bin/sleep "$SENUELO/ffmpeg"
( "$SENUELO/ffmpeg" 120 & )
sleep 3
bash "$BARRENDERO" --dry-run --no-candado4 --min-age-secs 1 | grep "$SENUELO/ffmpeg"; echo "exit=$?"
pkill -f "$SENUELO/ffmpeg 120"; rm -rf "$SENUELO"

Salida esperada: una línea DRY-RUN mataría: <pid>|<edad>|…/ffmpeg 120 y exit=0. Las opciones --no-candado4 y --min-age-secs 1 existen solo para pruebas: apagan la condición de "más viejo que tu sesión" y bajan la edad mínima para que un señuelo recién creado califique. Nunca las pongas en el registro de settings.json.

Cuando las cuatro pruebas pasen, avísale a la persona en una línea qué gana con esto.


✅ ¿Cómo sé que funcionó?

Cuando tu asistente esté por correr una prueba de video con una fuente que nunca termina, recibe un aviso para que le ponga un límite de tiempo antes de lanzarla (el aviso no bloquea: tu asistente decide). Y si alguna vez queda un proceso de trabajo colgado después de cerrar una sesión, el Barrendero lo cierra al abrir o cerrar la siguiente. Al abrir sesión, tu asistente recibe el aviso ("🧹 Barrendero: maté proceso huérfano pid …") y puede contártelo. Si algo estaba produciendo, lo perdona y lo deja en paz. Si un proceso que no conoce quema CPU por más de una hora, lo señala con 👀 y no lo toca. Todo queda anotado en ~/.claude/hooks/logs/barrendero.log.

¿Quieres implementarla con acompañamiento?

Agenda una asesoría directa con JP y aterrízala en tu caso · desde $600 MXN.

Agendar una asesoría