ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Harness 最佳实践:Java Spring Boot 项目落地 OpenSpec + Claude Code 的配置骨架与验证清单

Harness 最佳实践:Java Spring Boot 项目落地 OpenSpec + Claude Code 的配置骨架与验证清单 1. 为什么 Spring Boot 老项目需要 OpenSpec Claude Code如果你手上是一个跑了三五年的 Java Spring Boot 业务系统需求文档散在 Confluence、口头约定藏在老员工脑子里、SQL 脚本靠 DBA 手动执行那你大概已经体会过「AI 写代码很快但改错一行配置要排查半天」的滋味。OpenSpec 解决的是「改什么」的问题它把需求变成可审计的变更工件Claude Code 解决的是「怎么改」的问题它按工件执行代码改动。两者放进 Harness 流水线才能让 AI 编码从「玩具」变成「生产级工程能力」。这套方案适合谁有历史包袱的 Spring Boot 业务系统、以增量改造为主的团队、存在大量隐性契约比如「订单状态 3 不能直接改 5」这种口头规则的项目。不适合小型 demo 或一次性脚本因为配置成本高于收益。核心思路就四句话需求先工件化知识先显性化执行先加护栏评审与验证必须分离。下面我按落地顺序把配置骨架、TaoToken 接入位置、本地跑通和流水线校验的动作全部拆开。2. TaoToken 前置统一 Key 与 API 通道的接入位置Claude Code 在 Harness 流水线里跑最怕的是每个环境配一套 Key、每个开发者本地又一套最后审计时说不清谁调了什么。TaoToken 的作用是提供一个统一的 API 通道你只需要在项目级配置里写一次 base_url 和 Key本地和流水线共用同一套接入点。接入位置有三个按优先级排第一项目根目录的.claude/settings.local.json这是 Claude Code 读取项目级配置的地方适合放模型通道和权限规则。第二Harness 的 Secret Manager把 Key 存成TAOTOKEN_API_KEY环境变量流水线执行时注入。第三本地开发时用.env文件但记得加进.gitignore。API 地址统一用https://taotoken.net/api不要带任何查询参数。官网入口是https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content第一次接入时从这里进控制台创建 Key。注意Key 只创建一次本地和流水线共用。如果团队成员各自创建审计时无法追溯调用来源护栏就形同虚设。创建 Key 的路径是控制台里的 API Keys 页面建议按项目命名比如springboot-order-svc。创建后立刻复制页面刷新就不再显示完整 Key。3. 可复制配置config.toml 与 settings.json 骨架这一章是全文最核心的部分配置写对了后面验证才有的放矢。我按「仓库结构 → config.toml → settings.json → hooks 脚本」的顺序给骨架。3.1 仓库目录结构先看整体布局配置文件放在哪一目了然repo/ ├─ AGENTS.md # OpenSpec 导航只写工作流和必读文件 ├─ CLAUDE.md # Claude 系统提示词 ├─ REVIEW.md # 只读评审代理提示词 ├─ docs/ │ ├─ architecture/ │ │ └─ implicit-contracts.md # 隐性约定联调必查 │ ├─ product/ │ └─ standards/ ├─ openspec/ │ ├─ changes/ # 进行中 归档的变更 │ └─ specs/ # 系统现有规范 ├─ .claude/ │ ├─ settings.local.json.example │ ├─ skills/ │ ├─ agents/ │ └─ hooks/ │ ├─ guard_write.py │ ├─ ensure_change_context.py │ └─ run_checks.sh ├─ src/ └─ pom.xml分层逻辑openspec/管改什么docs/管项目原本怎么工作配置文件管 AI 该怎么做hooks/permissions管哪些事不能做skills/agents管团队专用审查。3.2 config.toml 骨架Harness 流水线里用 config.toml 声明执行阶段和模型通道。下面这份可以直接复制改# .harness/config.toml [project] name springboot-order-svc language java build_tool maven [ai] provider taotoken base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY model claude-sonnet-4-20250514 max_tokens 8192 [openspec] changes_dir openspec/changes specs_dir openspec/specs require_proposal true require_verify true [guardrails] protected_paths [ src/main/resources/application*.yml, db/, sql/, deploy/, infra/, secrets/ ] allowed_commands [ mvn compile, mvn test, mvn package, git status, git diff ] blocked_commands [ git push, kubectl, terraform, rm -rf ] [hooks] pre_write .claude/hooks/guard_write.py pre_command .claude/hooks/ensure_change_context.py post_write .claude/hooks/run_checks.sh关键参数说明api_key_env指向环境变量名而不是明文 Key这样流水线注入时不会泄露protected_paths里的目录 Claude Code 无法写入这是硬护栏blocked_commands拦截危险命令allowed_commands放行安全命令。3.3 settings.local.json 骨架Claude Code 读取的权限配置和 config.toml 配合使用{ permissions: { allow: [ Read, Glob, Grep, Bash(mvn compile), Bash(mvn test), Bash(mvn package), Bash(git status), Bash(git diff) ], deny: [ Write(src/main/resources/application*.yml), Write(db/**), Write(sql/**), Write(deploy/**), Write(infra/**), Write(secrets/**), Bash(git push), Bash(kubectl *), Bash(terraform *), Bash(rm -rf *) ] }, env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: ${TAOTOKEN_API_KEY} } }deny列表里的路径和 config.toml 的protected_paths保持一致双重保险。env里用${TAOTOKEN_API_KEY}引用环境变量本地跑之前先export TAOTOKEN_API_KEY你的Key。3.4 hooks 脚本骨架三个钩子各司其职。guard_write.py在写入前检查路径是否在保护列表#!/usr/bin/env python3 import sys, os, fnmatch PROTECTED [ src/main/resources/application*.yml, db/*, sql/*, deploy/*, infra/*, secrets/* ] def is_protected(path): for pattern in PROTECTED: if fnmatch.fnmatch(path, pattern): return True return False if __name__ __main__: target sys.argv[1] if len(sys.argv) 1 else if is_protected(target): print(f[GUARD] 拒绝写入受保护路径: {target}) sys.exit(1) sys.exit(0)ensure_change_context.py在命令执行前校验是否有活跃变更#!/usr/bin/env python3 import sys, os CHANGES_DIR openspec/changes def has_active_change(): if not os.path.isdir(CHANGES_DIR): return False for name in os.listdir(CHANGES_DIR): if name ! archive and os.path.isdir(os.path.join(CHANGES_DIR, name)): return True return False if __name__ __main__: if not has_active_change(): print([CONTEXT] 无活跃变更禁止执行代码改动命令) sys.exit(1) sys.exit(0)run_checks.sh在写入后自动跑编译和测试#!/bin/bash set -e echo [CHECK] 开始编译... mvn compile -q echo [CHECK] 开始测试... mvn test -q echo [CHECK] 打包验证... mvn package -DskipTests -q echo [CHECK] 全部通过4. 验证请求本地跑通与流水线校验配置写完不算完得验证它真的生效。我分本地和流水线两步走。4.1 本地跑通第一步设置环境变量并确认通道可达export TAOTOKEN_API_KEY你的Key curl -s -o /dev/null -w %{http_code} \ https://taotoken.net/api/v1/models \ -H Authorization: Bearer $TAOTOKEN_API_KEY返回 200 说明 Key 和通道都正常。如果返回 401检查 Key 是否复制完整返回 404检查 base_url 是否多了斜杠。第二步在项目根目录启动 Claude Code执行一次 OpenSpec 提案claude # 在交互界面输入 /opsx:propose 新增订单超时自动取消功能预期结果openspec/changes/下生成一个以变更名命名的目录里面有proposal.md、design.md、tasks.md三个文件。如果目录没生成检查openspec/changes是否存在且可写。第三步验证护栏是否生效。尝试让 Claude Code 修改受保护文件# 在 Claude Code 交互界面输入 请修改 src/main/resources/application.yml 里的数据库连接预期结果被guard_write.py拦截输出[GUARD] 拒绝写入受保护路径。如果没拦截检查 hooks 路径是否配置正确、脚本是否有执行权限。第四步验证无变更时禁止改动# 先归档当前变更 /opsx:archive # 然后尝试改代码 请修改 OrderService.java 的取消逻辑预期结果被ensure_change_context.py拦截提示无活跃变更。4.2 流水线校验Harness 流水线里加一个校验阶段把上面四步自动化# .harness/pipeline.yaml stages: - name: openspec-validate steps: - script: - export TAOTOKEN_API_KEY$TAOTOKEN_API_KEY - test -d openspec/changes || exit 1 - test -f AGENTS.md || exit 1 - test -f CLAUDE.md || exit 1 - test -f docs/architecture/implicit-contracts.md || exit 1 - python3 .claude/hooks/guard_write.py src/main/resources/application.yml exit 1 || echo guard ok - bash .claude/hooks/run_checks.sh这段脚本做了三件事检查仓库骨架文件是否齐全、验证 guard_write 对受保护路径确实返回非零、跑一遍编译测试。任何一步失败流水线就红变更不允许合并。提示流水线里的TAOTOKEN_API_KEY从 Harness Secret Manager 注入不要写在 pipeline.yaml 里。本地和流水线共用同一个 Key审计时调用来源清晰。5. 本篇常见错排查配置落地过程中下面这几个坑我踩过你大概率也会遇到。错误一ANTHROPIC_BASE_URL没生效请求打到了默认地址。现象是 Claude Code 报连接超时或 401。原因是 settings.local.json 里的 env 没被读取或者环境变量名写错。排查方法在 Claude Code 里执行echo $ANTHROPIC_BASE_URL确认输出是https://taotoken.net/api。如果为空检查 settings.local.json 是否在.claude/目录下以及 JSON 格式是否合法。错误二hooks 脚本没有执行权限。现象是护栏完全不生效Claude Code 能随意改受保护文件。原因是脚本没有x权限。修复chmod x .claude/hooks/guard_write.py chmod x .claude/hooks/ensure_change_context.py chmod x .claude/hooks/run_checks.sh错误三/opsx:propose报「changes 目录不存在」。原因是 openspec 目录没初始化。修复mkdir -p openspec/changes openspec/specs touch openspec/changes/.gitkeep错误四流水线里mvn test失败但本地通过。大概率是流水线环境没有注入TAOTOKEN_API_KEY导致 Claude Code 生成的测试代码引用了不存在的配置。检查 Harness Secret Manager 里的变量名是否和 config.toml 的api_key_env一致。错误五guard_write.py 拦截了正常写入。现象是改src/main/java/下的文件也被拦。原因是 fnmatch 模式写得太宽比如*application*会匹配到Application.java。修复把模式收窄成src/main/resources/application*.yml只匹配资源目录下的配置文件。错误六变更归档后ensure_change_context.py仍然放行。原因是 archive 目录被当成了活跃变更。检查脚本里的if name ! archive判断是否生效或者归档时把变更移到openspec/changes/archive/子目录下。6. 下一步把评审和验证拆开配置跑通只是第一阶段。接下来你要做的是把「实现、评审、验证」彻底分离/opsx:verify只检查实现和变更工件是否一致/prepare-review生成人工评审摘要/spring-architecture-review检查 Spring 分层是否被破坏/sql-risk-review检查 SQL 风险。这些能力封装成 skills 和 subagents不塞进主提示词才能复用和演进。如果你还在验证模型通道阶段可以先到模型对话页面确认 Key 能正常调用如果准备把 Claude Code 长期接入日常编码和 Agent 流程Coding Plan 页面有更完整的配额和通道说明接入文档里有 settings.json 的完整字段解释。三个入口按你的当前阶段选不用一次全看完。最后留一个实操建议第一版 proposal 大概率不靠谱人工审计不能省。design 阶段修正的成本远低于 apply 之后返工。变更边界模糊时拆成多个小变更每个变更单独走 propose → apply → verify → archive比一个大变更塞进去再拆要省事得多。
返回列表