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

Candado para archivos que tienes abiertos

Hook para Claude Code en macOS que frena a tu asistente cuando va a escribir por fuera un archivo que tienes abierto en Word, Excel, PowerPoint, Vista Previa u otra app de documentos, porque la app lo pisaría con su propia copia al guardar.

HookPremiumCalidad de vidaguardrails personales

🌱 Empieza aquí · Candado para archivos que tienes abiertos

Esta semilla le pone un candado a tu asistente: si va a cambiar un archivo que tú tienes abierto en ese momento en Word, Excel, PowerPoint, Vista Previa, Pages, Numbers o Keynote, se detiene antes de escribirlo. Así no pierdes el cambio cuando la app guarde su propia copia encima. En vez de escribir por fuera, tu asistente hace el cambio dentro de la app o te pide que cierres el archivo primero.

Funciona en Claude Code sobre macOS. En otros sistemas no puede ver qué tienes abierto (lo explicamos abajo).

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 técnico 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 el candado de archivos abiertos", "haz el setup de esto". Te entiende igual.


Para el asistente que siembra 🤖

Este componente es un hook (gancho de automatización) del evento PreToolUse de Claude Code: corre justo antes de cada herramienta Write, Edit, MultiEdit, NotebookEdit y Bash. Lee el evento por stdin (entrada estándar) y responde así:

  • Frena (código de salida 2, con la explicación en stderr) si el archivo destino está abierto en una app.
  • Avisa (código 0 con additionalContext) si escribes un documento de Office o iWork que vive en la carpeta de nube de Office de la persona y que no está abierto.
  • Calla (código 0 sin salida) en todo lo demás. Ante cualquier error propio, deja pasar.

Para saber qué está abierto usa tres capas, todas de macOS: AppleScript a Word, Excel y PowerPoint; el atributo de accesibilidad AXDocument de cada ventana; y lsof. Solo pregunta a las apps que ya están corriendo y nunca abre ninguna. Necesita python3 (viene con las herramientas de desarrollo de macOS; si falta, xcode-select --install).

El kernel trae dos archivos:

  • kernel/archivo-abierto-guard.py — el hook.
  • kernel/probar-archivo-abierto-guard.sh — el banco de pruebas que usarás en el paso 4.

No ejecutes el hook por tu cuenta fuera de los pasos de abajo y no lo registres en otro evento.

1. Copia el hook a la carpeta de hooks

macOS (Claude Code): corre esto desde la carpeta de la semilla.

SEMILLA="$(pwd)"
mkdir -p "$HOME/.claude/hooks"
cp "$SEMILLA/kernel/archivo-abierto-guard.py" "$HOME/.claude/hooks/archivo-abierto-guard.py"
chmod +x "$HOME/.claude/hooks/archivo-abierto-guard.py"
ls -la "$HOME/.claude/hooks/archivo-abierto-guard.py"; echo "exit=$?"

Linux o Windows: dile a la persona, con estas palabras, que aquí la semilla no sirve: "en tu sistema el candado no puede ver qué archivos tienes abiertos, así que nunca te frenaría". Las tres capas de detección dependen de macOS. Si aun así quiere el aviso de la nube de Office, la copia es la misma (en Windows con PowerShell: New-Item -ItemType Directory -Force "$HOME\.claude\hooks"; Copy-Item kernel\archivo-abierto-guard.py "$HOME\.claude\hooks\"), pero deja claro que ese aviso es lo único que hará.

2. Registra el hook en settings.json

Abre $HOME/.claude/settings.json (créalo si no existe) y agrega esta entrada dentro de hooks.PreToolUse. Si ya hay hooks de PreToolUse, suma este objeto al arreglo existente en lugar de reemplazarlo. El timeout de 10 segundos importa: el hook se organiza para responder en menos de 7.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit|NotebookEdit|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 \"$HOME/.claude/hooks/archivo-abierto-guard.py\"",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

Comprueba que quedó registrado y que el JSON sigue siendo válido:

AJUSTES="$HOME/.claude/settings.json"
python3 -m json.tool "$AJUSTES" > /dev/null && grep -q 'archivo-abierto-guard' "$AJUSTES" && echo 'REGISTRADO'

Salida esperada: REGISTRADO.

3. Aterriza la carpeta de nube de Office (opcional, recomendado si usa Office con la nube)

Cuando Word o Excel abren un archivo desde la nube de Microsoft, no contestan con una ruta de disco sino con un enlace https://d.docs.live.net/.... Para traducirlo a la carpeta local, el hook necesita saber dónde vive esa carpeta en esta Mac. Sin este dato, los archivos abiertos desde la nube no se detectan por la capa de Office y el aviso de la nube queda apagado; las otras dos capas siguen funcionando.

Busca la carpeta con la persona. En macOS, la app de sincronización de Microsoft la crea dentro de ~/Library/, con un nombre que termina en Drive- seguido del tipo de cuenta:

find "$HOME/Library" -maxdepth 2 -type d -name '*Drive-*' 2>/dev/null

Puede salir más de una (por ejemplo, la de otro servicio de nube). Pregúntale cuál es la de Microsoft. Luego escríbela en el hook instalado, en la constante RAIZ_NUBE_POR_DEFECTO (cambia <TU-CARPETA-DE-NUBE-DE-OFFICE> por la ruta completa):

RAIZ="<TU-CARPETA-DE-NUBE-DE-OFFICE>"
HOOK="$HOME/.claude/hooks/archivo-abierto-guard.py"
python3 - "$HOOK" "$RAIZ" <<'EOF'
import json, sys
ruta, raiz = sys.argv[1], sys.argv[2]
texto = open(ruta).read()
texto = texto.replace('RAIZ_NUBE_POR_DEFECTO = ""', "RAIZ_NUBE_POR_DEFECTO = " + json.dumps(raiz), 1)
open(ruta, "w").write(texto)
EOF
grep -n '^RAIZ_NUBE_POR_DEFECTO' "$HOOK"

Salida esperada: una línea con RAIZ_NUBE_POR_DEFECTO = " seguida de la ruta que escribiste. (Otra forma: la variable de entorno ARCHIVO_ABIERTO_NUBE_RAIZ, que gana sobre la constante.)

Permisos de macOS: la capa de ventanas necesita que la app de terminal donde corre Claude Code tenga el permiso de Accesibilidad (Ajustes del Sistema → Privacidad y seguridad → Accesibilidad). La primera vez que el hook le pregunte a Word, Excel, PowerPoint o a "System Events", macOS puede mostrar un aviso para permitir que la terminal los controle; pídele a la persona que acepte. Si no da los permisos, esa capa calla y el hook deja pasar (falla abierto).

4. Verificación post-siembra (obligatoria)

a) El archivo quedó en su lugar y registrado:

