mcpField
A
agent-guardrails

agent-guardrails

github.com/paldomAgent 工作流239 次安装7 周前更新
代码仓库

关于 agent-guardrails

面向 Python 仓库中的 Claude Code 编码 Agent,提供规则文件、钩子配置和检查脚本的护栏实施技能。它将命令拦截、编辑后反馈与停止前验证分层,并强调 CI 才是权威门禁。

主要功能

  1. 01审计现有护栏配置
  2. 02生成仓库规则文件
  3. 03拦截危险命令并检查编辑文件
  4. 04停止前运行提交门禁验证
  5. 05验证钩子能否实际触发

适用场景

  1. 01为 Python 仓库配置 Agent 行为约束
  2. 02阻止危险 Bash 与 Git 操作
  3. 03在编码过程中反馈 Ruff 检查结果
  4. 04确认 Agent 完成前通过仓库验证

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/paldom/python-skills --skill agent-guardrails

安装后在 Claude Code 中输入/agent-guardrails确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
AGENTS.md.template
settings.json.template
assets/hooks/
guard_bash.py
lint_edited_file.py
stop_verify.py
evals/
evals.json
references/
hooks-reference.md
layer-assignment.md
vetting-skills-and-plugins.md
scripts/
check_guardrails.py

详细介绍

agent-guardrails

安装 Python 仓库面向 Agent 的强制执行层:Claude Code 钩子,为编码 Agent 提供即时、确定性的反馈(并强制阻止少数绝不能做的事);负责部署这些钩子的设置配置;精简的规则文件;以及经过审核的公开技能。此技能要解决的问题是仅提供建议的防护措施——模型在上下文压力下会忘记规则、钩子悄无声息地从不触发,以及实际上毫无阻止作用的 exit 1“拦截”。

不适用场景

  • Git 钩子——.pre-commit-config.yaml、commit-msg/pre-push 阶段。如果已安装 python-precommit 技能,由它负责提交时的防护层。
  • CI 工作流、必需检查、分支规则集——由 python-ci 技能负责。CI 是此技能各层所依赖的权威关卡,而不是此技能安装的内容。
  • 验证 LLM 输出数据——Pydantic/Instructor 模式验证、附带错误上下文重试、SQL 安全验证器。这属于应用中的运行时数据验证,而非仓库防护;此技能不涵盖这些内容。
  • 调整检查本身的行为——ruff 规则(python-lint)、类型检查器配置(python-typing)、测试基础设施(python-testing)。此技能负责配置检查在 Agent 操作中何时运行,而不是检查的内容。
  • 通用提示词工程或系统提示词编写。

分层模型(请先阅读)

防护措施只有分层设置才能发挥作用;每一层都会捕获前一层无法捕获的问题(这是一种惯例,并非官方规范,但已得到多个来源的广泛共识):

层运行时机捕获的问题可绕过?
规则文件(AGENTS.md/CLAUDE.md)会话开始时读取约定、命令可以——模型可能会忘记的建议
Claude Code 钩子每次 Agent 操作发生时在不良写入/命令发生之前或发生时拦截可以——本地且由用户控制
pre-commit提交时整个差异中的问题可以——使用 --no-verify
CI + 规则集合并时所有问题,且运行于 Agent 无法控制的基础设施上不可以——唯一真正的关卡

每次都要向用户说明两点:任何必须始终执行的事情都应放在钩子中,而不是写成文字(规则文件只是愿望;钩子是由执行框架运行的契约);钩子绝不是安全边界——它们在本地且可由用户编辑,而其他工具路径(例如用 bash heredoc 代替 Edit)可以绕过文件匹配器,因此 CI 和服务端规则仍然具有权威性。(设置文件中的钩子确实会在子 Agent 中运行,输入中会包含 agent_id——这一缺口已经得到弥补。)钩子独有的一项能力:PreToolUse 拒绝会在文件写入磁盘之前发生——这是唯一能进行预防而非事后清理的层。

工作流

1. 审查现有内容
python3 "${CLAUDE_SKILL_DIR}/scripts/check_guardrails.py" --root .

只读:报告设置文件及其作用范围、已配置的钩子及其匹配器、规则文件及其长度,以及明显的缺陷(小写匹配器、将 exit 1 用作拦截、缺少脚本文件、未设防的 Stop 钩子)。同时检查 claude --version——钩子行为会随版本变化;当前文档才是权威来源:https://code.claude.com/docs/en/hooks

2. 规则文件 — 提供上下文,而非强制执行

