在整个团队中部署 zn-gate

通过各智能体的托管配置把 zn-gate 的 hook 放到每台机器上:Claude Code 托管设置、Cursor 企业 hook 和 Codex 的 requirements.toml,以及如何检查一台机器。

查看 .md

本页面向为团队配置笔记本电脑的人。你不必让每位开发者各自运行 zn hooks install,而是用自己的工具(设备管理、Ansible、系统镜像、登录脚本)在系统文件夹中为每个智能体放置一个配置文件。之后智能体会为所有人运行 zn-gate 的 hook;在 Claude Code 和 Codex 中,你还可以阻止用户和项目关闭它们。

zn-gate 不会替你部署这些文件:它是本地防护,不是 MDM(参见 Team 概览)。下面的所有内容现在都可以手动完成。

各智能体的相关事实来自该智能体自己的文档,阅读于 2026-10-19;大规模部署前请再次查阅,因为这些设置会变化。hook 命令与 zn-gate 1.12.0 或更高版本 中 zn hooks install 为项目安装写入的命令相同。

开始之前

  1. 在每台机器上安装 zn-gate,所有机器使用相同版本。它需要 Node.js 18 或更高版本:npm install -g zn-gate。请先做这一步。无法运行的 hook 并非无害:Claude Code 和 Codex 会在未检查的情况下放行工具调用,而当 hook 设置了 failClosed 时,Cursor 会阻止文件读取和提示词。
  2. 确保智能体能找到 zn。 下面的命令调用 zn hook <agent>,所以 zn 必须在智能体运行时使用的 PATH 中。桌面应用并不总是能获得你终端的 PATH。如果不确定,请写完整路径(macOS 和 Linux 上用 command -v zn,Windows 上用 where zn),例如 /usr/local/bin/zn hook claude-code。
  3. 先在一台机器上试用,检查它(见下文“检查一台机器”),然后再推广到其他机器。

Claude Code

Claude Code 从系统文件夹读取托管设置:

系统 文件夹
macOS /Library/Application Support/ClaudeCode/
Linux 和 WSL /etc/claude-code/
Windows C:\Program Files\ClaudeCode\

该文件夹包含 managed-settings.json、可选的 managed-settings.d/(放 *.json 文件)和 managed-mcp.json。Claude Code 先合并 managed-settings.json,再按字母顺序合并 managed-settings.d/ 中的文件,并把所有文件中的 hook 列表合在一起。因此你可以把 zn-gate 的 hook 放在单独的文件里,例如 managed-settings.d/50-zn-gate.json,与其他团队维护的策略并列。

Hook 与 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" 让 Claude Code 在 hook 无法启动时阻止提示词。它需要 Claude Code 2.1.295 或更高版本;更早的版本会忽略该字段。

从 zn-gate 1.13.0 起,zn-gate 还会检查输入的 skill 或命令展开后的内容。为此,请在 hooks 下添加这一项:"UserPromptExpansion": [{ "hooks": [{ "type": "command", "command": "zn hook claude-code", "timeout": 15, "onFailure": "block" }] }]。

allowManagedHooksOnly 的作用。 设为 true 时,Claude Code 只运行来自托管设置的 hook(再加上 Agent SDK 注册的 hook,以及你的托管设置强制启用的插件的 hook)。其余全部被阻止:用户 ~/.claude/settings.json 中的 hook、项目 .claude/settings.json 和 .claude/settings.local.json 中的 hook、其他插件的 hook,以及智能体 frontmatter 中的 hook。它有副作用:/goal 命令将无法使用,自定义状态栏必须来自托管设置。请有意识地做决定,并告知你的开发者。

只有当 zn-gate 的 hook 位于托管设置中时,该设置才保护 zn-gate。 如果你设置了 allowManagedHooksOnly 却没有放入这些 hook,开发者用 zn hooks install claude-code 或 zn-gate 插件安装的 hook 会停止运行,而 Claude Code 不会给出任何提示。zn-gate 会在 zn hooks install claude-code 和 zn-gate status 中告知开发者;当托管文件中包含 zn-gate 的 hook 时,它不会出声。

还请注意:

  • 托管设置中的 disableAllHooks: true 会关闭所有 hook,包括你的。请保持不设置。
  • 如果你通过多种方式下发策略(服务器托管设置、设备管理、Windows 注册表和文件),Claude Code 默认使用设置了策略的最高优先级来源,并忽略其他来源,因此某个文件可能被忽略。请把 zn-gate 的 hook 放在 Claude Code 在该机器上使用的来源中。/status 会在 Setting sources 一行显示它。zn-gate 只读取文件。

MCP 服务器(可选)

保护智能体的是 hook。如果你还希望开发者使用 zn-gate 的 secrets MCP 服务器(它让智能体在看不到内容的情况下使用保存在 zn 保险库中的密钥),那么托管 MCP 规则决定它能否启动。请注意:managed-mcp.json 文件会取得独占控制权。 该文件一旦存在,Claude Code 只加载其中的服务器(以及少数内置服务器),用户无法添加任何其他服务器。请列出你的团队需要的所有服务器,而不只是 zn-gate 的。若 mcpServers 对象为空,则不会加载任何服务器。

managed-mcp.json 的格式与项目的 .mcp.json 相同:

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

如果你不想要独占控制,可改用托管设置中的允许列表 allowedMcpServers 和 allowManagedMcpServersOnly,并把 secrets 服务器加入列表。参见 Claude Code 的托管 MCP 配置。当托管文件或列表阻止 secrets 服务器启动时,zn-gate status 会告知开发者。