HOOK="$HOME/.claude/hooks/archivo-abierto-guard.py"
ls -la "$HOOK"; echo "exit=$?"
grep -q 'archivo-abierto-guard' "$HOME/.claude/settings.json" && echo 'REGISTRADO'

Salida esperada: una línea que lista el archivo, exit=0 y REGISTRADO.

b) Prueba de comportamiento con el banco de pruebas. El banco simula 30 situaciones (escribir un Excel abierto, guardar con python un Word abierto, cp, mv, rm, tee, sed -i, pandoc, soffice, leer sin escribir, el escape, cambios por AppleScript...) con archivos falsos en una carpeta temporal que borra al terminar. No toca documentos reales. Corre esto desde la carpeta de la semilla:

SEMILLA="$(pwd)"
bash "$SEMILLA/kernel/probar-archivo-abierto-guard.sh"; echo "exit=$?"

Salida esperada: 30 renglones que empiezan con OK, el renglón RESULTADO banco=archivo-abierto bien=30 mal=0 y exit=0.

c) Prueba señuelo (demuestra que el banco sí detecta un candado que no hace nada):

SEMILLA="$(pwd)"
SALIDA="$(GUARDIA="true" bash "$SEMILLA/kernel/probar-archivo-abierto-guard.sh")"; RC=$?
printf '%s\n' "$SALIDA" | tail -1; echo "exit=$RC"

Salida esperada: RESULTADO banco=archivo-abierto bien=13 mal=17 y exit=1. Si este señuelo saliera en verde, el banco no estaría probando nada.

d) Prueba en vivo en la Mac (opcional): abre un archivo de texto en TextEdit y deja la ventana abierta. Luego corre esto con la ruta de ese archivo:

ARCHIVO="<RUTA-DEL-ARCHIVO-ABIERTO-EN-TEXTEDIT>"
python3 -c 'import json,sys; print(json.dumps({"tool_name":"Write","tool_input":{"file_path":sys.argv[1]}}))' "$ARCHIVO" \
  | python3 "$HOME/.claude/hooks/archivo-abierto-guard.py"; echo "exit=$?"

Salida esperada: el mensaje [archivo-abierto] «...» está abierto en ... y exit=2. Cierra la ventana, espera unos 10 segundos (el hook recuerda la última consulta durante 8) y repite: ahora debe salir solo exit=0. Si desde la primera vez sale exit=0, revisa que la terminal tenga el permiso de Accesibilidad (paso 3): es el que usa la capa de ventanas para ver qué archivo muestra TextEdit. Da el permiso y repite.

Cuando todo dé lo esperado, avísale a la persona que ya quedó y explícale en una línea qué gana con esto.


✅ ¿Cómo sé que funcionó?

Cuando tengas un documento abierto y le pidas a tu asistente que lo cambie, ya no lo va a reescribir por debajo. Te va a decir que el archivo está abierto y va a hacer el cambio dentro de la app (en Word, Excel o PowerPoint) o te va a pedir que lo guardes y lo cierres primero. Con los archivos que no tienes abiertos, trabaja igual que siempre.

Si algún día necesitas que escriba por fuera de todos modos (por ejemplo, ya cerraste el archivo y la app no se enteró), tu asistente puede agregar a su comando de terminal (Bash) el comentario # archivo-abierto-ok: <razón> y el candado lo deja pasar. 🌱

¿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