Beta。 Stores、references、工作上下文和 worksets 都是新功能。命令名、标志、文件格式和 JSON 输出仍可能在版本之间改变形态。下面的每个演练都针对当前构建运行过,但升级后请重新阅读本指南。
OpenSpec 通常活在一个代码仓库内部:代码旁边的一个 openspec/ 文件夹,保存着该仓库的 specs 和 changes。
一旦你的规划大到超出单个仓库,这就不再适用了:
- 你的工作横跨多个仓库 —— 一个功能同时触碰 API 服务器、Web 应用和一个共享库。这个计划该放在谁的
openspec/文件夹里? - 你的团队在代码存在之前就做规划,或者规划那些永远不会变成这个仓库里代码的东西。
- 需求由一个团队拥有、被其他团队消费。Wiki 版本会漂移,而你的编码 Agent 反正也读不了它。
Store 就是答案:一个独立仓库,唯一职责就是规划。它有着你已经熟悉的同一个 openspec/ 形态 —— specs 和 changes —— 外加一个小的身份文件。你在自己的机器上按名字注册它一次,之后每个普通的 OpenSpec 命令都能在任意位置作用于它。
team-plans (一个 store:规划在它自己的仓库里)
├── .openspec-store/store.yaml identity: "I am team-plans"
└── openspec/
├── specs/ what is true
└── changes/ what is in motion
▲
│ 按名字在每台机器上注册;
│ 像普通仓库一样通过 push/clone 共享
┌─────────────┼─────────────┐
│ │ │
web-app api-server mobile-app
(code repo) (code repo) (code repo)
两条规则让它保持简单:
- Store 就是一个 git 仓库。 你自己在上面提交、push、pull、审查。OpenSpec 永远不会自己 clone、sync 或 push 任何东西。
- 是声明,而非机制。 仓库可以声明它们和 store 的关系(如下所示)。声明改变的是 OpenSpec 能告诉你的东西 —— 绝不是你的命令会在哪里生效。
两条命令就能让你从零拥有一个可工作的、store 作用域内的变更:
openspec-cn store setup team-plans --path ~/openspec/team-plansStore ready: team-plans
Location: /Users/you/openspec/team-plans
OpenSpec root: ready
Registry: registered
Next: run normal OpenSpec commands against this store, for example:
openspec-cn new change <change-id> --store team-plans
Share this store by committing and pushing it like any Git repo.
openspec-cn new change add-login --store team-plansUsing OpenSpec root: team-plans (/Users/you/openspec/team-plans)
Created change 'add-login' at /Users/you/openspec/team-plans/openspec/changes/add-login/
Schema: spec-driven
Next: openspec-cn status --change add-login --store team-plans
这就是整个模型。从这里开始,生命周期和你已知的完全一致 —— status、instructions、validate、archive —— 只是每条命令都带上 --store team-plans,而且每个打印出的提示都会为你带上该标志。Using OpenSpec root: 这一行总会告诉你命令正在作用于哪里。
一个团队把它的 specs 和 changes 放在 team-plans 里,而不是散落在各个代码仓库中。
第一天(搭建的人):
openspec-cn store setup team-plans --path ~/openspec/team-plans \
--remote git@github.com:acme/team-plans.git
git -C ~/openspec/team-plans push -u origin main传入 --remote 会把 clone URL 记录在 store 自己的身份文件(.openspec-store/store.yaml)里,位于初始提交中。未来每一次 clone 一开始就知道自己从哪来,于是健康检查和错误消息能为还没有它的队友打印出完整、可直接粘贴的修复命令。
每个队友(每台机器一次):
git clone git@github.com:acme/team-plans.git ~/openspec/team-plans
openspec-cn store register ~/openspec/team-plans从那以后,每个人按名字在同一个规划仓库里工作:
openspec-cn status --store team-plans --change add-login
openspec-cn show add-login --store team-plans共享工作就是 git,这是有意为之。 你创建的变更只存在于你的 checkout 里,直到你提交并 push 它 —— 和代码一样。计划免费获得分支、pull request 和审查,因为 store 就是一个普通仓库。
连接团队的代码仓库。 一个规划被完全外部化的代码仓库,只需要在 openspec/config.yaml 里加一行:
# web-app/openspec/config.yaml
store: team-plans现在在 web-app 里运行的每个 OpenSpec 命令都会作用于 team-plans,完全不需要任何标志:
cd ~/src/web-app
openspec-cn status --change add-loginUsing OpenSpec root: team-plans (/Users/you/openspec/team-plans)
...
这个指针是兜底,绝不是覆盖:显式的 --store 永远优先;如果仓库自己长出了真正的规划文件夹,那些优先(并附一条警告,提示移除过时的指针)。
一个平台团队拥有需求。产品团队基于这些需求,在它们自己的仓库里、用它们自己的设计来构建。一个 reference 描述这种关系,而不移动任何人的工作。
platform-reqs (store) api-server (code repo)
owned by the platform team owned by a product team
┌──────────────────────────┐ ┌──────────────────────────┐
│ openspec/specs/ │ ◀────────│ openspec/config.yaml │
│ payments/spec.md │ reads │ references: │
│ auth/spec.md │ │ - platform-reqs │
│ │ │ openspec/specs/ │
│ openspec/changes/ │ │ (their own designs) │
│ platform work │ │ openspec/changes/ │
│ │ │ (their own work) │
│ │ └──────────────────────────┘
└──────────────────────────┘
产品团队在它仓库的 openspec/config.yaml 里声明它依赖什么:
references:
- platform-reqsReferences 是只读上下文。仓库保留它自己的 openspec/ 根;工作留在那里。变化在于:那个仓库里的 openspec-cn instructions 现在会包含被引用 store 的 specs 索引 —— 每条带一行摘要和精确的 fetch 命令(openspec-cn show <spec-id> --type spec --store platform-reqs)。在 api-server 里工作的 Agent 能找到上游的支付需求、引用它们,并在这个仓库自己的根里写它的底层设计 —— 而不需要任何人到处粘贴上下文。
一个 reference 可以携带它的 clone 来源,这样还没有这个 store 的队友会得到完整的修复方案,而不是死路一条:
references:
- { id: platform-reqs, remote: "git@github.com:acme/platform-reqs.git" }当你想把计划和代码一起打开时,做一个 workset。 这是个人化且显式的:每个人选择他们在自己机器上实际一起工作的文件夹。这些本地 checkout 路径的信息都不会被提交到共享规划仓库。
openspec-cn workset create platform \
--member ~/openspec/platform-reqs \
--member ~/src/api-server \
--member ~/src/web-app"我的环境健康吗?" —— openspec-cn doctor 检查当前根目录及其引用的 stores,只读,每个发现都附带可粘贴的修复命令:
Doctor
Root
Location: /Users/you/src/api-server
OpenSpec root: ok
References
- platform-reqs: ok (/Users/you/openspec/platform-reqs)
- design-system: Referenced store 'design-system' is not registered on this machine.
Fix: git clone -- git@github.com:acme/design-system.git '/Users/you/openspec/design-system' && openspec-cn store register '/Users/you/openspec/design-system' --id design-system
"我在和什么一起工作?" —— openspec-cn context 从 OpenSpec 声明中拼出工作集:根目录和它引用的 stores。
Working context for api-server (/Users/you/src/api-server)
OpenSpec root
api-server /Users/you/src/api-server
Referenced stores
platform-reqs /Users/you/openspec/platform-reqs
Fetch: openspec-cn show <spec-id> --type spec --store platform-reqs
两者都支持 --json 供 Agent 使用。openspec-cn context --code-workspace <path> 额外写入一个包含整个集合的 VS Code workspace 文件 —— 这是该命令执行的唯一写入操作。
与上述所有都独立:大多数人每个会话都会一起打开同样几个文件夹 —— 规划仓库加上两三个代码仓库。一个 workset 正是这个的个人化、有名字的视图,用一条命令在你选择的工具里重新打开。
workset "platform" openspec-cn workset open platform
├── team-plans ~/openspec/team-plans │
├── api-server ~/src/api-server ▼
└── web-app ~/src/web-app all three open in your tool
openspec-cn workset create platform \
--member ~/openspec/team-plans --member ~/src/api-server \
--tool code
openspec-cn workset listplatform (opens in VS Code)
team-plans /Users/you/openspec/team-plans
api-server /Users/you/src/api-server
openspec-cn workset open platform 随后启动保存的工具:编辑器(VS Code、Cursor)打开一个包含所有成员的窗口并返回。第一个成员是主成员。随时用 --tool <id> 覆盖工具。
Worksets 刻意不是共享状态。它们活在你的机器上,从不被提交,也不对工作内容做任何声明 —— 它们只记录你喜欢一起打开什么。移除一个绝不会触碰成员文件夹。新工具是配置而非代码:任何通过 workspace 文件或按文件夹 attach 标志启动的工具,都可以加到全局配置的 openers 键下(openspec-cn config edit)。
每个普通命令以相同的方式、按以下顺序解析它的根:
1. --store <id> 你显式指定了 → 那个 store
2. nearest openspec/ 这里有个真正的规划根 → 这个仓库
(从 cwd 向上查找)
3. store: 指针 config.yaml 声明了 → 那个 store
4. 以上都不是 本机注册了 store? → 带选择提示的错误
没注册任何 store? → 当前目录
(经典行为)
Using OpenSpec root: 这一行(以及 --json 输出里的 root 块)会告诉你命中的是哪种情况。
- Beta 形态。 本页上的任何东西都可能在版本之间改变 —— 名字、标志、文件格式、JSON 键。
- 每台机器每个 store id 一个 checkout。 用同一个 id 注册第二个 checkout 会失败,并提示先
store unregister。 - 绝不 sync,这是设计使然。 OpenSpec 永不 clone、pull 或 push。一个过时的 checkout 会一直显示陈旧 specs,直到你 pull;references 是从磁盘上任何现存内容实时索引的。
- 空的规划文件夹可以缺失。 一个新的 store 可能还没有
openspec/changes/、openspec/specs/或openspec/changes/archive/。这在 beta 期间是被接受的;这些文件夹会在普通命令为其创建文件时自行出现。 - 指针仓库保持指针身份。 一个
openspec/config.yaml声明了store: <id>的仅配置仓库,被视为外部化规划,而非可注册的 store checkout。如果你有意想把这个仓库转成本地 store 根,先移除store:这一行。 - 有些命令留在原地。
view、templates、schemas,以及已废弃的名词形式(openspec-cn change show,...)只作用于当前目录 —— 没有--store。 - 每机器状态就是每机器的。 store 注册表和 worksets 都是本地设置。你机器上的任何布局信息都不会被提交到共享规划中。
- Worksets 有两种启动方式。 一个无法用 workspace 文件或按文件夹 attach 标志启动的工具,不能被加为 opener。
- Agent JSON 有一个已知的命名大小写分裂(store 系列键是 snake_case,工作流系列是 camelCase)。记录在 agent 契约;统一它延后到带版本号的发布。
| 什么 | 在哪 | 共享? |
|---|---|---|
| 一个 store 的规划 | <store>/openspec/(specs、changes) |
是 —— 提交并 push 它 |
| 一个 store 的身份 | <store>/.openspec-store/store.yaml |
是 —— 随 store 一起提交 |
| Store 注册表 | <data dir>/openspec/stores/registry.yaml |
否 —— 仅本机 |
| Worksets | <data dir>/openspec/worksets/ |
否 —— 仅本机 |
<data dir> 在 macOS 和 Linux 上是 ~/.local/share/openspec(若设置了则是 $XDG_DATA_HOME/openspec),在 Windows 上是 %LOCALAPPDATA%\openspec。
本页上每个命令的确切标志和 JSON 结构:CLI 参考(Stores、Doctor、工作上下文、个人 worksets)以及 agent 契约。