Thomas Schilling(tschuehly,PhotoQuest 创始人,Spring/Kotlin/HTMX 圈常客,做过 Spring ViewComponent)在 Spring I/O 2026(巴塞罗那)做了一场 Claude Code for Spring Developers。主张很冲:2026 年还不用 Claude Code,你就在白白错过一次巨大的效率提升。

但这场 talk 真正的价值在它的结构:他用同一个功能反复迭代——先演示「什么都不配」的 vibe coding 怎么翻车,再一层层加上 Context、Skills、Hooks、MCP、Workflows,最后收拢成一套可复用的 “agent stack”。他自己的 Claude Code 使用数据也为这套方法背书:3,700+ commits、1,700+ sessions、11k+ prompts、提交速度约 ——连这些 slides 本身都是用 Claude Code 做的。

本文以他的 slides 八个板块为骨架;其中 /interview 和 Gradle 代理 hook 两处,参考了他配套的两篇博客(见文末)补全细节。

主线:一个功能,从翻车到工程化#

Demo 是 PhotoQuest 里的一个照片表情投票游戏(库表就叫 ranking_game):大屏轮播照片,宾客扫码加入,每人有一份固定的表情额度(3❤️ + 3😂 + 3😮)投给喜欢的照片,限时参与,最后揭晓每个表情类别下票数最高的前三张。同一功能他做了很多遍,每遍都比上一遍多给 Claude 一层支持。

agent 的工作循环是 Read → Plan → Act → Observe → Repeat。顺的时候很顺:给计时加上 1–30 分钟校验,它新建 InvalidTimerDurationException、加上 if (timerSeconds < 60 || timerSeconds > 1800)、确认编译通过,全程 1 分 24 秒。

Iteration 1(vibe coding 基线,不写 CLAUDE.md、不配 skill、不规划,直接让它"把游戏做出来")很难看:

指标 Iteration 1(裸跑)
测试 0
人工抓出的 bug 8
漏掉的关键状态 整个 REVEAL(揭晓)状态被跳过
其它 JSON 直接渲染到页面上、图片重叠、票数算错
上下文占用 98%(202,719 tokens)

他给这页留了贯穿全场的一句:

The agent only knows what’s in context.

后面每个板块,本质都在解决同一个问题:怎么把"该进上下文的东西"可靠地喂进去(也及时移出去)。 加了 onboarding 之后,同一个功能:

指标 Iteration 1 Iteration 2
测试 0 37
设计决策 0(Claude 自己猜) 20(interview 逼出来的)
CLAUDE.md 规则 0 8
子代理会话 0 3

基础:把 Claude Code 当一个"最快的同事"#

  • 接口任选:CLI、VS Code / IntelliJ、桌面端、Web、手机,甚至 Slack 和 GitHub Actions。
  • 挑模型、调力度:简单高频用 Sonnet(便宜,适合跑大量 subagent);复杂架构、跨文件重构、规划、调试用 Opus。再叠 /effort 档位(low/medium/high/max)。
  • 安全网 checkpoints/rewind 回退、/branch 开实验分支——“experimentation is free”,跑歪了 rewind 回去就行。
  • subagent:开独立上下文去调研,主会话保持精简。例如让 subagent 摸清 SSE 通知链路(Guest 上传 → pg_notify → NotificationService → Reactor Sink → SSE),主会话不被淹没。
  • headlessclaude -p "..." 跑无界面;PR 评论里 @claude 触发 GitHub Actions。

他特意点出 “The Spring advantage”:强约定降低歧义、编译期校验早抓错、内建可测试性、可预测的结构让 agent 易于导航——“Your stack is your advantage.” 平时嫌弃的"框架太有规矩",恰恰是 agent 最能稳定发挥的环境。

Context:每一次会话都是"第一天"#

Every session is day one.

Claude 每开一个会话都是失忆的新同事,上下文就是你给它做 onboarding 的唯一手段。翻车的典型:一次没开规划、用手机随口提需求,结果它把卡片排成"A4 一页 6 张",而真实要求是"A6 一页 1 张"。

工程化手段分几层:

CLAUDE.md 是长出来的,不是写出来的。 先放 5 行最关键信息,正常用,每出现一次不想要的行为就补一条规则,直到稳定:

Every rule needs to earn its place through a real failure.

里面的规则很 Kotlin/Spring:改完 Kotlin 必须 ./gradlew compileKotlin compileTestKotlin没跑测试/演示证明正确前不许标完成;多实例下别用内存去重,要用 DB 检查和 AdvisoryLock.kt 做分布式一致。

