vft-rules:Claude Code 插件级规则注入与自动检查
为什么需要它
想让 Claude 写代码时「一定」遵守团队规范,只写说明文字是不够的:
| 手段 | 什么时候生效 | 能保证遵守吗 |
|---|---|---|
CLAUDE.md / .claude/rules/ | 会话开始或读到匹配文件时加载 | 不能,模型可能遗漏 |
| skill | 描述命中时加载 | 不能 |
| 钩子 + 检查脚本 | 每次读写文件时由 Claude Code 自动执行 | 能,违规会被退回修改 |
另外,插件不能直接提供 .claude/rules/:官方只加载项目和用户目录下的规则文件,插件根目录的 CLAUDE.md 也不会被当作项目上下文。插件能带的是 skill、agent、钩子等。
vft-rules 用钩子把两件事都做了:
- 读写文件前注入规范:文件路径命中规则的
paths时,把规则正文注入给模型,效果等同.claude/rules/。 - 写完文件后自动检查:运行规则声明的检查项,error 级违规直接退回,模型必须修复后才能继续。
装一次插件,所有项目都生效;规则跟着插件升级,改一处各处同步。
工作流程
Claude 读/改 xxx.vue
→ PreToolUse:inject.mjs 匹配 rules/*.md 的 paths
命中且本会话没注入过 → 注入规则正文
→ 工具执行(写入文件)
→ PostToolUse:check.mjs 运行规则里的 checks
有 error → 退回模型修复
只有 warn → 提示,不阻断
上下文压缩 / clear
→ SessionStart:reset.mjs 清注入记录,下次命中重新注入
三个脚本都在 plugins/vft-kit/scripts/rules/,任何内部异常都会静默放行,不会卡住会话。
内置规则:vue-sfc
适用于 **/*.vue,内容覆盖 <script setup>、模板、TSX 渲染函数、响应式副作用和样式。其中能用文本规则可靠判断的条目会自动检查:
| 检查项 | 级别 | 说明 |
|---|---|---|
no-with-defaults | error | Vue ≥ 3.5 用 props 解构声明默认值,不用 withDefaults(按项目实际安装的 vue 版本判断,低版本自动跳过) |
no-v-if-with-v-for | error | 同一元素不能同时写 v-if 和 v-for |
tsx-no-quoted-directive | error | TSX 里 v-auth="'a:b'" 多了一层引号,指令收到的是带引号的字符串 |
v-for-needs-key | warn | v-for 必须带 :key |
tsx-no-kebab-component | warn | TSX 里 <el-button> 这类小写组件标签不会被自动导入解析 |
语义类规范(比如「条件判断别漏 .value」「SSR 顶层别碰 window」)只注入说明,由模型遵守。
内置规则:style-layout
适用于 **/*.vue 和 css / scss / sass / less / styl 样式文件,主要解决还原 MasterGo 等设计稿时,模型按图层坐标把整页写成绝对定位的问题:
- 文档流优先:块级元素自然排列,横向排列与对齐用 flex;设计稿的「自动布局」直接翻译成 flex 属性。
position: absolute只用于角标、浮层、遮罩、装饰层等脱离文档流的元素。 - 居中按顺序选:flex 居中 → 定宽块
margin: 0 auto→ 脱离文档流的元素用left: 50%+transform: translate(-50%, -50%)。不用按设计稿算出来的left: 137px做「看起来居中」。 - 先看 Vue 版本:Vue 2 项目通常要兼容旧 WebView,不用 CSS Grid,flex 的
gap也慎用(iOS < 14.5、Chrome < 84 不支持)。Vue 3 项目不受这一条限制。
| 检查项 | 级别 | 说明 |
|---|---|---|
vue2-no-grid | error | 项目安装的 vue 主版本 < 3 时,不能出现 display: grid / inline-grid / -ms-grid 和任何 grid-* 属性(含 grid-gap、grid-column-gap、grid-auto-*、grid 简写)。检查 .vue 的 <style> 块、样式文件,以及模板里的 style / :style(含 gridTemplateColumns 驼峰写法)。scss/less 变量 $grid-gap 和类名 .grid-item 不算。非 Vue 项目或 Vue 3 自动跳过 |
vue2-flex-gap | warn | Vue 2 项目里,同一规则块同时写了 display: flex 和 gap / row-gap / column-gap 时提示改用 margin |
absolute-hardcoded-layout | warn | 同一文件里「position: absolute + 上下、左右两个方向都写死非零长度」的规则块达到 3 个时提示。left: 50% 的居中写法、单个角标不计入;兼容 scss/less 嵌套 |
确认项目只跑在新内核上时,可以在 .claude/vft-rules.json 里把 vue2-no-grid、vue2-flex-gap 设为 off。
这两项只拦 Claude 的写入。想让人手写的样式也被拦下,在项目 .stylelintrc 的 rules 里加:
'property-disallowed-list': ['/^grid/'],
'declaration-property-value-disallowed-list': { display: ['/grid/'] },
内置规则:package-json
适用于 **/package.json,要求依赖一律写精确版本号,不写 ^1.3.5、~4.17.21、>=1.0.0、* 这类范围。范围版本在重装、换机器、CI 构建或锁文件丢失时会装到不同的小版本,老项目容易因此构建失败。
| 检查项 | 级别 | 说明 |
|---|---|---|
pin-exact-version | error | 检查 dependencies、devDependencies、optionalDependencies。提示里给出 node_modules 中实际安装的版本,按它改,不要只删掉 ^(那等于降到范围下限)。workspace:*、catalog:、file:、git 地址、URL 放行;npm: 别名要写精确版本;peerDependencies 描述兼容范围,不检查 |
安装时加 -E(pnpm add -E xxx),或在项目 .npmrc 写 save-exact=true,就不用装完再手改。对外发布、需要保留范围版本的库,在 .claude/vft-rules.json 里把 pin-exact-version 设为 off。
项目继承与私有规则
在项目根目录建 .claude/ 下的这几个文件。钩子从被操作的文件一路向上查找,所有层级由外到内合并:monorepo 根放一份对全仓生效,子项目再放一份继续追加或覆盖(disable 取并集,检查级别内层覆盖外层,checks.mjs 同名内层覆盖)。
.claude/vft-rules.json # 关闭规则、调整检查级别
.claude/vft-rules/*.md # 私有规则
.claude/vft-rules/checks.mjs # 私有自动检查
继承内置规则并追加
frontmatter 写 extends: vue-sfc,项目正文会追加到内置规范后面,checks 合并:
---
name: my-vue
extends: vue-sfc
checks:
- no-v-loading
---
- 加载态用 v-spin,不用 v-loading。
- 列表页用 useCrudPage + <crud-page>。
不写 extends 且与内置规则同名时,整条替换;名字不同就是新增规则,可以匹配任意文件类型:
---
name: my-api
paths:
- 'src/apis/**/*.ts'
checks:
- no-axios-direct
---
- 接口统一走 request 封装,不直接用 axios。
私有自动检查
checks.mjs 默认导出一个对象,键是检查 id,同名会覆盖内置检查:
export default {
'no-v-loading': {
level: 'error', // error 阻断 / warn 提示
// src: 文件全文;blocks: .vue 文件切好的 template/scripts(其他文件为 null)
run: ({ src }) => {
const i = src.search(/\sv-loading[\s=>]/);
return i < 0 ? [] : [{ line: src.slice(0, i).split('\n').length, message: '加载态用 v-spin' }];
},
},
};
关闭与调整级别
{
"disable": ["vue-sfc"],
"checks": { "v-for-needs-key": "off", "tsx-no-kebab-component": "error" }
}
在 Codex 或命令行里用
钩子只在 Claude Code 里自动运行。Codex 或手动检查时直接调用同一份脚本:
# 检查文件,有 error 时退出码为 1,可接进 lint-staged / CI
node "$VFT_PLUGIN_ROOT/scripts/rules/check.mjs" src/**/*.vue
# 查看某个文件适用的规则正文
node "$VFT_PLUGIN_ROOT/scripts/rules/inject.mjs" src/App.vue
踩坑与说明
- zsh 传文件列表:
check.mjs $files在 zsh 里不会按行拆分,整串会当成一个参数,结果显示「没有发现问题」。用find ... -print0 | xargs -0 node check.mjs。 - 会话去重:同一会话里一条规则只注入一次,记录存放在
CLAUDE_PLUGIN_DATA(没有时用系统临时目录)。上下文压缩后会自动重新注入。 - 修改插件规则后:需要升级插件版本并刷新插件缓存(见 plugin-refresh),新会话才会读到新规则。项目内
.claude/vft-rules/的改动即时生效。 - 自测:改完规则模块跑
node plugins/vft-kit/scripts/rules/selftest.mjs。

还没有留言,来发表第一条吧~