21 October 2026

最近我把日常维护的多个项目整理到了一个聚合工作区里,尝试让 AI 在同一个入口下处理跨项目需求,也能同时推进几个不同的任务。折腾下来发现,把目录放到一起只是第一步,后面还得解决项目怎么找、代码在哪改、任务进度怎么接上,以及什么时候才算完成。这篇记录下我目前的做法,给有类似需求的同学做个参考。

为什么要搞一个聚合工作区

我维护的系统包含多个独立项目,有前端、后端、数据服务,也有一些日常跑数和自动化测试项目。一个需求落下来,经常需要在几个仓库之间来回切换。

比如给一个页面增加查询条件,前端需要加输入项,API 需要接收参数,数据服务还得补上过滤逻辑。人来做的时候,脑子里大概知道这条调用链。交给 AI 的时候,就需要先告诉它:前端在哪、接口在哪、哪个才是现在使用的服务。

如果每次开一个新会话都重新交代这些内容,挺麻烦的。而且项目一多,历史服务和新服务并存,光靠名字猜还真不一定能找对。

另外,我也希望能同时处理几个任务:一个需求正在开发,另一个问题需要排查,还有一个任务已经交给测试,随时可能退回来修改。

这时候如果几个会话都在同一个目录里改代码,问题就来了:你这边正在改功能,它那边切了分支;你以为工作区里的修改都是自己的,结果混进了另一个任务的文件。AI 写代码再快,这种现场混乱也够喝一壶的。

所以我现在主要解决两件事:让 AI 能找到正确的项目,让不同任务有各自的代码现场。

先把项目入口和规则集中起来

聚合工作区本身是一个独立 Git 仓库,保存项目导航、协作规范和辅助脚本。业务项目继续保留各自的仓库和提交历史。

为了方便说明,下面把实际业务项目名换成了通用名称,目录也做了简化:

system-workspace/
├── README.md                   # 工作区说明和阅读顺序
├── AGENTS.md                   # AI 入口和规则路由
├── config/
│   └── projects.json           # 项目注册表
├── projects/                   # 各项目的查看入口
│   ├── web-app/                # Junction,指向原仓库
│   ├── api-service/
│   └── data-service/
├── doc/ai/
│   ├── standards/current/      # 按场景拆分的协作规范
│   ├── skills/                 # 可复用的操作流程
│   └── prompts/                # 轻量提示词模板
├── scripts/                    # 项目定位、任务和工作区管理
├── tasks/                      # 任务台账
└── runtime/                    # 需求资料、日志和临时产物

我在 Windows 上使用 Junction,把原来散落在不同目录的仓库链接到 projects/ 下。这样从一个地方就能浏览所有项目,也不用为了聚合入口搬动原来的代码目录。

这里有个需要特别注意的地方:Junction 指向的就是原目录,修改链接里的文件,会直接修改源项目。 它不会替你隔离任务。

因此,在这个工作区里,外部项目的 projects/ 入口主要用于导航和引用,正式业务开发使用后面介绍的固定工作区池。少数直接维护在聚合仓库里的原生工具项目,按自己的规则处理。

项目注册表,解决“到底该改哪个项目”

有了入口目录,还需要一份能让人和 AI 都看懂的项目地图。

我把项目职责、别名、入口、源仓库、分支角色和调用链统一放到项目注册表里,再通过脚本查询或生成可读文档。比如:

页面查询需求:web-app -> api-service -> data-service
数据生产任务:batch-job -> data-service
功能回归:test-cases

实际处理需求时,先定位页面入口,再根据接口调用去找后端,最后看数据来自哪里。这样就不用一上来在所有仓库里搜索,也能减少修改已经停用的旧接口这种问题。

分支也一样。我会记录“开发基线”“测试”“生产”等角色分别对应哪个分支,让脚本解析。不会因为一个分支叫 master,就直接认定它一定是生产分支。

注册表变更后,可读项目目录由脚本生成,并检查是否同步。维护一份事实来源就够了,不然 README、Skill 和聊天记录里各有一张项目表,时间长了总有一份会过期。

