单一事实源:在一个项目里同时管理 AGENTS、CLAUDE、GEMINI 和 Cursor Rules
2026-02-11
· 585 字 · 约 3 分钟
在同一个仓库里同时支持 Claude Code、Codex、Gemini CLI、Cursor 时,最容易遇到的问题是:同一条规则写了四份,最后四份不一致。
本文给一个可落地方案:单一事实源 + 多工具适配层 。
目标
只维护一份核心规则。
允许各工具保留少量差异补丁。
自动生成目标文件,减少手工编辑。
子目录可以加增量规则,不污染全局。
推荐目录
1
2
3
4
5
6
7
8
9
10
11
12
docs/ai/
core.md
tooling/
claude.md
codex.md
gemini.md
cursor.md
scopes.list
scopes/
content/blog.md
scripts/
sync-ai-configs.sh
工作流
在 docs/ai/core.md 写所有工具共享规则(单一事实源)。
在 docs/ai/tooling/*.md 写各工具专属补丁。
在 docs/ai/scopes.list 列出需要子目录增量规则的路径。
在 docs/ai/scopes/*.md 写对应子目录的增量规则。
运行脚本生成目标文件。
生成命令
1
2
3
4
5
6
7
8
# 只预览,不落盘
scripts/sync-ai-configs.sh
# 实际写入
scripts/sync-ai-configs.sh --apply
# 强制覆盖已有手工文件(谨慎)
scripts/sync-ai-configs.sh --apply --force
脚本全文(可直接复制)
点击展开 sync-ai-configs.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR= " $( cd " $( dirname " ${ BASH_SOURCE[0]} " ) /.." && pwd) "
AI_DIR= " $ROOT_DIR/docs/ai"
APPLY= 0
FORCE= 0
while [[ $# -gt 0 ]] ; do
case " $1" in
--apply) APPLY= 1; shift ;;
--force) FORCE= 1; shift ;;
*) echo "Usage: $0 [--apply] [--force]" >&2; exit 2 ;;
esac
done
require_file() { [[ -f " $1" ]] || { echo "Missing file: $1" >&2; exit 1; } ; }
read_file() { cat " $1" ; }
is_generated_file() {
[[ -f " $1" ]] || return 1
head -n 1 " $1" | rg -q "AI-CONFIG: GENERATED"
}
write_target() {
local target= " $1" content= " $2"
mkdir -p " $( dirname " $target" ) "
if [[ -f " $target" && $FORCE -ne 1 ]] ; then
if ! is_generated_file " $target" ; then
echo "SKIP (manual file): ${ target#$ROOT_DIR/} "
return 0
fi
fi
if [[ $APPLY -eq 1 ]] ; then
printf "%s\n" " $content" > " $target"
echo "WRITE ${ target#$ROOT_DIR/} "
else
echo "PLAN ${ target#$ROOT_DIR/} "
fi
}
build_root_doc() {
local tool= " $1"
cat <<EOF
<!-- AI-CONFIG: GENERATED. DO NOT EDIT DIRECTLY. -->
# $(tr '[:lower:]' '[:upper:]' <<<"$tool") Instructions
$(read_file "$AI_DIR/core.md")
$(read_file "$AI_DIR/tooling/$tool.md")
EOF
}
build_scope_doc() {
local tool= " $1" scope= " $2" scope_file= " $3"
cat <<EOF
<!-- AI-CONFIG: GENERATED. DO NOT EDIT DIRECTLY. -->
# Scope Instructions: $scope
本文件仅定义当前目录的增量规则,不重复全局规则。
$(read_file "$scope_file")
$(read_file "$AI_DIR/tooling/$tool.md")
EOF
}
build_cursor_rule() {
local scope= " $1" scope_file= " $2"
cat <<EOF
---
description: Generated scope rule for $scope
globs:
- $scope/**
alwaysApply: false
---
<!-- AI-CONFIG: GENERATED. DO NOT EDIT DIRECTLY. -->
# Cursor Scope Rule: $scope
$(read_file "$scope_file")
EOF
}
require_file " $AI_DIR/core.md"
require_file " $AI_DIR/scopes.list"
require_file " $AI_DIR/tooling/claude.md"
require_file " $AI_DIR/tooling/codex.md"
require_file " $AI_DIR/tooling/gemini.md"
require_file " $AI_DIR/tooling/cursor.md"
write_target " $ROOT_DIR/AGENTS.md" " $( build_root_doc codex) "
write_target " $ROOT_DIR/CLAUDE.md" " $( build_root_doc claude) "
write_target " $ROOT_DIR/GEMINI.md" " $( build_root_doc gemini) "
while IFS= read -r scope || [[ -n " $scope" ]] ; do
[[ -z " $scope" || " $scope" = ~ ^# ]] && continue
scope_id= " ${ scope//\/ /-} "
scope_file= " $AI_DIR/scopes/ ${ scope} .md"
require_file " $scope_file"
write_target " $ROOT_DIR/ $scope/AGENTS.md" " $( build_scope_doc codex " $scope" " $scope_file" ) "
write_target " $ROOT_DIR/ $scope/CLAUDE.md" " $( build_scope_doc claude " $scope" " $scope_file" ) "
write_target " $ROOT_DIR/ $scope/GEMINI.md" " $( build_scope_doc gemini " $scope" " $scope_file" ) "
write_target " $ROOT_DIR/.cursor/rules/generated- ${ scope_id} .mdc" " $( build_cursor_rule " $scope" " $scope_file" ) "
done < " $AI_DIR/scopes.list"
[[ $APPLY -eq 0 ]] && echo -e "\nDry run only. Use --apply to write files."
生成结果
脚本会生成或更新:
根目录:AGENTS.md、CLAUDE.md、GEMINI.md
子目录:<scope>/AGENTS.md、<scope>/CLAUDE.md、<scope>/GEMINI.md
Cursor 规则:.cursor/rules/generated-<scope>.mdc
说明:
默认会跳过手工文件(非模板生成文件),避免误覆盖。
目标文件头部有 AI-CONFIG: GENERATED 标记,便于识别。
子目录规则示例
如果 content/blog 有特殊约束,只需要写增量:
文章要有明确日期锚点。
能用表格/列表时优先表格/列表。
工具能力对比要优先引用官方链接。
这样全局规则继续在根目录生效,子目录只补差异。
为什么不建议一份文件硬链给所有工具
可以共享大部分内容,但不建议 100% 共用单文件,原因有三个:
工具语义不同,同一句规则执行效果可能不同。
各工具有专属能力(rules/policy/skills),需要少量补丁。
版本迭代快,强耦合会增加回归风险。
实践上,建议共享 80%-90%,剩下 10%-20% 留给工具适配层。
流程图
flowchart TD
A[docs/ai/core.md<br/>单一事实源] --> B[docs/ai/tooling/*.md<br/>工具差异补丁]
A --> C[docs/ai/scopes/*.md<br/>子目录增量]
B --> D[scripts/sync-ai-configs.sh]
C --> D
D --> E[AGENTS.md]
D --> F[CLAUDE.md]
D --> G[GEMINI.md]
D --> H[.cursor/rules/generated-*.mdc]
E --> I[本地/CI 使用]
F --> I
G --> I
H --> I
I --> J[CI 漂移检查<br/>sync 后 git diff --exit-code]
#AI 配置
#AGENTS.md
#CLAUDE.md
#GEMINI.md
#Cursor Rules
#Skills
目录