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.
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
- 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 tienefailClosed. - Asegúrate de que el agente encuentra
zn. Los comandos de abajo llaman azn hook <agent>, así quezndebe 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 znen macOS y Linux,where znen Windows), por ejemplo/usr/local/bin/zn hook claude-code. - 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: trueen 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.
/statusla muestra en la líneaSetting 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 = truehace que Codex omita los hooks de usuarios, proyectos, sesiones y plugins, y cargue solo los hooks gestionados.[features] hooks = truemantiene los hooks activados incluso para un usuario que los desactivó en su propioconfig.toml.managed_dirywindows_managed_dirdeben 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
/hooksy 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.
-
Pregunta al agente qué ajustes usa.
- Claude Code: ejecuta
/statusy lee la líneaSetting sources. Debe incluir los ajustes gestionados de empresa (para archivos, "file").claude doctorlista 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.
- Claude Code: ejecuta
-
Ejecuta
zn-gate statusen una máquina con Claude Code. Informa, en una línea, de un ajuste gestionado que impide los hooks de zn-gate o su servidorsecrets(disableAllHooks,allowManagedHooksOnlysin los hooks de zn-gate,managed-mcp.jsonsin 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. -
Prueba el propio comando del hook. En macOS o Linux, en una carpeta vacía, crea un archivo
.envde 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-codeLa respuesta debe contener
"permissionDecision":"deny". Para un archivo normal comoREADME.txt, no debe contenerlo. La misma prueba para Codex es una llamadaBashcon"command":"cat .env"enviada azn hook codex; para Cursor es{"hook_event_name":"beforeReadFile","cwd":"…","file_path":"…/.env","content":"x","workspace_roots":["…"]}enviado azn 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. -
Compruébalo de extremo a extremo. En una carpeta desechable que contenga solo el
.envfalso de arriba, pide al agente que lo lea. Debe rechazarlo con un mensaje que empieza porzn:.
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 uninstallsolo 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.