Despliega zn-gate en todo un equipo

Pon los hooks de zn-gate en cada equipo con la configuración gestionada de cada agente: ajustes gestionados de Claude Code, hooks de empresa de Cursor y requirements.toml de Codex, y cómo comprobar una máquina.

Ver .md

Esta página es para quien prepara los portátiles de un equipo. En lugar de pedir a cada desarrollador que ejecute zn hooks install, colocas un archivo de configuración por agente en una carpeta del sistema, con tu propia herramienta para ello (gestión de dispositivos, Ansible, una imagen, un script de inicio de sesión). El agente ejecuta entonces los hooks de zn-gate para todos y, en Claude Code y Codex, también puedes impedir que usuarios y proyectos los desactiven.

zn-gate no despliega estos archivos por ti: es una barrera local, no un MDM (consulta el Resumen de Team). Todo lo que sigue funciona hoy a mano.

Los datos sobre cada agente proceden de la propia documentación de ese agente, leída el 2026-10-19; vuelve a consultarla antes de un despliegue grande, porque estos ajustes cambian. Los comandos de los hooks son los que zn hooks install escribe en una instalación de proyecto con zn-gate 1.12.0 o posterior.

Antes de empezar

  1. Instala zn-gate en cada máquina, con la misma versión en todas. Necesita Node.js 18 o posterior: npm install -g zn-gate. Hazlo primero. Un hook que no puede ejecutarse no es inocuo: Claude Code y Codex dejan pasar la llamada a la herramienta sin comprobar, y Cursor bloquea las lecturas de archivos y los prompts cuando un hook tiene failClosed.
  2. Asegúrate de que el agente encuentra zn. Los comandos de abajo llaman a zn hook <agent>, así que zn debe estar en el PATH con el que se ejecuta el agente. Las aplicaciones de escritorio no siempre reciben el PATH de tu terminal. Si no estás seguro, escribe la ruta completa (command -v zn en macOS y Linux, where zn en Windows), por ejemplo /usr/local/bin/zn hook claude-code.
  3. Pruébalo en una máquina, compruébala (ver "Comprobar una máquina" más abajo) y luego despliega al resto.

Claude Code

Claude Code lee sus ajustes gestionados de una carpeta del sistema:

Sistema Carpeta
macOS /Library/Application Support/ClaudeCode/
Linux y WSL /etc/claude-code/
Windows C:\Program Files\ClaudeCode\

La carpeta contiene managed-settings.json, una carpeta opcional managed-settings.d/ con archivos *.json y managed-mcp.json. Claude Code combina primero managed-settings.json y después los archivos de managed-settings.d/ por orden alfabético, y junta las listas de hooks de todos los archivos. Así puedes tener los hooks de zn-gate en su propio archivo, por ejemplo managed-settings.d/50-zn-gate.json, junto a la política de la que se encargan otros equipos.

Hooks y allowManagedHooksOnly

{
  "allowManagedHooksOnly": true,
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|PowerShell|Monitor|Read|Grep|LSP|Edit|MultiEdit|Write|NotebookEdit|WebFetch",
        "hooks": [{ "type": "command", "command": "zn hook claude-code", "timeout": 15 }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "^(Bash|PowerShell|Monitor|Read|Grep|LSP|WebFetch|ReadMcpResourceTool)$|^mcp__.*",
        "hooks": [{ "type": "command", "command": "zn hook claude-code", "timeout": 15 }]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [{ "type": "command", "command": "zn hook claude-code", "timeout": 15, "onFailure": "block" }]
      }
    ]
  }
}

"onFailure": "block" hace que Claude Code bloquee un prompt cuando el hook no puede arrancar. Requiere Claude Code 2.1.295 o posterior; las versiones anteriores ignoran el campo.

Desde zn-gate 1.13.0, zn-gate también comprueba en qué se expande una skill o un comando escrito. Para ello, añade esta entrada dentro de hooks: "UserPromptExpansion": [{ "hooks": [{ "type": "command", "command": "zn hook claude-code", "timeout": 15, "onFailure": "block" }] }].

Qué hace allowManagedHooksOnly. Con true, Claude Code ejecuta solo los hooks que vienen de los ajustes gestionados (más los hooks que registra el Agent SDK y los de plugins que tus ajustes gestionados activan a la fuerza). Bloquea todo lo demás: los hooks del ~/.claude/settings.json de un usuario, del .claude/settings.json y .claude/settings.local.json de un proyecto, de otros plugins y del frontmatter de agentes. Tiene efectos secundarios: el comando /goal deja de funcionar y una línea de estado personalizada debe venir de los ajustes gestionados. Decídelo a propósito y avisa a tus desarrolladores.

El ajuste protege a zn-gate solo si los hooks de zn-gate están en los ajustes gestionados. Si activas allowManagedHooksOnly sin ellos, los hooks que un desarrollador instala con zn hooks install claude-code o con el plugin de zn-gate dejan de ejecutarse y Claude Code no muestra ningún mensaje. zn-gate se lo dice al desarrollador en zn hooks install claude-code y zn-gate status, y calla cuando los archivos gestionados contienen los hooks de zn-gate.