这些注册信息是否适合提交,要看仓库的共享范围。团队内部可以保存必要的项目元数据,密码、私钥和令牌仍放本机私有配置;准备公开分享时,还要把内部地址、真实路径和业务信息替换掉。

AI 先读什么,也要有顺序

我的入口文件没有把所有规则塞进去,而是保留几条核心约束和场景路由。

大体上的阅读顺序是:

  1. 先读聚合工作区 README,理解目录和项目关系。
  2. 按当前动作读取规则,比如正式开发、问题排查、数据处理或交付。
  3. 命中具体业务流程时,再读对应 Skill。
  4. 进入具体项目后,继续读它自己的 README 和开发规范。

聚合层负责告诉 AI 去哪里、按什么流程做;项目层负责告诉它代码怎么写、怎样构建和验证。

我会把可重复执行的流程放到 Skill 中,比如某类跨项目需求怎么定位、问题排查先查哪些证据、交付前检查什么。输入输出明确、步骤比较短的内容,则保留成提示词模板。

这样换一个会话,或者换一个 AI 工具时,至少还有一套可以重新读取的上下文。

多任务并行,用固定工作区池隔离代码

只建立多个会话,还不能保证代码互不干扰。我现在使用固定工作区池,为每个任务分配一个独占的 slot:

workspace-pool/
├── ws-01/                      # 任务 A:开发查询条件
│   ├── web-app/
│   ├── api-service/
│   └── data-service/
├── ws-02/                      # 任务 B:排查接口异常
│   ├── web-app/
│   └── api-service/
└── ws-03/                      # 空闲,等待下一个任务

这些代码目录通过 Git worktree 建立。它们拥有各自的工作目录,同时与源仓库共享 Git 对象。池可以包含全部项目,也可以只初始化经常一起使用的几个项目。

一个任务可能涉及多个仓库,就在同一个 slot 里的对应项目目录中处理;另一个任务使用另外一个 slot。同一仓库的不同任务需要使用各自的任务分支,不能随便在两个工作目录中同时检出同一个分支。

为什么要固定下来复用?主要是为了保留本地构建环境。

前端的 node_modules、Java 项目的 target、Gradle 缓存和 IDE 索引,重新准备都需要时间。我现在释放 slot 时保留这些缓存,下个任务继续使用已有目录,代码和分支则按新任务的要求重新准备。

不过,缓存保留也意味着依赖文件变更后仍要安装依赖,必要时也得清理重建,不能因为目录里有旧产物就默认验证有效。

池清单记录每个 slot 的占用情况,管理脚本通过文件锁和原子写入协调分配。如果指定的 slot 已被占用,就报告冲突;没有空闲位置时,先释放已完成任务或者扩容,不偷偷找个新目录绕过去。

开发和排查使用不同模式

我把工作区使用方式区分成了两种:

模式 使用方式
Development 从确认的基线创建或续接任务分支,进行开发和验证
Investigation 同步目标远端分支,冻结具体 commit,以 detached HEAD 进入排查现场

排查时固定 commit,后面写结论就能说明证据来自哪一版代码。同步失败时,也不能拿本地旧代码当作当前环境来分析。

只查看远程日志、数据库或已有文档时,不一定需要占用代码工作区;需要阅读、编译或比较本地业务代码时,再分配排查 slot。

排查发现问题以后,如果要进入正式修改,就释放排查现场,再按开发模式准备分支。查出原因和开始修改,是两个需要明确区分的动作。

下面是我自己的管理脚本中使用的命令形式,项目名是示例,不是安装某个工具后就自带的通用命令:

# 查看池的占用情况
python scripts/task.py workspace list

# 已登记的排查任务占用工作区
python scripts/task.py workspace acquire investigate-query --project api-service --mode Investigation

# 已完成开发授权和阶段检查的任务占用工作区
python scripts/task.py workspace acquire add-filter --project web-app --project api-service --mode Development --fetch

命令背后还会检查任务状态、项目范围和分支配置,不能只复制最后一条命令,就跳过前面的准备工作。

用 Task 保存任务进度

代码目录隔离之后,还需要知道每个任务做到哪了。

如果这些信息只存在聊天里,过几天再回来,很容易忘记哪个任务已经推送、哪个还等测试、哪个分支才是需要继续修改的版本。

