构建

包

ObjectOS 中的组织单元 —— 有版本、可安装、可共享。

你在 ObjectOS 中构建的一切都存在于一个包中:一个有版本的、自包含的 元数据集合。包是 AI Builder 工作的单元、市场交付的单元,也是 ObjectOS 跟踪更新的单元。

包里有什么

com.acme.crm@1.2.0
├── manifest          id, version, namespace, dependencies
├── objects/          *.object.ts, *.state.ts, *.hook.ts
├── views/            *.view.ts, *.page.ts, *.form.ts
├── actions/          *.action.ts
├── flows/            *.flow.ts, *.approval.ts
├── agents/           *.agent.ts, *.skill.ts
├── permissions/      *.permission.ts
├── sharing/          *.sharing.ts
├── translations/     en.ts, zh-CN.ts, ...
├── apps/             *.app.ts  (navigation)
└── data/             defineDataset(...) seed

每个元数据产物(对象、动作、流程 ……)恰好属于一个包。包 id 采用 反向域名形式(com.acme.crm、org.mycompany.helpdesk),命名空间 前缀(crm_、hd_)让安装在同一租户中的不同包的表名 / 对象名不会冲突。

创建包

通过 AI Builder

"为我们的内部 CRM 新建一个包,命名空间为 crm。"

AI 会调用 create_package 和 set_active_package。从那以后,你描述的 每个对象 / 字段 / 动作都会落在 crm 中。

通过 CLI

os init my-crm -t app
cd my-crm
# manifest lives in the `manifest:` block of ./objectstack.config.ts
pnpm dev

通过 UI

Studio → Packages → New Package —— 名称、id、版本、命名空间。

当前包

在 AI Builder 中,一次对话带有一个当前包 —— 新元数据的默认容器。当你 说类似 "切换到 com.acme.helpdesk。" 的话时,AI 会用 set_active_package 工具设置它。在 CLI 中,当前包就是项目 objectstack.config.ts 中(manifest: 块)声明的那个包。

版本管理

包采用 semver。规则与运行时相同 —— 参见 更新日志与版本管理。

在你发布之前,升级版本号不会改变任何东西。运行时会按租户、按包跟踪 installed_version,当目录中有更新的版本时,市场会显示一个 "Update available" 徽标。

依赖

包可以依赖其他包:

{
  "id": "com.acme.helpdesk",
  "version": "0.3.0",
  "dependencies": {
    "com.acme.crm": "^1.0.0",
    "sys.feeds":   "*"
  }
}

运行时在安装时解析依赖。如果 com.acme.crm 没有安装,helpdesk 的安装会 失败,并给出清晰的错误。

系统包(sys.*)始终存在 —— 信息流、附件、审计、身份等。

发布

os cloud login                 # once: stores a cloud token in ~/.objectstack/cloud.json
os compile                     # → dist/objectstack.json
os package publish             # → ObjectStack cloud catalog

os package publish 会把编译好的清单上传到 OS_CLOUD_URL 所指定的目录。 认证来自 os cloud login(交互式),或者在 CI 中来自一个 OS_CLOUD_API_KEY bearer 令牌。对于私有 / 物理隔离的分发,跳过发布, 直接把编译好的 dist/objectstack.json 交给目标安装环境(见下文的安装)。 参见市场。

这两个变量配置的是你构建机器的发布身份 —— 也就是 CLI 访问包目录的 凭据。它们不是部署连接控制平面的方式:一个运行中的部署用它被绑定时 签发的令牌进行认证,没有需要配置的 API 密钥。在把这两个名字中的任何一个 复制到部署的配置中之前,请先查看环境变量。

ObjectOS Cloud 上的两条开发者路线

开发者可以通过以下两种方式之一,把变更带进托管环境:

包发布MCP 构建
怎么做在源码中构建,然后 os package publish,再从 Marketplace 安装你自己的 Agent 通过 MCP 以 metadata:write scope 接入,在环境中构建
落地的是什么一个有版本的包,整体安装环境中的草稿,由人在 Studio → Changes 中发布
能构建什么环境运行的一切,包括脚本、Webhook 和 API 触发的流程环境的 AI 构建所提供的内容:数据模型、界面、示例数据、应用外壳、由记录和按钮触发的流程、无代码动作
最适合发布版本:多个环境中的同一版本、在你的仓库中评审、Marketplace迭代:在一个环境中尝试变更并在应用中看到它

用 MCP 构建快速塑造一个应用;一旦它需要版本,就改用包:把它交付到另一个 环境或组织、把它保存在仓库中,或承载 MCP 构建不提供的元数据。

安装

安装是一个环境内的操作 —— 与发布不同。你把包发布一次(到目录),然后 在目标环境内部安装它,由你的环境登录确认并授权这次安装。安装时你永远 不需要知道环境 id。

路径怎么做
在 UI 中(推荐)登录环境 → Marketplace → 选择包 → Install。安装到当前环境。
CLI → 运行中的运行时os package install com.acme.crm --runtime <url> —— 运行时从它配置的目录中解析包,并把它合并到自己的内核中
CLI 物理隔离os package install ./dist/objectstack.json --runtime <url> —— 内联发送编译好的产物,不经过目录往返
RESTPOST /api/v1/marketplace/install-local(请求体:{ packageId, versionId? } 或 { manifest })
物理隔离(启动时)挂载编译好的 dist/objectstack.json 产物(参见物理隔离)

安装命令中的包 id 是稳定的清单 id(com.acme.crm)—— 你永远不需要内部的 pkg_… 行 id。

CI 快捷方式。 部署到一个已知环境的流水线可以一步完成发布和安装: os package publish --env <id> --install [--seed-sample-data]。这是为 自动化提供的便利,而不是人使用的路径 —— 交互式安装发生在环境的 Marketplace 中。 这一步是全有或全无的:如果安装被拒绝,就什么都不会发布 —— 不会存储任何 版本,命令以非零状态退出,因此流水线能看到这次失败。

安装会把包的元数据合并到实时内核中,向 ObjectQL 注册它的对象,并在首次 安装时写入初始数据 —— 无需重启。缓存的安装会在下次启动时重新注册,所以 它们能在进程重启后保留下来。

卸载

卸载会删除包的缓存清单,使它在下次启动时不再被重新注册。由于对象注册是 累加式的,要完全卸下一个已在运行的包的对象,需要重启内核。数据默认 保留,所以你可以重新安装并继续。

跨包约定

为了防止许多包共存时发生冲突:

产物约定
对象名称始终带前缀:crm_account、hd_ticket
动作名称带前缀:crm_assign_owner、hd_close_ticket
流程名称带前缀:hd_overdue_alert
翻译键放在命名空间之下:crm.account.label
种子数据 externalId<prefix>:<key>,例如 crm:demo-account-1
系统名称保留:sys_*(自定义包中永远不要使用)

CLI 和 AI Builder 都会在创建时强制执行这些约定。

系统包

运行时自带一小组始终存在的包,提供多态服务:

包提供
sys.identitysys_user、sys_organization、sys_member、会话、API 密钥
sys.feedssys_comment、sys_activity、sys_attachment
sys.auditsys_audit_log
sys.filessys_file
sys.aiai_conversations、ai_pending_actions
sys.settingssys_setting

你通过在对象上设置 enable: { feeds: true, trackHistory: true, … } 来启用 它们 —— 参见数据模型。

下一步