feat: support multi-root projects with primary and additional directories
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 395
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
## 使用场景
希望把同一项 Cindy 工作涉及的多个目录放进一个逻辑项目,例如:
- `cindy/`:主 checkout
- `cindy-moved/`:迁移后的 checkout、worktree 或相关参考目录
用户希望在一个项目里持续处理相关代码、对话和 Agent 任务,而不是为每个目录分别维护项目。
这不只包括 Git worktree,也包括路径完全无关、无法靠 VCS 自动归一化的多 checkout 场景,例如:
- Perforce 的 Dev / TADev workspace;
- SVN 的多个分支 checkout;
- 用户手动迁移、复制或分别维护的多个代码目录。
这些目录需要由用户显式声明属于同一个逻辑 Project;不能依赖共同父目录、Git remote 或 worktree 关系猜测归属。
## 当前问题
Cindy 目前没有独立的 Project 实体。Project 主要由 session 的单值 `workingDir` 动态分组得到;session 数据只有一个 `working_dir`。
现有 `extra_dirs` 不能直接解决问题:它是 session 级的附加只读引用目录,不是持久化的 Project 成员目录,草稿重启时也会清空。
更重要的是,`workingDir` 同时承担:
1. Agent 实际 `cwd`;
2. 文件写入与 sandbox / auto-review 安全根;
3. Git、worktree、PR 目标;
4. Claude/Codex 的项目配置、resume、AGENTS/skills 发现;
5. Maker Memory、project-context、插件设置和自动化配置的 workdir scope;
6. Cindy 侧栏的 Project 分组与对话过滤。
因此不能简单把它从字符串改成数组,也不能把多个目录直接塞进 `extra_dirs`。
当前以绝对路径作为 scope key 的能力还会把同一逻辑项目的不同 checkout 隔离开。例如两个 P4 workspace 会各自维护独立的 Maker Memory,切换分支后无法共享已经建立的项目上下文。
## 调研结论
截至 2026-08-05,Codex Desktop 已支持本地项目绑定多个目录并指定 primary:
- primary 是默认 `cwd`、新任务起点、Git/PR/worktree 和项目级配置发现锚点;
- secondary 是同一项目的额外文件能力根,可用于搜索、读取和编辑;
- 实际读写由 sandbox / permission profile 决定;
- 开源 Codex app-server/core 将 `cwd` 与 `runtime_workspace_roots` 分开,roots 会进入 Agent filesystem context 和权限计算;
- Desktop 的 saved project / `rootPaths` 属于上层产品状态,不等同于底层 app-server 字段。
因此,目录一一匹配的主要原因不是 GitHub 映射,也不是对话查询性能,而是 Cindy 尚未拆分“项目身份、执行 cwd、安全根、Agent 原生项目 scope、持久化 scope”。
对话搜索在项目过滤时主要先收集 session IDs,再按 session IDs 查询;目录不是全文搜索的主要索引。
参考:
- https://learn.chatgpt.com/docs/projects
- https://learn.chatgpt.com/docs/changelog
- https://github.com/openai/codex/blob/main/codex-rs/app-server-protocol/src/protocol/v2/thread.rs
- https://github.com/openai/codex/blob/main/codex-rs/core/tests/suite/workspace_roots.rs
- https://github.com/openai/codex/issues/27943
## 目标
请后续专项设计并评估:
1. Project identity 与 ProjectRoot / membership 层;
2. primary root 与 additional roots;
3. 每个 root 的 read-only / read-write 权限;
4. Project identity 与 session 实际 `workingDir` 的解耦;
5. 项目变更后,已有 session runtime roots 和权限的生效时机;
6. local、SSH remote、device-link、mobile 的边界;
7. 多 root 下 Git、worktree、PR、AGENTS/skills/config、project-context、Memory、插件和自动化分别以什么 root 为准;
8. 旧项目、旧 session、alias、侧栏状态、scheduler consent 等数据迁移;
9. Git worktree、P4、SVN 与纯手工目录都能通过显式 membership 共享同一个稳定 Project scope,不依赖 VCS 探测。
## 关键语义
- Project identity 由稳定的 Project ID 表达,不由某个绝对路径、共同父目录或 VCS 身份代替。
- 同一 Project 的任意成员 root 都可以成为某个 session 的实际 `workingDir`。primary 是新任务的默认起点,以及默认 Git、配置和作用域锚点;不代表 additional root 只能作为只读参考目录。
- Maker Memory 与 project-context 应能按 Project ID 共享,让同一项目的多个 checkout 复用上下文;实际文件访问权限仍按本次运行的 roots、root access 与 sandbox / permission profile 共同决定。
- 第一阶段可以只开放受限的 runtime roots,但数据模型不能把 additional 永久建模为“只读附件”。
## 建议方向
评估以下模型,而不是直接改造 `workingDir`:
```ts
Project { id, displayName, primaryRootId }
ProjectRoot {
id, projectId, path,
role: 'primary' | 'additional',
access: 'read' | 'write',
remoteHostId?, deviceId?, order
}
```
兼容原则:
- 旧项目迁移为单 root Project;
- 旧 session 保留原始 `workingDir`,新增 nullable `projectId` 聚合;
- primary 继续作为默认 cwd / Git / 项目配置锚点;
- additional roots 不静默复用现有 session `extra_dirs` 语义;
- 不把共同父目录伪装成一个 Git 项目;
- 不依赖 Git/P4/SVN 自动探测决定 membership,允许用户显式归组;
- 配置必须提供可视化 UI,不要求用户手编辑配置文件。
## 非目标
- 本 Issue 不要求当前提交实现多目录项目;
- 不要求把多个 Git 仓库或 P4/SVN workspace 合并成一个仓库;
- 不要求一次性重写所有 Memory、transcript、Git 或插件历史数据;
- 不要求把所有附加目录的 AGENTS/config 无条件拼进全局 prompt;
- 不要求本 Issue 直接修改服务端或跨仓协议。
## 预期交付
后续负责该专项的人应先提交:
- 产品与数据模型方案;
- 迁移与向下兼容方案;
- 权限和运行时 roots 同步协议;
- Desktop / Mobile / SSH / device-link 影响面;
- 分阶段实现计划与验证矩阵。
其中验证矩阵必须包含:两个路径无关的 P4/SVN checkout 被显式归入同一 Project,在任一 checkout 中启动 session 时保持各自实际 `workingDir`,同时共享 Project 级 Memory / project-context,且不会静默扩大另一目录的文件写权限。
本 Issue 是调研和需求入口,不代表当前 Cindy 仓库已有实现承诺。
Contributor guide
Research direction
The issue names no Cindy files, tests, or entry points; begin by mapping the session working_dir and extra_dirs data paths and the project-scoping consumers described in the issue. Read the referenced Codex thread protocol and workspace_roots.rs for comparison. Done means a product/data model, migration plan, runtime-roots and permission protocol, platform impact analysis, phased plan, and validation matrix.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- devtools
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100