在仓库根目录编写(或精简)AGENTS.md,并让 CLAUDE.md 仅包含 @AGENTS.md,确保每个 Agent 都读取同一份权威文件。请从 assets/AGENTS.md.template 开始。以下规则值得写入 Python 仓库:

  • 写明确切命令,而非泛泛描述 — uv sync、uv run pytest、 uv run ruff check --fix、uv run mypy src/
  • “使用 uv,绝不使用 pip 或 poetry”(Agent 最常见的失败:默认使用全局 pip 安装)
  • “在宣布任务完成前运行 lint、类型检查和测试”
  • “绝不为了通过检查而放宽门槛 — 不得降低覆盖率、跳过测试或使用 || true”(Agent 面临压力时,会选择最省事的方式让检查通过)
  • 明确影响范围:“涉及身份验证、依赖项或锁文件的更改,须提交人工审核”

将其控制在约 200 行以内,并由人工精心编写:评估显示,自动生成的上下文文件会明显降低 Agent 的成功率 — 应写明本仓库特有的信息,而非通用概述。反复出现的 PR 审查修改意见,是新增规则的最佳来源。

3. Hooks — 确定性层

将 assets/hooks/ 中的三个 hook 脚本复制到 .claude/hooks/,赋予它们可执行权限,然后将 assets/settings.json.template 配置到 .claude/settings.json。架构采用轻量 JSON、厚重脚本:设置文件只负责路由事件,逻辑则放在纳入版本控制的脚本中。

目标事件 + 匹配器脚本
阻止危险的 bash 命令(--no-verify、SKIP=、hooksPath 伎俩、强制推送到 main、直接使用 pip、宽泛的 rm -rf)对 Bash 使用 PreToolUseguard_bash.py
立即为刚编辑的 Python 文件提供 ruff 反馈(仅报告,不重写)对 Edit|Write|NotebookEdit 使用 PostToolUselint_edited_file.py
仅在提交门禁会接受时才放行Stopstop_verify.py

三个脚本都只使用 Python 标准库(无需 jq):bash 防护脚本会解析命令(包括包装命令、bash -c、换行符、git -c/-C 选项),而非简单搜索字符串,因此会拦截 git push origin HEAD:main --force、git -c core.hooksPath=/dev/null commit 和 python3.12 -m pip,但不会拦截 git commit -uno。

一致性原则。 Stop 门禁绝不重新实现检查逻辑:当仓库存在 .pre-commit-config.yaml 时,stop_verify.py 会直接对已更改和未跟踪的文件运行 pre-commit — 与 git commit 将运行的门禁完全相同(pre-commit run --files 会按工作树当前状态检查;不会暂存文件)。自动修复型 hook(prettier、ruff --fix、空白字符修复工具)会在修复工作树后以非零状态退出,因此门禁会运行两次,第二次检查通过后即表示干净。手写的子集(仅运行 ruff check .)会偏离配置,造成典型问题:Agent 宣布完成,所有者提交时却被 prettier 拦截。未使用 pre-commit 的仓库则保留快速的单一 VERIFY_CMD 回退方案。