按路径加载的 scoped rules(.claude/rules/,碰到对应目录才加载,主上下文保持干净:

.claude/rules/
├── kotlin-conventions.md   (src/main/kotlin/**)
├── viewcomponent.md        (src/main/kotlin/page/**)
├── tailwind-daisyui.md     (src/**/*.html)
├── testing.md              (src/test/**)
└── payment.md              (src/**/payment/**)

记忆三层CLAUDE.md(最关键、进 git)→ .claude/rules/(按路径条件加载)→ auto-memory(跨会话个人笔记,本地不进 git)。

管好上下文预算/context 看占用、/compact 手动压缩。但他更推荐主动收尾、开新会话——上下文越满表现越退化。做法:把状态记进 markdown 计划文件,手动结束当前会话,给下一个会话写一段 continuation prompt。

Skills:把资深工程师会"口述"的东西写下来#

If a senior dev wrote down how they approach architecture, git flow, and domain knowledge — that’s a skill.

CLAUDE.md 与 skill 的根本区别是 always-on 还是 on-demand

  • CLAUDE.md(常驻):会话一开始就加载,适合"永远要做 X";代价是一直占上下文、注意力会从当前任务漂走。
  • Skills(按需):开始只加载描述,调用时才载入完整内容,适合参考文档和可复用工作流。

他的核心 skill:/interview(AI 主导的结构化访谈)、/tdd-task(严格 RED→GREEN→REFACTOR)、/test(跑测试、只报失败)、/commit(按功能分组提交,SKILL.md 就 8 行)。skills 库见 jvmskills.com,专为 JVM 生态精选整理(Spring Boot、jOOQ、PostgreSQL、Kotlin、testing)。

/interview 是这节重头,直接针对 Iteration 1 的"瞎猜":subagent 先探索代码库,再用决策树逐项 interview——入口放哪、照片来源、宾客怎么加入、提交流程、反作弊(选了服务端强制)、存储模型、最少照片数、宾客交互。一轮产出 171 行 spec、8 轮决策点

他还演示怎么 review spec:通读,用 % 标可疑决策,对 10+ 处追问,逐条判断价值——Claude 主动提的 10 个改动里 8 个被判定不必要

最有冲击力的反例是 “missing nav link” 问题:7 个阶段都实现了、17 个测试全绿,但功能根本点不进去——没人问过"用户怎么走到这儿"。结论是 “Fix the process, not just the bug”:于是他迭代了 /interview 这个 skill 本身——把强制话题固定为"入口、用户从头到尾的旅程、边界情况、状态转移、终止态与死胡同",并要求导航类 user story 排最前。结果:26 条 user story,零遗漏入口

他博客里用 AskUserQuestionTool 规划 Spring Security 7 迁移是同一套 /interview 打法:两轮 interview 把"给 JWT 加字段"问成"整体迁离 Supabase Auth、删 ~700 行鉴权代码",产出 900 行实现级 spec。先把问题问清楚再写代码是这套方法的内核。

Hooks:让规则真正"粘住"#

CLAUDE.md 和 skill 是软约束,模型可能漂走;hook 提供确定性。生命周期:SessionStart → PreToolUse → PostToolUse → SessionEnd;四种类型:command/http/prompt/agent

他实际在用的:

事件 工具 脚本 作用
PreToolUse Bash git-guardrails.sh 拦危险 git 命令
PreToolUse Bash pre-commit-gate.sh lint/编译没过不许提交
PostToolUse Edit/Write post-edit-lint.sh 把 lint 违规反馈回去
SessionEnd stop-uncommitted-check.sh 有未提交改动就告警

PreToolUse 用 exit code 2 硬拦截(Claude 无法继续):

DANGEROUS_PATTERNS=("git push" "git reset --hard" "git clean -fd" \
  "git branch -D" "git checkout ." "git restore .")
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
  if echo "$COMMAND" | grep -qE "$pattern"; then
    echo "BLOCKED: '$COMMAND' matches '$pattern'" >&2
    exit 2
  fi
done

他甚至用 hook 强制走 skill 而非裸命令——拦下 gradlew test,提示 “Use the /test skill instead”。PostToolUse 是自纠错闭环:导入了 Jackson 2 的 ObjectMapper,hook 立刻拦下并提示改用 Jackson 3 的 JsonMapper——这个错以后再也不会犯了。一句总结:

Anything you can put in a hook — put it in a hook.

他那个 Gradle 代理 hook 是 JVM 实战:Claude Code Web 沙箱走 HTTP 代理,但 Java 的 HttpURLConnection 无视 https_proxy,Gradle 每次 UnknownHostException;用 PreToolUse hook 把代理写进 ~/.gradle/gradle.properties 并预热依赖缓存解决。

MCP:让 agent 把 IDE 当 API 调用#

MCP 是连接 AI 与外部工具的开放标准。他接了 Sentry(错误监控)、Linear(任务)、JavaDoc Central(最新 JVM 库文档)、IntelliJ(reformat_file、rename、execute_run_configuration),还用 Spring AI 自己写 MCP server。

最让 Spring 开发者有共鸣的,是 agent 自身的开发体验对比:

没有 MCP 有 IntelliJ MCP
sed 重排格式 reformat_file
手动修 import 自动优化 import
靠 Gradle 启动 execute_run_configuration

The IDE becomes an API that agent calls.

落地时他不直接暴露裸 MCP,而是包进 skill:/restart = 先停掉旧应用 → 用 MCP 启动(execute_run_configuration())→ 等就绪 → 查错误日志。

Workflows:五个层级,按问题匹配打法#

核心:不是每个任务都用同一套流程,要按问题类型匹配。

  1. Human in the loop:描述、看着做、随时纠偏。适合范围还小、盯得过来的时候。
  2. Plan Mode(Shift+Tab 或自发进入):探索、原型、迭代,不需预先写 spec。适合它老猜错、需求只在你脑子里的时候。
  3. Spec-Driven:先和领域/UX/产品敲 spec 再写代码。适合 What 不明显、只有 Why 的时候。
  4. Drift Problem:跨 7 个阶段时,各 skill 触发得越来越不稳定——agent 不是确定性机器,上下文越满,注意力越容易跑偏
  5. The Ralph Loop每个阶段开一个全新 agent(不累积漂移),Interview → Spec → Plan → Phase 1 Agent → Phase 2 Agent → …。

两条配套纪律:

  • 从 checklist 到 contract:用扁平 markdown 清单(纯文字、无强制)时只产出 39 个测试;改用 TodoWrite 把任务变成可跟踪的状态后,涨到 60 个让"指令"变成"被跟踪的状态"。
  • 多模型 review:同分支同 prompt 让两个不同模型当 reviewer,Claude 抓出计时器挂死/预算竞态,另一个模型抓出 manager 控件暴露/脚本注入——不同模型盲区不同。

配套工具#

  • 隔离 blast radius/sandbox 在 OS 层围住文件系统和网络;更彻底的做法是 Docker microVM——一次性、隔离,agent 跑飞了直接丢掉。
  • 语音输入:handy.computer(开源、本地),说话比打字快,而且"说出来"会暴露你的推理。
  • 并行不打架:Worktrunk——每条分支配独立 git worktree、专属 Postgres、专属 LocalStack,多 agent 并行零冲突。
  • 整干净历史/rebase-commit 把 46 个调试提交整成 10 个"功能+对应测试"的原子提交。

落点:你的"新工作"——一套会复利的 agent stack#

talk 最后把一切收拢成四层:

是什么 关键点
CLAUDE.md 项目上下文 因"真实失败"一条条长出来;下次会话从上次终点开始
skills/ 你早该写的文档 /interview/tdd-task/test/commit/restart;按你的栈定制
hooks/ 真正粘住的规则 PreToolUse/PostToolUse;约束叠加、错误不复发
workflow 五个层级 按问题类型匹配;改 bug ≠ 做复杂功能

他用 Thoughtworks 一句话点题:

Engineering quality doesn’t disappear when AI writes code. It migrates to specs, tests, constraints, and risk management.

以及几句很冲的收尾:当实现变便宜,瓶颈挪到判断力——建什么、对不对、谁担后果;“Building bad software has never been easier”,速度免费、纪律得你自己上;“You will fall behind” 不是因为 AI 取代你,而是因为用它的工程师每天都在积累复利

几点笔记(个人观点)#

  1. 这场 talk 最聪明的是它的"对照实验"结构。 它没吹 AI 多神,而是先摆出 Iteration 1 的难看数据(0 测试、8 bug、漏掉整个 REVEAL 状态、98% 上下文),再让你看着同一功能在加了 Context/Skills/Hooks 后变成 37→60 个测试。它证明了收益不来自模型,而来自你给它搭的脚手架。

  2. “The agent only knows what’s in context” 几乎是整套方法的公理。 CLAUDE.md、scoped rules、skills、hooks、subagent、Ralph loop 拆开是六件事,合起来只解决一个问题:在正确时刻,把正确的东西放进、并及时移出上下文。 想清楚这点,就能自己判断一个新 /xxx 该属于哪一层。

  3. 对 Spring 开发者,“你的栈就是你的优势"要敢信。 强约定、编译期校验、可预测结构、内建可测试性,正是 agent 最需要的护栏。把 ./gradlew compileKotlinAdvisoryLock.kt、Jackson 3 import 检查这类很具体的 JVM 规则塞进 hook,等于把 Spring 的确定性直接喂给不确定的模型——这点是 Python 那种弱约定栈学不来的。

  4. /interview 这条线最值得直接借鉴。 它的关键不只是"先问后写”,而是当流程出问题时去改 skill 本身,而不是改这次的代码(“fix the process, not the bug”)。“missing nav link”——17 个测试全绿但功能点不进去——是对"测试覆盖 ≠ 需求覆盖"最生动的提醒。

  5. Hooks 是最被低估的一层。 CLAUDE.md 和 skill 都是软约束,模型心情不好就漂了;只有 hook(PreToolUse 硬拦截 + PostToolUse 自纠错)是真确定性。我打算先做两个最低成本的:git-guardrails(拦 push/reset --hard)和 pre-commit-gate(编译/lint 不过不许提交)。

  6. 几点保留:Ralph loop、Worktrunk 这类重型工作流对个人 SaaS 划算,搬到有合规和数据边界的团队前得先算清权限和成本;“不用就落后/每天复利"有 FOMO 成分,能复用的是他的 stack,不是焦虑;他给的数字(171 行、26 user story、60 测试)是单项目体感,别当 KPI——真正要学的是**“每条规则都因一次真实失败而生"这条克制原则**,否则 CLAUDE.md 很快膨胀成没人看的垃圾场。

参考资料#