Ten también en cuenta:

  • disableAllHooks: true en los ajustes gestionados desactiva todos los hooks, también los tuyos. Déjalo sin definir.
  • Si entregas la política de más de una forma (ajustes gestionados por servidor, gestión de dispositivos, registro de Windows y archivos), Claude Code usa por defecto la fuente de mayor rango que define una política e ignora las demás, de modo que un archivo puede ignorarse. Pon los hooks de zn-gate en la fuente que Claude Code usa en esa máquina. /status la muestra en la línea Setting sources. zn-gate lee solo los archivos.

Servidores MCP (opcional)

Los hooks son lo que protege al agente. Si además quieres que los desarrolladores usen el servidor MCP secrets de zn-gate (permite al agente usar un secreto guardado en la bóveda de zn sin verlo), las reglas de MCP gestionado deciden si puede arrancar. Cuidado: un archivo managed-mcp.json toma el control exclusivo. En cuanto existe, Claude Code carga solo los servidores de ese archivo (y unos pocos integrados), y los usuarios no pueden añadir ningún otro. Lista todos los servidores que necesita tu equipo, no solo el de zn-gate. Con un objeto mcpServers vacío no se carga ningún servidor.

managed-mcp.json usa el mismo formato que un .mcp.json de proyecto:

{
  "mcpServers": {
    "secrets": {
      "type": "stdio",
      "command": "zn",
      "args": ["secrets-mcp", "--agent", "claude-code"]
    }
  }
}

Si no quieres el control exclusivo, usa en su lugar las listas de permitidos allowedMcpServers y allowManagedMcpServersOnly en los ajustes gestionados, y añade el servidor secrets a la lista. Consulta la configuración de MCP gestionado de Claude Code. zn-gate status avisa al desarrollador cuando un archivo o una lista gestionada impide que arranque el servidor secrets.

Cursor

Cursor lee los hooks de empresa de un hooks.json del sistema:

Sistema Archivo
macOS /Library/Application Support/Cursor/hooks.json
Linux y WSL /etc/cursor/hooks.json
Windows C:\ProgramData\Cursor\hooks.json
{
  "version": 1,
  "hooks": {
    "beforeMCPExecution": [{ "command": "zn hook cursor", "timeout": 30 }],
    "beforeReadFile": [{ "command": "zn hook cursor", "timeout": 30, "failClosed": true }],
    "beforeShellExecution": [{ "command": "zn hook cursor", "timeout": 30 }],
    "beforeSubmitPrompt": [{ "command": "zn hook cursor", "timeout": 30, "failClosed": true }],
    "postToolUse": [{ "command": "zn hook cursor", "timeout": 30 }],
    "preToolUse": [{ "command": "zn hook cursor", "timeout": 30, "matcher": "Grep|Write|Delete" }]
  }
}

Es el mismo conjunto de hooks que zn hooks install cursor, con failClosed en los dos hooks que leen archivos y prompts. Con failClosed: true, un fallo, un tiempo agotado o la falta de respuesta del hook bloquea la acción en lugar de dejarla pasar. Por eso zn-gate debe estar instalado antes: en una máquina sin zn, Cursor bloquearía las lecturas de archivos y los prompts.

Qué hace Cursor con varias fuentes: ejecuta los hooks de cada hooks.json (empresa, equipo, proyecto y usuario), con prioridad para el de empresa, y un deny de cualquiera de ellos prevalece. Así, los hooks propios de un desarrollador se siguen ejecutando junto a los tuyos. La documentación de Cursor (leída el 2026-10-19) no describe ningún ajuste que haga que solo se ejecuten los hooks de empresa, así que en Cursor zn-gate no puede hacerse obligatorio como en Claude Code y Codex. el plan enterprise de Cursor también puede distribuir hooks desde su panel web; esta página cubre solo el archivo.

zn-gate no cubre la línea de comandos de Cursor (cursor-agent).

Codex CLI

Codex lee los requisitos del administrador de un requirements.toml del sistema:

Sistema Archivo
macOS y Linux /etc/codex/requirements.toml
Windows %ProgramData%\OpenAI\Codex\requirements.toml

En macOS, la gestión de dispositivos también puede entregar el mismo contenido como requirements_toml_base64 en el dominio com.openai.codex. Consulta la configuración gestionada de OpenAI.

allow_managed_hooks_only = true

[features]
hooks = true

[hooks]
managed_dir = "/opt/example-managed-hooks"
windows_managed_dir = 'C:\ProgramData\ExampleCorp\managed-hooks'

[[hooks.PreToolUse]]
matcher = "^(Bash|apply_patch)$"

[[hooks.PreToolUse.hooks]]
type = "command"
command = "zn hook codex"
command_windows = "zn hook codex"
timeout = 30
statusMessage = "zn: checking for secrets"

