Agent 规则文件不想入库?用 symlink 单仓托管多项目规则

一、背景

接入 Codex / Claude Code 这类 Agent 后,规则文件会逐渐分散在多个位置:

text 复制代码
# 项目目录
AGENTS.md
CLAUDE.md
references/

# 家目录
~/.codex/AGENTS.md
~/.claude/CLAUDE.md

这些文件有几个明显问题:

  1. 不想提交到业务仓库

    规则文件主要影响 AI 行为,其中一部分还带有个人工作习惯,不一定属于业务代码。直接提交到业务仓库,会污染业务仓库的提交记录。

  2. 加入 .gitignore 又无处追踪

    规则文件虽然不适合进入业务仓库,但它本身仍然需要版本历史。否则换机器、回滚规则、复用配置都会变成手工操作。

  3. 文件位置比较分散

    项目规则在项目目录,全局规则在家目录。多个项目之间还可能复用一部分规则,手工复制很容易漂移。

所以这里真正要解决的是:

规则文件需要被 Git 追踪,但不应该进入业务仓库。

二、目标

目标 说明
单一真相源 规则文件只在一个仓库中维护,避免多处复制后漂移
不污染业务仓库 业务项目的 git status 不出现这些规则文件
支持多 scope 同时管理项目规则和 ~/.codex / ~/.claude 全局规则
换机器可复现 clone 规则仓库后执行同步脚本即可恢复
编辑零感知 在业务项目或规则仓库里编辑,改的都是同一份文件

核心思路:

规则文件的真实位置在 code-rules/ 仓库,业务项目和家目录里只放指向它的 symlink。

目录结构如下:

text 复制代码
code-rules/
├── sync-project-a.sh
├── sync-global.sh
├── project-a/
│   ├── links.txt
│   ├── AGENTS.md
│   ├── CLAUDE.md
│   └── references/
└── global/
    ├── links.txt
    ├── codex/
    │   └── AGENTS.md
    └── claude/
        └── CLAUDE.md

这里按 scope 拆分:

  • project-a/:项目级规则
  • global/:全局规则
  • links.txt:声明当前 scope 下哪些文件要链接到哪里
  • sync-*.sh:读取 links.txt 并创建 symlink

仓库里用非隐藏目录 codex/claude/,目标位置再链接到 ~/.codex/~/.claude/。这样仓库端更容易查看和编辑,系统端仍然符合 Agent 默认路径约定。

四、工作流程

