仓库结构
本页定义 core-first monorepo:根目录 openprogram/ 是 Agent 核心;Server、Web、Desktop 与 CLI 是使用核心的可运行应用,统一归入 apps/。目标是让目录直接表达运行边界和依赖方向,同时保持产品行为与用户数据兼容。
1. 设计原则
核心与应用分离
openprogram/ 只承载 Agent、Context、Session、Provider、Program、Tool、Memory 与 Runtime 等核心能力。所有可运行入口放在 apps/。核心业务域不能依赖应用;Core import package 内为保留旧公开入口而存在的 compatibility adapter 可以单向委托应用 package,但不能承载应用实现。
按可验证边界拆分
只有当一段代码具有独立输入、输出和测试入口时才移动。单纯因为文件长而引入 mixin、manager 或 facade 不属于有效拆分。
公共接口保持稳定
迁移期间保留现有 CLI 命令、HTTP/WS 协议、端口、用户数据目录和必要的 Python import 兼容入口。每个应用独立移动、验证和提交。
当前设计与实施记录分离
本 HTML 描述长期结构;相邻实现说明维护代码位置、兼容边界、验证方法和未完成事项。历史提交与逐轮评审记录通过 Git 查询。
2. 顶层职责
OpenProgram/
apps/
server/ FastAPI、HTTP、WebSocket、认证与静态资源托管
web/ Next.js Web 应用
desktop/ Electron 桌面应用
cli/ Python CLI 与 Ink TUI 应用
openprogram/ OpenProgram Agent 核心与 Python SDK
tests/ Python 测试:层级 / 产品域
docs/ 用户文档与设计记录
scripts/ 可执行或可导入的开发、验证和发布工具
references/ 参考实现快照与本地比较语料
website/ 官网源码
pyproject.toml 单一 Python aggregate project 配置
uv.lock Python 唯一锁文件
package.json npm workspace 入口
package-lock.json npm workspace 唯一锁文件
.github/、.codegraph/ 和 .superpowers/ 是仓库基础设施,不是产品运行时目录。根目录只保留两套生态入口与锁文件、项目元数据和入口文档。根 pyproject.toml 继续定义用户安装的单一 openprogram aggregate distribution,并与唯一 uv.lock 管理 Python 开发环境;G2 不创建没有成员的 [tool.uv.workspace],也不把 Core、Server、CLI 拆成三个公开 distributions。Web、Desktop 和 Ink CLI 由根 package.json 声明 npm workspaces,共用唯一 package-lock.json。这些文件是源码与构建配置,不进入普通用户的安装目录。
Web 固定 React 18,Ink CLI 固定 React 19。npm 默认 hoisting 会让公共位置的 React peer 与类型依赖影响另一应用,因此根私有 package 以精确版本声明 React 18、react-reconciler 0.29 及其类型作为依赖布局约束;CLI 的 React 19 与 react-reconciler 0.33 保持在自己的 workspace。CLI 不依赖从根解析 React 的第三方 hook package。该约束不新增产品运行时功能,也不统一两个应用的 React 主版本。
核心 Python import package 位于根目录 openprogram/,它是 Server、CLI 与 Harness 共用的 Agent Core / SDK,不是普通应用。仓库当前没有第二个共享 Python package,因此不建立 packages/。源码归属与发布 distribution 是两个边界:项目保持一个用户可安装的 openprogram wheel,其中继续包含 openprogram、openprogram_server 和 openprogram_cli。应用专用脚本放在 apps/<name>/scripts/,跨应用的开发与验证命令放在 scripts/,正式 runtime、installer 与 release 命令放在 scripts/release/。
现有公开地址继续提供 scripts/install-release.sh。该文件只承担兼容分发:完整 checkout 中执行 scripts/release/install-release.sh;被单独下载时,从同一已验证 repository 和不可变 tag 下载正式实现到临时文件后执行。scripts/install.sh、scripts/install.ps1、scripts/refresh-local-app.sh 和 scripts/promote_stable.sh 保持路径不变;本地刷新继续复用归入 scripts/release/ 的 staging 与版本验证 helper。
当前 checkout 已完成发布脚本和 Node workspace 整理:正式发布脚本归入 scripts/release/;Web、Desktop 和 Ink CLI 由根 npm workspace 管理并共享唯一 package-lock.json;Python Core 保持在根目录 openprogram/。根 pyproject.toml 继续发布包含 Core、Server 和 Python CLI 的单一 openprogram wheel。
OpenProgram 不随安装包分发默认 skill;产品内置工作流由 Programs 提供。openprogram/skills/ 只实现 AgentSkills 兼容的加载能力,来源为远端缓存、插件、用户目录 ~/.openprogram/skills/ 和当前项目 <cwd>/skills/。仓库不建立 skills_bundled/ 或第二份隐藏副本。
tests/ 中的 Python 用例使用 tests/<layer>/<product-domain>/test_*.py,按最强实际依赖选择层级。具体边界由 测试体系 和仓库 contracts 维护。
核心 package 与应用 package
openprogram/ 的一级目录只保留可独立说明的核心产品域或稳定协议边界,例如 agent/、programs/、context/、memory/ 和 providers/。子能力必须归入所属产品域;Context 的 Git DAG 位于 context/git/,不再占用独立的 contextgit/ 一级目录。FastAPI route、WebSocket handler、静态前端托管、Electron 与界面代码不属于核心 package。
apps/server/openprogram_server/ 是 Python 服务应用;FastAPI routes、WebSocket actions、owner auth、静态资源托管与 Server-only helpers 位于其 _webui/ 内。兼容期内这些文件仍以既有 openprogram.webui.* 名称加载,根 package 只负责定位同一份应用源码,不复制模块状态。apps/cli/ 是 CLI 应用 workspace,Ink TUI 使用其中的 src/、tests/ 和 package.json,Python parser、dispatch、Rich fallback 与 setup flow 位于 apps/cli/python/openprogram_cli/。openprogram.cli 只保留兼容 loader 和 module entry;两处兼容边界均不承载新的应用实现。
工具配置、收藏夹和其他 profile 状态属于用户数据,写入 ~/.openprogram[-profile]/,不作为源码或 wheel seed 保存在 openprogram/。兼容读取只检查旧版 openprogram/webui/ package 位置并一次性复制到 profile state;它不能依赖已迁移到 apps/server 的 Server module 路径。
仓库当前不建立 packages/。只有出现第二个被两个及以上应用消费、具有独立稳定公共入口的共享 package 时,才重新评估是否需要该目录;不为未来可能复用的协议、UI 或配置预建空 package。
__pycache__/、.DS_Store、构建产物和 Finder 冲突副本不是仓库结构。它们保持 Git ignored,可安全清理,但不能用作代码分层或验收证据。用户安装的 programs/packages/ checkout 属于本地产品数据,不随源码目录整理删除。
3. 超长文件处理
| 文件 | 现状 | 决定 | 边界 |
|---|---|---|---|
openprogram/cli/ |
只保留兼容 loader、python -m openprogram.cli 入口和边界说明 |
已迁移 | 应用实现位于 apps/cli/python/openprogram_cli/;源码开发通过 editable install 或 uv run 保留 python -m openprogram 与 python -m openprogram.cli,wheel 额外保留 canonical python -m openprogram_cli 和 console script。 |
apps/desktop/main.js |
窗口、更新、WebView、标签转移和菜单共处,接近 4,000 行 | 分批实施 | 纯菜单几何计算已提取到 menu-geometry.js,纯 worker recovery 状态已提取到 worker-recovery-state.js,transfer payload validation 已提取到 tab-transfer-validation.js;HTTP 探测、进程与窗口生命周期、原生 WebView 所有权变更、标签转移协调和菜单宿主只在各自具备执行级验收后移动。 |
apps/web/lib/desktop/desktop-bridge.ts |
类型、视图状态和标签转移共处,接近 2,000 行 | 分批实施 | WebTab 与 Desktop 服务公共类型已提取到 desktop-bridge-types.ts,preload-facing transfer contracts 已提取到 desktop-transfer-types.ts,并由原文件 re-export;aggregate bridge、view state、journal persistence 与 tab transfer coordination 保持在原处,直到识别出可独立执行验证的职责。 |
runtime.py、runner.py、resource_governance.py |
文件较长,但核心状态机和不变量集中 | 不按长度拆 | 只有出现可独立验证的职责或重复实现时再拆;不引入 mixin 层。 |
| 大型 Web / Desktop 检查脚本 | 少数脚本同时包含 fixture、场景执行和多项结构断言,最长超过 3,000 行 | 后续批次 | 先提取共享 fixture 与可独立执行的场景;保留原命令入口,不为缩短文件引入测试框架。 |
4. 文档信息架构
用户文档
start/、install/、capabilities/、interfaces/、models/、integrations/、server/、reference/。进入公开导航和搜索。
当前设计
reference/design/。按产品域展示当前有效的设计说明;UI 文档按基础、会话编辑、浏览器标签、设置目录、工作区分组。
实施记录
与设计页相邻的实现说明以及 reference/design/plans/ 描述当前实施边界、验证要求和剩余任务;文末集中维护实现状态,不复制设计正文,也不累积历史提交和评审日志。
内部计划
docs/superpowers/ 保留在 Git 中供维护者追溯,不进入公开站点。仍被当前设计引用的 reference/design/plans/ 继续发布,并保持独立 Plans 分组。
根目录 README.md 解释完整产品;openprogram/README.md 解释核心 SDK;apps/server/README.md、apps/web/README.md、apps/desktop/README.md 和 apps/cli/README.md 分别解释各运行入口。入口 README 只描述当前职责、依赖方向和验证命令。
5. 采用与拒绝
| 选择 | 结论 | 原因 |
|---|---|---|
根目录 openprogram/ 核心 + apps/ 运行入口 | 采用 | 核心保持项目一级入口,Server、Web、Desktop 与 CLI 的应用边界在 apps/ 中可见。 |
| move-only 应用迁移 | 采用 | 先移动路径并修复构建、import 和脚本,再单独处理内部大文件拆分,避免同时改变行为。 |
| 通过导航分组整理文档 | 采用 | 避免批量移动文件造成旧链接失效。 |
把 openprogram/ 命名为 backend | 拒绝 | OpenProgram 是 Agent 核心与 SDK,Server 只是它的一个应用入口。 |
保持 Server 实现在 openprogram/webui/ | 拒绝 | 该目录混合服务端、旧静态 UI、构建产物和 Web 命名,无法表达真实职责。 |
| 按固定行数自动拆文件 | 拒绝 | 行数不能证明职责独立,容易产生只转发调用的模块。 |
| 为拆分引入新的依赖注入框架 | 拒绝 | 现有模块函数和显式参数足以保留边界。 |
| 一次提交移动所有应用 | 拒绝 | 应用分别迁移和验证;最终状态统一进入 apps/,但不以一个不可审查的提交完成。 |
6. 验收合同
openprogram/不包含 FastAPI route、WebSocket handler、前端源码、Electron 源码或持久化前端构建产物。apps/server、apps/web、apps/desktop和apps/cli均有独立入口、README、测试命令和构建命令。openprogram.cli.build_parser在兼容期保持可导入,完整命令树、console script 与 TUI 行为一致。- 默认端口仍为
18100;同一 Worker 提供 API、WebSocket 和 Web 静态文件,不恢复旧双端口 Next.js Server。 - 浏览器与 Electron 继续加载同一套 Web 应用;Electron 专属能力只通过 preload/IPC 暴露。
- Agent Harness 可以直接导入
openprogram,不依赖 Server、Web 或 Desktop。 - 旧
openprogram/webui/static/和无生产调用的旧双端口实现被删除。 - 前端构建产物只进入 ignored build/staging 目录和最终发行包,不作为核心源码长期维护。
- 可变 profile 状态不进入源码树或 wheel;旧 package-local JSON 只作为升级兼容输入读取,不在新版本继续跟踪。
- 公开文档构建不包含
docs/superpowers/,所有公开链接有效。 - 设计导航按产品功能分组;源文件路径保持不变。
- Git tracked 顶层目录必须在结构 contract 中声明,根目录不出现开发脚本;不含实现的 source-checkout module entry 必须被 contract 单独列出。
- 有效 README、技能和安装说明不得引用已删除的源码根路径。
- 根目录不再保留旧的
web/、desktop/和cli/workspace;有效源码分别位于对应apps/子目录。 - 一级 Python 包的目录 README 与
__init__.pydocstring 保持同步。 - 每个结构批次独立提交,先通过直接相关测试,再进入规格与质量复核。
实现状态和可复现命令见 仓库结构实施。