
在 Claude Code 中给 Python XML 项目建立可靠验证体系推荐分成四层Rules 告诉 Claude 应遵守什么 Skill 编排一次完整验证流程 Subagent 在独立上下文中复核实现 Hooks 用真实命令执行不可绕过的确定性检查其中最重要的原则是Rules、Skill、Subagent 都属于模型行为约束只有 Hook/CI 调用真实测试和校验程序才能形成确定性门禁。一、推荐目录结构project/ ├── src/ ├── config/ ├── schemas/ ├── tests/ ├── openspec/ ├── scripts/ │ ├── validate_xml.py │ └── quality_gate.py ├── .claude/ │ ├── settings.json │ ├── rules/ │ │ ├── python.md │ │ ├── xml.md │ │ ├── tests.md │ │ └── openspec.md │ ├── skills/ │ │ └── validate-change/ │ │ └── SKILL.md │ ├── agents/ │ │ ├── spec-verifier.md │ │ ├── python-reviewer.md │ │ └── xml-reviewer.md │ └── hooks/ │ ├── validate_changed_file.py │ └── stop_quality_gate.py ├── CLAUDE.md └── pyproject.toml建议把真正的验证逻辑放在scripts/quality_gate.py scripts/validate_xml.pySkill、Hook、CI 都调用同一套脚本避免出现Claude Code 验证一套 开发者本地验证一套 CI 又验证另一套二、Rules定义长期约束Rules 是提示词约束不是强制执行程序。适合告诉 ClaudePython 修改必须增加测试XML 不能整体重排配置变更必须兼容旧 XML修改 XSD 后必须校验所有 XMLOpenSpec Scenario 必须有测试证据。Claude Code支持.claude/rules/*.md还可以使用paths限定规则只在读取匹配文件时加载。Claude Code Rules 官方文档Python Rule.claude/rules/python.md--- paths: - src/**/*.py - tests/**/*.py - scripts/**/*.py --- # Python Rules - Preserve existing public APIs unless the approved OpenSpec change says otherwise. - Follow patterns already used in adjacent modules. - Add or update pytest tests for observable behavior changes. - Do not weaken or delete existing assertions merely to make tests pass. - Do not introduce a new dependency without documenting it in design.md. - Do not mark an OpenSpec task complete until its corresponding test passes. - Run targeted tests first, then the complete regression suite. - Report any pre-existing test failures separately from newly introduced failures.XML Rule.claude/rules/xml.md--- paths: - config/**/*.xml - schemas/**/*.xsd - tests/fixtures/**/*.xml --- # XML Rules - Treat XML files and XSD files as external compatibility contracts. - Preserve existing elements, attributes, namespaces, comments, and ordering unless the approved OpenSpec change explicitly modifies them. - Do not reformat an entire XML file for a localized change. - Validate changed XML against the applicable XSD when one exists. - Verify that existing production-compatible XML remains readable. - Test missing values, invalid values, unknown elements, and default behavior. - If old code cannot read the new XML format, document rollback and deployment order. - Do not enable DTD or external entity resolution without explicit approval.测试规则.claude/rules/tests.md--- paths: - tests/**/*.py - tests/fixtures/**/* --- # Test Rules - Every OpenSpec Scenario that changes behavior requires verification evidence. - Prefer behavioral assertions over implementation-detail assertions. - Include compatibility tests for existing XML fixtures. - Tests for invalid XML must assert both rejection and absence of side effects. - Snapshot tests do not replace semantic XML assertions. - Do not replace integration tests with mocks unless the design explicitly permits it.OpenSpec Rule.claude/rules/openspec.md--- paths: - openspec/**/*.md - openspec/**/*.yaml --- # OpenSpec Verification Rules Before claiming a change is complete: 1. All applicable requirements and scenarios must be mapped to implementation. 2. Every scenario must have automated test evidence or an explicit manual check. 3. All completed tasks must have passed their validation command. 4. Run openspec validate --all --strict. 5. Run the project quality gate. 6. Review Python, XML, XSD, and test diffs. 7. Report unverified risks; never silently classify them as passed.Path Rule 是按相关文件读取触发的不是安全边界Claude 官方明确说明 CLAUDE.md/Rules 是上下文指导不能保证严格遵守。三、Skill/Command编排统一验证流程Claude Code最新版本已经把自定义 Command 归入 Skills 体系。推荐创建.claude/skills/validate-change/SKILL.md调用方式/validate-change add-xml-retry-policy内容--- name: validate-change description: Validate a Python and XML OpenSpec change before sync or archive. argument-hint: [change-name] disable-model-invocation: true --- Validate OpenSpec change $ARGUMENTS. Do not edit production code during the first verification pass. ## Step 1: Resolve the change Run: bash openspec status --change $ARGUMENTS --jsonRead:proposal.mddesign.mdtasks.mdall delta specsaffected main specsStep 2: Inspect the diffRun:gitstatus--shortgitdiff--statgitdiff-- src tests config schemas openspecCheck for:out-of-scope files;unrelated XML reformatting;deleted or weakened tests;unapproved dependencies;accidental public API changes;XML/XSD mismatch.Step 3: Build a traceability matrixFor every Requirement and Scenario, identify:implementation file;test file and test name;XML/XSD contract involved;verification command;PASS, FAIL, or NOT VERIFIED.Do not mark a scenario PASS solely because tasks.md is checked.Step 4: Run deterministic validationRun:python scripts/quality_gate.pyAlso run:openspec validate--all--strictStep 5: Independent reviewDelegate read-only reviews to:python-reviewerfor Python correctness and regressions;xml-reviewerfor XML/XSD compatibility;spec-verifierfor requirement-to-test traceability.Step 6: ReportReturn:overall status;failed commands;traceability matrix;blocking findings;warnings;residual risks.A change is ready for sync/archive only when:deterministic checks pass;no blocking reviewer finding remains;every required scenario is PASS or explicitly accepted as manual verification.设置 yaml disable-model-invocation: true意味着只有用户显式输入/validate-change才执行避免 Claude 自己在不合适的时候运行耗时验证。Skills 支持参数、工具权限和子代理上下文官方说明见 Claude Code Skills。四、Subagent用独立上下文复核不要让实现代码的同一个上下文直接给自己打分。建议建立三个只读 Subagent。1. Python Reviewer.claude/agents/python-reviewer.md--- name: python-reviewer description: Independently reviews changed Python code for correctness, regression risk, and test quality. Use proactively after implementation. tools: Read, Glob, Grep, Bash model: sonnet permissionMode: dontAsk maxTurns: 20 --- You are a read-only Python reviewer. Do not edit files. Review the current Python diff and related tests. Check: 1. observable behavior matches the approved OpenSpec change; 2. public API compatibility; 3. error handling and side effects; 4. resource cleanup; 5. type and boundary handling; 6. existing tests were not weakened; 7. tests prove behavior rather than implementation details; 8. XML configuration values are validated before use. Run read-only commands when needed: - git diff -- src tests - targeted pytest commands; - ruff or configured type checks. Report findings as: - BLOCKER - WARNING - NOTE Every finding must include file path, evidence, and recommended correction. If no blocking issue is found, say so explicitly, but list residual risks.2. XML Reviewer.claude/agents/xml-reviewer.md--- name: xml-reviewer description: Independently reviews XML and XSD changes for compatibility, schema validity, security, and unintended formatting changes. tools: Read, Glob, Grep, Bash model: sonnet permissionMode: dontAsk maxTurns: 20 --- You are a read-only XML contract reviewer. Do not edit files. Review changed XML, XSD, Python parser code, fixtures, and tests. Check: 1. changed XML validates against the applicable XSD; 2. old checked-in XML remains valid and readable; 3. new elements and attributes have defined defaults; 4. namespaces and ordering remain compatible; 5. unrelated XML content was not reformatted; 6. Python parser behavior matches the XSD; 7. unknown elements retain documented behavior; 8. DTD and external entity handling is safe; 9. rollback compatibility is documented; 10. tests cover valid, missing, invalid, and compatibility cases. Report BLOCKER, WARNING, and NOTE findings with evidence.3. Spec Verifier.claude/agents/spec-verifier.md--- name: spec-verifier description: Independently maps OpenSpec requirements and scenarios to code and tests before sync or archive. tools: Read, Glob, Grep, Bash model: sonnet permissionMode: dontAsk maxTurns: 25 --- You are a read-only OpenSpec verification agent. Do not edit files. For the selected change: 1. read proposal, specs, design, and tasks; 2. inspect the implementation diff; 3. find test evidence for every scenario; 4. run relevant read-only validation commands; 5. distinguish automated proof from model inference. Produce a traceability table: | Requirement/Scenario | Implementation | Test evidence | Result | Allowed results: - PASS: relevant command was run and passed; - FAIL: command or behavior failed; - NOT VERIFIED: insufficient evidence. Never classify a scenario PASS solely because tasks.md contains [x].为什么要限制写权限Subagent frontmatter只给tools:Read,Glob,Grep,Bash不提供 Edit/Write让它更接近独立审查者。但要注意Bash本身仍可能运行写命令。更严格时在 Agent 提示中明确只允许只读命令通过 permissions/hooks 限制危险命令或仅允许专门的验证脚本不使用bypassPermissions。Claude Code支持自定义 Agent、工具限制、预加载 Skills 和 worktree 隔离参见 Subagents 官方文档。五、统一的确定性验证脚本不要在 Hook 中塞很多复杂 shell 命令。建议集中到scripts/quality_gate.py示例from__future__importannotationsimportsubprocessimportsysfromdataclassesimportdataclassdataclass(frozenTrue)classCheck:name:strcommand:list[str]CHECKS[Check(nameOpenSpec validation,command[openspec,validate,--all,--strict],),Check(nameXML validation,command[sys.executable,scripts/validate_xml.py],),Check(namePython tests,command[sys.executable,-m,pytest,-q],),Check(nameRuff,command[sys.executable,-m,ruff,check,.],),]defmain()-int:failed:list[str][]forcheckinCHECKS:print(f\n{check.name})resultsubprocess.run(check.command,checkFalse)ifresult.returncode!0:failed.append(check.name)iffailed:print(\nQuality gate failed:)fornameinfailed:print(f-{name})return1print(\nAll quality checks passed.)return0if__name____main__:raiseSystemExit(main())如果项目没有 Ruff不要照抄改成项目实际命令。验证脚本应满足无交互退出码可靠输出清晰本地与 CI 一致不修改生产文件不依赖 Claude 解释结果。六、XML 验证脚本如果项目使用lxml和 XSD可以建立scripts/validate_xml.py示意from__future__importannotationsimportsysfrompathlibimportPathfromlxmlimportetree PROJECT_ROOTPath(__file__).resolve().parents[1]XSD_PATHPROJECT_ROOT/schemas/application.xsdCONFIG_ROOTPROJECT_ROOT/configdefbuild_safe_parser()-etree.XMLParser:returnetree.XMLParser(resolve_entitiesFalse,no_networkTrue,load_dtdFalse,recoverFalse,)defmain()-int:schema_documentetree.parse(str(XSD_PATH),parserbuild_safe_parser())schemaetree.XMLSchema(schema_document)failedFalseforxml_pathinsorted(CONFIG_ROOT.rglob(*.xml)):try:documentetree.parse(str(xml_path),parserbuild_safe_parser())schema.assertValid(document)print(fPASS{xml_path.relative_to(PROJECT_ROOT)})except(etree.XMLSyntaxError,etree.DocumentInvalid)asexc:failedTrueprint(fFAIL{xml_path.relative_to(PROJECT_ROOT)}:{exc},filesys.stderr,)return1iffailedelse0if__name____main__:raiseSystemExit(main())需要根据项目实际情况调整不一定所有 XML 使用同一个 XSD测试中故意非法的 XML 不应纳入正式配置扫描include/import 可能需要本地 resolver如果不用lxml继续使用项目现有工具不要仅为了 Hook 擅自增加依赖。七、Hooks建立自动门禁推荐采用两类 HookPostToolUse修改后运行轻量检查StopClaude 准备结束任务时运行完整质量门禁。项目级 Hook 放在.claude/settings.json基础配置示例{hooks:{PostToolUse:[{matcher:Write|Edit,hooks:[{type:command,command:python .claude/hooks/validate_changed_file.py,timeout:30}]}],Stop:[{hooks:[{type:command,command:python .claude/hooks/stop_quality_gate.py,timeout:900}]}]}}Hook 会通过 stdin 收到 JSON 事件数据。不要依赖脆弱的 shell 字符串截取建议用 Python 解析。轻量修改后检查.claude/hooks/validate_changed_file.pyfrom__future__importannotationsimportjsonimportsubprocessimportsysfrompathlibimportPathdefrun(command:list[str])-int:returnsubprocess.run(command,checkFalse).returncodedefmain()-int:eventjson.load(sys.stdin)tool_inputevent.get(tool_input,{})raw_path(tool_input.get(file_path)ortool_input.get(path)or)ifnotraw_path:return0pathPath(raw_path)ifpath.suffix.py:returnrun([sys.executable,-m,ruff,check,str(path),])ifpath.suffixin{.xml,.xsd}:returnrun([sys.executable,scripts/validate_xml.py,])return0if__name____main__:raiseSystemExit(main())注意PostToolUse发生在文件已经修改之后它不能撤销这次修改非零结果会反馈给 Claude促使它修复不适合每次编辑都运行完整测试套件。官方说明PostToolUse已经发生无法阻止原工具调用若返回错误stderr 会提供给 Claude。Hooks ReferenceStop Hook结束前完整验证.claude/hooks/stop_quality_gate.pyfrom__future__importannotationsimportjsonimportsubprocessimportsysdefmain()-int:eventjson.load(sys.stdin)# 防止 Stop hook 在持续失败时形成无意义的递归循环。ifevent.get(stop_hook_active):return0resultsubprocess.run([sys.executable,scripts/quality_gate.py],checkFalse,)ifresult.returncode!0:print(Quality gate failed. Fix the failures before declaring the task complete.,filesys.stderr,)return2return0if__name____main__:raiseSystemExit(main())对StopHook退出码0允许 Claude 停止退出码2阻止停止并把错误反馈给 Claude继续处理。Claude Code官方明确规定StopHook 的 exit code 2 会阻止结束并继续对话。Hooks exit-code 行为必须正确处理event.get(stop_hook_active)否则如果测试持续失败Claude 尝试结束、Hook 又阻止结束可能形成循环。八、Hook 不要做什么不要每次编辑都跑完整 pytest错误PostToolUse(Edit) → pytest 全量测试 20 分钟会严重拖慢开发。推荐分层编辑 Python → ruff 单文件/相关测试 编辑 XML → XML/XSD 校验 Claude Stop → 完整质量门禁 CI → 最完整验证不要让 Hook 自动修改文件例如不建议 Hook 自动运行ruffformat.否则 Claude刚修改文件Hook 又静默改一遍diff 来源不清楚。验证 Hook 最好是只读的ruffformat--check.ruff check.格式修复应由 Claude显式执行。不要在 Hook 中调用不可信的网络服务项目仓库中的.claude/settings.json和 Hook 脚本会随代码分发。团队成员在信任仓库前应该审查Hook 执行了什么是否读取环境变量是否发送代码或密钥是否修改 Git是否下载程序。不要把 Hook 当作 CI 替代品本地 Hook 可以被禁用修改跳过因环境缺失而失败用户未接受工作区信任而不生效。最终质量门禁仍应在 CI 中重复执行。九、结合 OpenSpec 的完整验证流程推荐工作流/opsx:propose add-xml-retry-policy ↓ 人工审查 specs/design/tasks ↓ /opsx:apply add-xml-retry-policy ↓ PostToolUse Hook轻量即时检查 ↓ /validate-change add-xml-retry-policy ↓ 三个只读 Subagent 独立审查 ↓ Stop Hook完整确定性质量门禁 ↓ /opsx:verify add-xml-retry-policy ↓ 人工查看 git diff ↓ /opsx:sync ↓ /opsx:archive ↓ CI 再执行完整门禁建议最终人工运行python scripts/quality_gate.pygitdiff--checkgitdiff-- src tests config schemas openspec十、建议的验证分层层级触发方式检查内容是否确定性RulesClaude读取相关文件编码、兼容、安全规范否/validate-change用户显式执行编排完整验证部分SubagentSkill/主 Agent委派独立语义复核否PostToolUse Hook文件修改后单文件 lint、XML/XSD是Stop HookClaude准备结束完整测试和质量门禁是CIpush/PR最终环境验证是最关键的设计原则1. 单一验证入口本地、Hook、Skill 和 CI 最终调用同一个命令python scripts/quality_gate.py2. 模型与执行证据分开模型负责理解 Spec发现遗漏建立追踪矩阵审查兼容性和设计。程序负责pytestXML/XSDlinttype checkOpenSpec格式校验退出码。3. Reviewer 不修改代码Subagent先只报告问题由主 Agent 根据报告修复。避免审查者一边审查、一边偷偷改变证据。4. PASS 必须有命令证据不接受看起来正确 应该能通过 tasks 已勾选接受pytest tests/test_config.py -q 12 passed python scripts/validate_xml.py 8 XML files passed5. Hook 只负责最小强制规则复杂业务判断不要完全放到 HookHook 应保持快速无交互可重复退出码稳定输出清楚。这套结构的最佳分工是Rules 让 Claude少犯错Skill 让验证不漏步骤Subagent降低自我审查偏差Hook 和 CI 用真实命令阻止未经验证的结果被宣称为完成。