%%{ init: { "theme": "neutral", "flowchart": { "nodeSpacing": 60, "rankSpacing": 90 } } }%% flowchart LR subgraph REPO["code-rules 仓库(单一真相源)"] direction TB SRC["规则文件
AGENTS.md / CLAUDE.md
references/ ..."] LINKS["links.txt
声明式清单"] SCRIPT["sync-*.sh
读清单建 symlink"] LINKS --> SCRIPT end subgraph SYS["系统中的目标位置"] direction TB PROJ["项目目录
~/Desktop/project-a/"] GLOBAL["全局配置
~/.codex/ ~/.claude/"] end EDIT(["日常改规则"]) -->|"直接编辑"| SRC NEW(["新增规则文件"]) -->|"1. 创建文件"| SRC NEW -->|"2. 登记"| LINKS NEW -->|"3. 执行"| SCRIPT SRC -.->|"symlink 透明访问"| PROJ SRC -.->|"symlink 透明访问"| GLOBAL SCRIPT -->|"建立 / 修正 symlink"| PROJ SCRIPT -->|"建立 / 修正 symlink"| GLOBAL SRC -->|"git commit"| HISTORY["版本历史
在 code-rules 中追踪"] style REPO fill:#dbeafe,stroke:#2563eb style SYS fill:#f3e8ff,stroke:#9333ea style SRC fill:#fff,stroke:#2563eb style LINKS fill:#fff,stroke:#2563eb style SCRIPT fill:#fff,stroke:#2563eb style PROJ fill:#fff,stroke:#9333ea style GLOBAL fill:#fff,stroke:#9333ea style HISTORY fill:#dcfce7,stroke:#16a34a style EDIT fill:#fef9c3,stroke:#ca8a04 style NEW fill:#fef9c3,stroke:#ca8a04

核心心智模型:

  • 规则文件的唯一真相源在 code-rules/
  • 系统中的对应路径都是指向它的 symlink
  • 日常修改规则时,任意一端编辑都可以,不需要额外同步
  • 新增规则文件时,才需要创建文件、登记 links.txt、执行同步脚本
  • 版本历史只在 code-rules/ 中追踪,业务仓库不受影响

五、关键实现

5.1 声明式清单 links.txt

每个 scope 下维护一份 links.txt

格式:

text 复制代码
<源相对路径> => <目标绝对路径>

项目规则示例:

text 复制代码
AGENTS.md     =>  ~/Desktop/project-a/AGENTS.md
CLAUDE.md     =>  ~/Desktop/project-a/CLAUDE.md
references    =>  ~/Desktop/project-a/references

全局规则示例:

text 复制代码
codex/AGENTS.md   =>  ~/.codex/AGENTS.md
claude/CLAUDE.md  =>  ~/.claude/CLAUDE.md

links.txt 的作用是把"链什么"和"怎么链"拆开。

新增规则文件时,只需要改清单,不需要改脚本。行首加 # 可以暂停某条同步。

5.2 同步脚本 sync-*.sh

同步脚本只做一件事:读取 links.txt,按行创建 symlink。

核心逻辑可以简化成下面这样:

bash 复制代码
#!/usr/bin/env bash
set -euo pipefail

REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
SCOPE_DIR="$REPO_DIR/project-a"
LINKS_FILE="$SCOPE_DIR/links.txt"

while IFS= read -r raw || [ -n "$raw" ]; do
  line="$(printf '%s' "$raw" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"

  [ -z "$line" ] && continue
  case "$line" in \#*) continue ;; esac

  src_rel="$(printf '%s' "${line%%=>*}" | sed -e 's/[[:space:]]*$//')"
  dst_raw="$(printf '%s' "${line#*=>}" | sed -e 's/^[[:space:]]*//')"

  dst="${dst_raw/#\~/$HOME}"
  dst="${dst//\$HOME/$HOME}"
  src="$SCOPE_DIR/$src_rel"

  [ ! -e "$src" ] && {
    echo "源缺失: $src_rel"
    continue
  }

  mkdir -p "$(dirname "$dst")"

  if [ -L "$dst" ]; then
    current="$(readlink "$dst")"

    if [ "$current" = "$src" ]; then
      echo "已链接: $src_rel => $dst"
      continue
    fi

    rm "$dst"
    ln -s "$src" "$dst"
    echo "修正: $src_rel => $dst"
    continue
  fi

  if [ -e "$dst" ]; then
    echo "冲突: $dst 已是真实文件或目录,未覆盖"
    continue
  fi

  ln -s "$src" "$dst"
  echo "新建: $src_rel => $dst"
done < "$LINKS_FILE"

脚本设计保持保守:

场景 行为
目标不存在 创建 symlink
目标已经是正确 symlink 跳过
目标是错误 symlink 删除后重新创建
目标是真实文件或目录 报冲突,不覆盖
源文件不存在 报错
清单行被注释 跳过

这里不自动覆盖真实文件,也不自动清理已存在的 symlink。同步脚本只负责"建立或修正链接",不替用户做删除决策。

5.3 按 scope 拆同步脚本

sync-project-a.shsync-global.sh 分开维护。

好处是:

  • 只想同步项目规则时,不影响全局规则
  • 只想同步全局规则时,不影响项目目录
  • 后续新增项目 scope 时,只需要新增一个目录和一份同步脚本

六、使用方式

6.1 日常修改规则

可以直接编辑规则仓库里的文件:

bash 复制代码
vim ~/Desktop/code-rules/project-a/AGENTS.md

也可以编辑业务项目中的 symlink 文件:

bash 复制代码
vim ~/Desktop/project-a/AGENTS.md

两种方式改的是同一个文件。

修改后只需要在 code-rules 仓库中提交:

bash 复制代码
git add project-a/AGENTS.md
git commit -m "chore: update agent rules"

6.2 新增规则文件

新增文件时才需要执行同步流程:

bash 复制代码
# 1. 在对应 scope 下创建文件
mkdir -p project-a/references

# 2. 在 project-a/links.txt 中登记
# references => ~/Desktop/project-a/references

# 3. 执行同步脚本
./sync-project-a.sh

# 4. 提交到规则仓库
git add project-a/links.txt project-a/references
git commit -m "chore: add project references"

6.3 暂停或恢复同步

links.txt 中注释对应行即可暂停:

text 复制代码
# references => ~/Desktop/project-a/references

恢复时去掉 #

需要注意:注释或删除清单行,不会自动删除系统中已经存在的 symlink。想彻底断开时,手动删除目标 symlink。

6.4 换机器部署

bash 复制代码
git clone <远程仓库> ~/Desktop/code-rules
cd ~/Desktop/code-rules
./sync-project-a.sh
./sync-global.sh

执行后,业务项目目录和家目录中的 Agent 规则入口就会重新指向 code-rules 中的规则文件。

几个备选方案对比:

方案 问题
直接提交到业务仓库 规则文件进入业务代码历史,边界不清
放业务仓库但加入 .gitignore 规则文件失去版本追踪
独立仓库 + 手工复制 两边容易漂移,编辑时还要确认哪份是最新
独立仓库 + rsync 本质仍是复制,需要同步动作,仍可能漂移
独立仓库 + symlink 文件系统层面保持单一真相源,编辑零感知

symlink 的优势是简单:

  • 没有运行时依赖
  • 不需要复制文件
  • 不需要区分"源文件"和"同步后的文件"
  • 任何位置编辑,实际修改的都是同一份内容

同步脚本的职责也很小,只负责把链接建好。

八、小结

这套方案解决的是一个很具体的问题:

Agent 规则文件不想进入业务仓库,但又需要被版本追踪,并且不想分散在多个目录里手工维护。

最终结构是:

text 复制代码
code-rules 负责追踪
links.txt 负责声明
sync-*.sh 负责建链
业务项目和家目录只负责使用

规则文件的真实内容集中在 code-rules/,业务项目和 Agent 默认目录通过 symlink 访问它。

这样既保留了 Git 版本历史,又避免污染业务仓库;同时项目规则、全局规则也能放在同一个地方统一管理。

相关推荐
夏天的峰没有风3 小时前
claude code 无法连接到 Anthropic 服务
claude
爱吃的小肥羊4 小时前
Claude 塌房实锤:Pro 用户可能连 Claude Code 都不配用了
aigc·openai·ai编程
财经资讯数据_灵砚智能4 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年4月20日
人工智能·python·信息可视化·自然语言处理·ai编程
jerrywus5 小时前
把 Obsidian 知识库接进 Claude Code:400 行代码实现 AI 长期记忆
前端·agent·claude
0zien05 小时前
【AI编程 - 第一弹】2048小游戏
ai编程·claude·creator·trae·vibe
安思派Anspire5 小时前
你的AI并不笨:它只是缺少一个约束机制
aigc·openai·ai编程
登山人在路上6 小时前
RAGAS 中的已知偏差详解
人工智能·全文检索·ai编程
周末程序猿6 小时前
万字长文:从0开发大模型之17种Agent架构演进
agent·ai编程
程序员小崔日记7 小时前
当 AIR 只支持 Mac,我开始重新思考操作系统这件事
macos·操作系统·ai编程