退出码约定 — 最容易出错的部分(已根据 https://code.claude.com/docs/en/hooks 验证,2026-09-10):

  • exit 0 — 继续执行。stdout 可以包含 JSON 决策;退出码为 0 时,普通的 stderr 只会写入调试日志,因此用户必须看到的警告应通过 stdout 中的 {"systemMessage": "..."} 输出。
  • exit 2 — 可阻止事件的阻止型退出码,JSON 中的内容无法覆盖它。显示的原因是 JSON 决策中的 reason(如果有输出),否则就是 stderr — 因此最简单的做法仍是“exit 2 + 在 stderr 中提供原因”。“阻止”的含义取决于事件类型: PreToolUse 会阻止调用;PostToolUse 无法撤销调用 — stderr 仅用于反馈(且只会在调用成功时触发;失败的调用会触发 PostToolUseFailure);Stop 会阻止停止,并强制 Agent 继续工作。
  • exit 1(或其他任何代码) — 不会阻止执行,除非 stdout 包含有效的决策 JSON,该 JSON 会在任何退出码下生效。单独的 exit 1 加一条消息只会被记录并忽略;大量 hook 配置出问题,根源就是这一点。

能够经受团队实际使用考验的 hook 规则:

  • 将 PostToolUse 限定到单个已编辑文件,并确保耗时不到 1 秒——它会在每次匹配的调用中同步运行。更耗时的任务(mypy、测试)应放在 Stop 钩子、pre-commit 或 CI 中。
  • Stop 钩子必须遵循 stdin JSON 中的 stop_hook_active——模板会再次验证,然后放行(退出码为 0),而不是再次阻止——否则会陷入循环;连续阻止 8 次后,执行框架会强制覆盖。
  • 为 Stop gate 设置宽裕且明确的超时时间(模板配置为 300 秒),并在设置时预构建钩子环境(uv run pre-commit install --install-hooks):钩子超时后会不阻塞,因此首次运行时冷启动构建环境会悄悄跳过验证。
  • 匹配器区分大小写:bash 永远不会匹配 Bash。字母、数字、_、-、空格、逗号和 | 都会按精确匹配列表处理;其他任何字符都会使其成为非锚定正则表达式(Edit.* 也会匹配 NotebookEdit)。
  • Edit|Write|NotebookEdit 无法捕获由 shell 驱动的编辑(sed -i、heredoc)。通过 Stop 钩子的验证环节弥补这个缺口,该环节会检查整个工作树;如果需要对 shell 写入进行逐文件响应,可使用 FileChanged 监视路径。
  • ConfigChange(匹配器 project_settings)可以阻止对 .claude/settings.json 的编辑——这是唯一能阻止 Agent 在会话中途重写自身防护规则的钩子。
  • 仅对确定且明确的违规行为进行硬性拒绝(exit 2);对于风格层面的问题,优先提供非阻塞反馈——过于激进的 PreToolUse 阻止可能会让 Agent 完全停滞,而不是引导它。
  • 按观察 → 警告 → 强制执行的顺序推出:先仅记录日志,再针对造成实际损害的模式添加范围明确的拒绝规则。

完整机制(各事件的退出码为 2 时的语义、匹配器和 if 字段规则、JSON 决策通道、作用范围、已知版本漂移问题): references/hooks-reference.md。 各项检查应放在哪个层级: references/layer-assignment.md。

4. 设置作用范围和权限
  • .claude/settings.json — 已提交到代码库,适用于每位贡献者。这是团队约定;对此文件的更改应接受 PR 级别的审查(见下文安全部分)。
  • .claude/settings.local.json — 已加入 gitignore,用于个人实验。
  • ~/.claude/settings.json — 用户全局设置。所有作用范围的设置会以累加方式合并;项目文件无法关闭用户钩子,只能添加钩子。
  • 钩子可以收紧策略,但不能取代权限系统:钩子 exit 0 不会批准任何操作,而且 if 过滤器仅尽力而为,遇到不明确的命令时会默认放行。工具的硬性允许/拒绝应由 permissions 规则控制;钩子则用于添加权限语法无法表达的检查。
5. 安装并审查公开技能

推荐使用成熟的公开技能,而不是从头构建——但应将每个第三方技能、插件和 MCP 服务视为未经审查且拥有完整用户权限的依赖项。安装前的最低限度审查:阅读插件清单(mcpServers 条目意味着可访问网络)、它提供的每个钩子及其运行的命令,以及每个完整的 SKILL.md 正文;检查请求的权限是否与所述功能相称;固定版本,并像审查依赖升级一样审查更新。精选起点和完整检查清单: references/vetting-skills-and-plugins.md。

6. 通过触发每道防线进行验证

从未触发过的防护措施尚未经过验证。逐一进行刻意测试:

# 1. Scripts standalone, with realistic stdin — check exit code + stderr
echo '{"tool_input":{"command":"git commit --no-verify -m x"}}' \
  | python3 .claude/hooks/guard_bash.py; echo "exit=$?"        # expect exit=2
echo '{"tool_input":{"command":"git status"}}' \
  | python3 .claude/hooks/guard_bash.py; echo "exit=$?"        # expect exit=0
# 2. Audit passes
python3 "${CLAUDE_SKILL_DIR}/scripts/check_guardrails.py" --root .

然后,在实时会话中:要求 Agent 执行一项被阻止的操作(预期调用被阻止并显示原因),编辑一个包含刻意引入的 lint 错误的文件(预期收到钩子反馈),并以检查失败结束一轮(预期 Stop gate 会予以拦截)。在使用 pre-commit 的代码库中,还要以树中存在未格式化的 YAML/Markdown 文件结束一轮——Stop gate 必须运行提交 gate 并自动修复或阻止,绝不能直接放行。如果钩子没有触发,请依次检查:匹配器大小写、设置嵌套,以及 python3 是否在 PATH 中。

输出规范

完成意味着:

  • AGENTS.md(≲200 行,针对仓库)中包含由 CLAUDE.md 导入的内容。
  • .claude/settings.json 配置了 PreToolUse 防护、PostToolUse 单文件检查,以及一个 Stop 门禁:运行仓库自己的提交门禁(对变更集运行 pre-commit)或单条快速验证命令;.claude/hooks/ 中的脚本具有可执行权限,仅通过退出码 2 + stderr 阻止操作;Stop 由 stop_hook_active 防止重复触发。
  • 每个钩子均已演示能够触发并阻止操作(步骤 6 的记录)。
  • scripts/check_guardrails.py 退出码为 0。
  • 已分别用一句话告知用户:钩子只是便利措施,CI 才是门禁;以及已提交的钩子会在每位贡献者的机器上执行。

失败模式与注意事项

症状原因 / 修复
钩子“阻止”了操作,但操作仍继续exit 1——只有退出码 2 会阻止操作;其他情况都会记录后忽略
Agent 看不到阻止原因原因以纯文本打印到 stdout——退出码为 2 时,如果有 JSON reason 字段则使用该字段,否则使用 stderr;纯 stdout 文本不会显示
退出码为 0 的钩子发出的警告从未显示退出码为 0 时,stderr 只会写入调试日志——在 stdout 上打印 {"systemMessage": "..."}
钩子从未触发匹配器区分大小写(bash≠Bash)、settings 嵌套错误、$HOME 未展开,或 python3 不在 PATH 中——这些问题都会静默失败
Stop 钩子无限循环缺少 stop_hook_active 防护;运行环境最多允许阻止 8 次,但仍应修复防护
Agent 表示“完成”,但所有者的 git commit 失败(prettier 重新格式化、空白修复器触发)Stop 门禁重新实现了部分检查,而没有运行仓库的 pre-commit——接入 stop-verify.sh 的一致性检查路径(对变更集运行 pre-commit run --files)
新克隆后首次 Stop 卡住或超时钩子环境正在冷启动构建;在设置阶段预先构建(pre-commit install --install-hooks),并保留较宽裕的超时时间——超时的钩子不会阻止操作,也就是静默放行
Agent 编辑了文件,但格式钩子没有反应通过 Bash 编辑(sed -i、cat >)——Edit|Write 不会触发;依赖 Stop 钩子对工作树的检查
格式化钩子与 Agent 冲突自动修复型 PostToolUse 钩子在 Agent 编辑文件时重写文件,导致 Agent 下一次编辑因文件过期检查而失败——随附的钩子只报告问题;自动修复应交由 pre-commit 和 Stop 门禁的第二轮检查
PreToolUse 退出码为 2,导致 Agent 卡住而非进行修正某些版本中的已知行为——尽量少用强制拒绝,并确保拒绝原因可操作;将风格反馈放在非阻塞渠道中
把钩子当作安全措施钩子是本地的,受用户控制;其他工具路径(例如通过 shell 写入)可以绕过文件匹配器——CI + 规则集才是边界。钩子也会在子 Agent 中运行。
已提交的钩子 = 在每次克隆时执行代码.claude/ 中的变更就是代码:用 CODEOWNERS 保护,并在检出 PR 分支前通过 Web UI 审查(这方面确实发生过 CVE)
插件/技能被发现有恶意行为安装前先审查(步骤 5)、固定版本,并优先选择官方或经过筛选的来源
教程中的钩子说明与实际行为不符事件类型和阻止语义会随版本变化——应以 https://code.claude.com/docs/en/hooks 为准,而不是任何静态列表,包括本技能中的列表

文件

  • scripts/check_guardrails.py — 只读审计设置、钩子、匹配器和规则文件;发现缺陷时返回非零退出码。
  • assets/settings.json.template — 三脚本配置的钩子接线。
  • assets/hooks/guard_bash.py — PreToolUse 拒绝规则(基于词法分析器,使用标准库): --no-verify/-n/缩写、SKIP= 跳过钩子、core.hooksPath 重定向、参数顺序不限的向 main 强制推送、在 uv 之外直接使用 pip / python -m pip、对宽泛路径递归强制删除。
  • assets/hooks/lint_edited_file.py — PostToolUse 单文件 ruff check + 通过项目自带的 ruff(uv run)运行 format --check;只报告,不重写。
  • assets/hooks/stop_verify.py — 停止门禁,带有 stop_hook_active 防护, 在 $CLAUDE_PROJECT_DIR 中运行:对已更改和未跟踪文件运行仓库的 pre-commit (运行两次,以使自动修复钩子收敛;备用方案为 uv run),或在没有 pre-commit 的仓库中运行一个 VERIFY_CMD 列表;通过 systemMessage 解除门禁。
  • assets/AGENTS.md.template — 起始规则文件。
  • references/hooks-reference.md — 完整的钩子机制及已知问题。
  • references/layer-assignment.md — 各项检查运行所在的层级。
  • references/vetting-skills-and-plugins.md — 审查清单及精选技能。

评论

支持 Markdown