[[hooks.PostToolUse]]
matcher = ".*"

[[hooks.PostToolUse.hooks]]
type = "command"
command = "zn hook codex"
command_windows = "zn hook codex"
timeout = 30
statusMessage = "zn: checking for secrets"

[[hooks.UserPromptSubmit]]

[[hooks.UserPromptSubmit.hooks]]
type = "command"
command = "zn hook codex"
command_windows = "zn hook codex"
timeout = 30
statusMessage = "zn: checking for secrets"

Qué hacen las claves, según la documentación de Codex:

  • allow_managed_hooks_only = true hace que Codex omita los hooks de usuarios, proyectos, sesiones y plugins, y cargue solo los hooks gestionados.
  • [features] hooks = true mantiene los hooks activados incluso para un usuario que los desactivó en su propio config.toml.
  • managed_dir y windows_managed_dir deben ser rutas absolutas de carpetas que existan, o Codex no carga los hooks gestionados. zn-gate no necesita ningún script en ellas, así que basta una carpeta vacía que crees tú.
  • Los hooks gestionados cuentan como de confianza por política: a diferencia de los hooks que instala un desarrollador, no necesitan la revisión en /hooks y el usuario no puede desactivarlos allí.

Si el hook no puede arrancar, Codex deja pasar la llamada (y el prompt), así que se aplica la misma regla: instala zn-gate primero.

Comprobar una máquina

zn-gate check en la versión 1.12.0 lee la configuración propia de cada usuario, no los archivos gestionados. En una máquina donde zn-gate se despliega solo con configuración gestionada, dice "zn is not set up for this agent" aunque los hooks gestionados funcionen. No lo tomes como un fallo de tu despliegue. Usa estas comprobaciones en su lugar.

  1. Pregunta al agente qué ajustes usa.

    • Claude Code: ejecuta /status y lee la línea Setting sources. Debe incluir los ajustes gestionados de empresa (para archivos, "file"). claude doctor lista lo que Claude Code descartó.
    • Cursor: abre la pestaña Hooks en Customize y el canal de salida Hooks para ver los hooks que se ejecutaron y los errores.
    • Codex: ejecuta /hooks. Los hooks gestionados aparecen marcados como gestionados.
  2. Ejecuta zn-gate status en una máquina con Claude Code. Informa, en una línea, de un ajuste gestionado que impide los hooks de zn-gate o su servidor secrets (disableAllHooks, allowManagedHooksOnly sin los hooks de zn-gate, managed-mcp.json sin el servidor, una lista de permitidos o de bloqueados de MCP). Si no hay línea, no encontró ninguno en los archivos; no puede ver la política que llega por ajustes gestionados por servidor, gestión de dispositivos o el registro.

  3. Prueba el propio comando del hook. En macOS o Linux, en una carpeta vacía, crea un archivo .env de prueba con una clave falsa y pide al hook que lo lea, como hace el agente:

    printf 'ZN_CHECK_EXAMPLE_KEY=zn-check-fake-value-not-a-real-key\n' > .env
    printf '{"hook_event_name":"PreToolUse","session_id":"test","cwd":"%s","tool_name":"Read","tool_input":{"file_path":"%s/.env"}}' "$PWD" "$PWD" | zn hook claude-code

    La respuesta debe contener "permissionDecision":"deny". Para un archivo normal como README.txt, no debe contenerlo. La misma prueba para Codex es una llamada Bash con "command":"cat .env" enviada a zn hook codex; para Cursor es {"hook_event_name":"beforeReadFile","cwd":"…","file_path":"…/.env","content":"x","workspace_roots":["…"]} enviado a zn hook cursor, que responde "permission":"deny". Esto demuestra que el comando que escribiste arranca y que las reglas de zn bloquean el archivo. No demuestra que el agente lo llame: eso lo comprueban los pasos 1 y 2.

  4. Compruébalo de extremo a extremo. En una carpeta desechable que contenga solo el .env falso de arriba, pide al agente que lo lea. Debe rechazarlo con un mensaje que empieza por zn:.

Mantenerlo en marcha

  • Actualiza todas las máquinas a la vez. Instala la misma versión de zn-gate en todas y cambia los archivos gestionados solo para ajustarlos a lo que esa versión necesita; el changelog indica cuándo cambian las entradas de los hooks (por ejemplo, la 1.13.0 añade una entrada para Claude Code).
  • Únete a la organización. Los hooks gestionados ejecutan las comprobaciones; la política de la organización y el registro de auditoría requieren que cada máquina se una con zn team join. Consulta Incorporar una máquina y Política de la organización.
  • Para quitar zn-gate, borra las entradas de los archivos gestionados; zn hooks uninstall solo elimina lo que escribió él mismo.

Qué no cubre esta página

OpenCode y los agentes que zn-gate aún no admite (consulta Documentación para agentes de IA). En Windows no se probaron los archivos de Cursor y Codex. Escríbenos a support@usezn.com si algo de aquí no coincide con lo que ves.