Cursor

Cursor 从系统的 hooks.json 读取企业 hook:

系统 文件
macOS /Library/Application Support/Cursor/hooks.json
Linux 和 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" }]
  }
}

这与 zn hooks install cursor 是同一组 hook,只是在读取文件和提示词的两个 hook 上加了 failClosed。设置 failClosed: true 后,hook 崩溃、超时或没有返回,都会阻止该操作,而不是放行。这就是必须先安装 zn-gate 的原因:在没有 zn 的机器上,Cursor 会阻止文件读取和提示词。

Cursor 如何处理多个来源:它会运行每个 hooks.json(企业、团队、项目和用户)中的 hook,企业级优先,其中任何一个返回 deny 都会生效。因此开发者自己的 hook 仍会与你的 hook 一起运行。Cursor 的文档(阅读于 2026-10-19)没有描述能让只运行企业 hook 的设置,所以在 Cursor 中无法像 Claude Code 和 Codex 那样强制使用 zn-gate。Cursor 的企业版方案还可以从其网页控制台分发 hook;本页只涉及文件方式。

zn-gate 不覆盖 Cursor 命令行(cursor-agent)。

Codex CLI

Codex 从系统的 requirements.toml 读取管理员要求:

系统 文件
macOS 和 Linux /etc/codex/requirements.toml
Windows %ProgramData%\OpenAI\Codex\requirements.toml

在 macOS 上,设备管理也可以在 com.openai.codex 域中以 requirements_toml_base64 的形式下发相同内容。参见 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"

这些键的作用,依据 Codex 的文档:

  • allow_managed_hooks_only = true 让 Codex 跳过用户、项目、会话和插件的 hook,只加载托管 hook。
  • [features] hooks = true 即使在用户于自己的 config.toml 中关闭了 hook 的情况下,也保持 hook 开启。
  • managed_dir 和 windows_managed_dir 必须是已存在文件夹的绝对路径,否则 Codex 不会加载托管 hook。zn-gate 不需要其中放任何脚本,所以你自己创建一个空文件夹即可。
  • 托管 hook 被视为由策略信任:与开发者自己安装的 hook 不同,它们不需要在 /hooks 中审核,用户也无法在那里关闭它们。

如果 hook 无法启动,Codex 会放行该调用(以及提示词),所以同样的规则适用:先安装 zn-gate。

检查一台机器

1.12.0 版本的 zn-gate check 读取每位用户自己的配置,而不读取托管文件。 在仅通过托管配置部署 zn-gate 的机器上,即使托管 hook 正常工作,它也会显示 “zn is not set up for this agent”。请不要把它当作部署失败。请改用下面的检查。

  1. 询问智能体它使用了哪些设置。

    • Claude Code:运行 /status,查看 Setting sources 一行。它必须列出企业托管设置(文件方式显示 “file”)。claude doctor 会列出 Claude Code 丢弃的内容。
    • Cursor:在 Customize 中打开 Hooks 标签页,并查看 Hooks 输出通道,了解已运行的 hook 和任何错误。
    • Codex:运行 /hooks。托管 hook 会被标记为托管。
  2. 在 Claude Code 机器上运行 zn-gate status。 它会用一行报告阻止 zn-gate hook 或其 secrets 服务器的托管设置(disableAllHooks、没有 zn-gate hook 的 allowManagedHooksOnly、没有该服务器的 managed-mcp.json、MCP 允许列表或拒绝列表)。没有这一行表示它在文件中没有发现任何此类设置;它看不到来自服务器托管设置、设备管理或注册表的策略。

  3. 测试 hook 命令本身。 在 macOS 或 Linux 上,在一个空文件夹中创建带假密钥的测试 .env 文件,然后像智能体那样让 hook 读取它:

    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

    返回内容必须包含 "permissionDecision":"deny"。对于 README.txt 这样的普通文件,则不能包含。Codex 的同类测试是把带 "command":"cat .env" 的 Bash 调用传给 zn hook codex;Cursor 则是把 {"hook_event_name":"beforeReadFile","cwd":"…","file_path":"…/.env","content":"x","workspace_roots":["…"]} 传给 zn hook cursor,它会返回 "permission":"deny"。这证明你写的命令能够启动,且 zn 的规则会阻止该文件。它不能证明智能体会调用它:这要靠第 1 步和第 2 步。

  4. 端到端查看。 在只含上述假 .env 的临时文件夹中,让智能体读取它。它必须被拒绝,并显示以 zn: 开头的消息。

保持其正常运作

  • 同时更新所有机器。 在所有机器上安装相同的 zn-gate 版本,只在该版本需要时才修改托管文件;更新日志会说明 hook 条目何时变化(例如 1.13.0 为 Claude Code 增加了一项)。
  • 加入组织。 托管 hook 负责执行检查;组织策略和审计记录要求每台机器用 zn team join 加入。参见加入设备和组织策略。
  • 要移除 zn-gate, 请删除托管文件中的条目;zn hooks uninstall 只会移除它自己写入的内容。

本页不涉及的内容

OpenCode,以及 zn-gate 尚不支持的智能体(参见面向 AI 智能体的文档)。Cursor 和 Codex 的文件未在 Windows 上测试。如果这里的内容与你看到的不符,请发邮件至 support@usezn.com。