因此我为需要跨会话处理的业务需求建立独立 Task。台账至少记录:任务 ID、涉及项目、当前状态和阶段、下一步、产出物位置,以及工作区、分支和提交等信息。

我目前把流程拆成下面这些阶段:

接收 -> 分析 -> 方案 -> 授权确认 -> 开发 -> 本地验证
     -> 审查 -> 代码交付 -> 测试环境测试 -> 完成

默认先分析需求、整理资料、输出方案。用户明确要求进入开发后,再记录授权并准备开发现场。等待用户或外部系统时,保留当前阶段,同时记录等待状态。

阶段推进也不只是改一个状态字段。比如,本地验证要有执行命令和结果;交付要能对应到具体提交和远端分支;完成前要有测试验收、交接资料和工作区释放记录。

有些关键节点还要人工确认,例如方案、代码审核和测试验收。确认记录绑定当时产出物的指纹,文件变了就需要重新确认,避免拿旧版方案的批准去交付新版内容。

测试退回来时,则根据 Task 中保存的分支和基线恢复现场。如果原 slot 已经释放,也可以按任务记录重新分配,继续修原来的功能分支,不另起一条互不相干的修改线。

工作区释放前会检查是否有未提交或未推送的内容,排查模式也要核对基线。释放是软释放,保留缓存;任务完成则是另一个动作,不能把“空出目录了”当成“业务验收通过了”。

工作目录分开了,运行环境还得另外协调

这个地方很容易忽略:两个 Git worktree 并不会自动拥有两套运行环境。

两个前端任务都启动在同一个端口,还是会冲突;两个任务连同一个测试数据库,数据也仍然可能互相影响。共享测试分支的合并、部署和数据库变更,同样需要协调。

所以固定工作区池主要解决代码现场的隔离。真正运行时,还需要根据任务分配端口、选择环境,并明确共享资源的使用顺序。

另外,slot 的占用记录只能约束通过管理脚本进入的操作。人或者其他工具直接进目录修改,仍然可能破坏现场。流程需要大家一起遵守,脚本也要在关键动作前重新检查状态。

临时资料也要能找到

多任务一起来,需求附件、SQL、日志和测试结果很容易散落一地。我把单个需求的资料集中到同一个目录:

runtime/
└── 20261021/
    └── add-filter/
        ├── source.md           # 需求来源
        ├── attachments/        # 原始附件
        ├── solution/           # 技术方案
        └── run-001/            # 某次运行的命令、日志和结果

长时间运行的命令还要留下运行 ID、状态和退出码。发现没有结果时,先确认上一次进程是不是还活着,再决定要不要重跑。

需求资料和运行现场默认不进入 Git。以后确实值得复用的经验,再整理到规范、Skill 或项目文档中。这样长期知识和一次任务产生的过程文件就不会混在一起。

如果从头搭建,我建议分几步来

上面这套规则是针对我目前多仓库、多任务的工作方式整理的。个人只有一两个小项目时,没有必要一开始就把所有阶段和确认流程都搬过去。

可以先从下面几步开始:

  1. 建一个聚合目录,写清项目职责、入口和常用命令。
  2. 整理项目注册表和调用链,减少重复解释和项目定位错误。
  3. 真正出现并行修改时,再引入独立工作目录和占用登记。
  4. 任务开始跨会话、跨测试轮次时,再增加 Task 台账和恢复流程。
  5. 把反复出错、反复提醒的检查逐步放进脚本。

我现在比较看重最后一点。文档里写“不要误切分支”当然有用,但脚本在占用工作区前检查分支和未提交内容,会更踏实一些。写“测试通过才能完成”,也不如要求台账里留下对应的验收证据。

这套方式还有维护成本:注册表要更新,规范不能互相矛盾,工作区池会占磁盘,验证结果也得有人认真看。它没有替我们判断需求对不对,或者代码是否真正满足业务。

不过,把项目关系、任务状态和代码现场整理清楚以后,AI 至少能在一个比较确定的范围里连续工作。对我来说,少花一些时间重新交代上下文、收拾混在一起的修改,就已经很有价值了。





blog comments powered by Disqus
Fork me on GitHub