mcpField
O
objectstack-platform

objectstack-platform

github.com/objectstack-ai开发76220 次安装今天更新
代码仓库

关于 objectstack-platform

objectstack-platform 是介绍 ObjectStack 项目配置、运行时设置和插件开发的技能,指导开发者使用 `defineStack()`、验证元数据、管理构建产物、选择驱动及了解内核和 HTTP 边界。

主要功能

  1. 01使用 defineStack() 配置堆栈
  2. 02验证元数据及交叉引用
  3. 03构建并组织项目脚手架
  4. 04选择和连接存储驱动
  5. 05开发插件及内核集成
  6. 06通过 Hono 集成 ObjectStack HTTP 路由

适用场景

  1. 01初始化 ObjectStack 项目
  2. 02运行前检查堆栈元数据
  3. 03为开发或生产环境选择驱动
  4. 04将 ObjectStack 路由嵌入 Hono 应用

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/objectstack-ai/objectstack --skill objectstack-platform

安装后在 Claude Code 中输入/objectstack-platform确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
config-plugins-ops.json
references/
_index.md
bootstrap.md
plugin-hooks.md
plugin-development.md
operations.md
rules/
plugin-lifecycle.md
service-registry.md

详细介绍

Platform — ObjectStack 引导与插件系统

围绕 defineStack() / 内核表面的两个关注点:项目设置 (objectstack.config.ts、驱动程序、启动序列)和插件 开发(插件、服务、内核钩子 / 事件处理器、 ObjectKernel 与 LiteKernel)。


defineStack() — 核心配置

objectstack.config.ts 是每个项目的唯一入口。 它调用 defineStack() 来声明所有元数据。

→ 已原样移至 references/bootstrap.md § 最小示例。

完整配置参考

defineStack() 接受一个 ObjectStackDefinitionInput,其顶层键 包括 manifest、packages、objects、objectExtensions、picklists、 picklistExtensions、views、apps、pages、dashboards、reports、 datasets、actions、flows、jobs、 emailTemplates、docs、books、positions、permissions、 capabilities、sharingRules、apis、webhooks、api、server、 agents、tools、skills、hooks、functions、mappings、 analyticsCubes、connectors、data(种子数据)、datasources、 datasourceMapping、translations、i18n、plugins、devPlugins、 devHint、devLogins、requires、tiers、onEnable、appName、email、sms。

这里有意不提供顶层 workflows 或 approvals 集合: 审批是通过包含 Approval 节点的流程来编写的(ADR-0019),记录 状态机则是每个对象上的 state_machine 验证规则 (ADR-0020)。roles: 或 policies: 这样的虚构键不会被静默忽略——顶层会拒绝它,导致堆栈加载失败:

defineStack validation failed (1 issue):

  ✗ (root): Unrecognized key(s) on this stack definition: `policies`. …

未声明的键会根据所在表面进行处理,应牢记以下两种处理方式:

  • 拒绝——defineStack() 的顶层、每个 objects[] 条目 (ObjectSchema)以及每个字段(FieldSchema)。解析会抛出错误,指出 表面和有问题的键。TypeScript 会更早拒绝该字面量, 并报出 TS2353: Object literal may only specify known properties。
  • 发出警告后丢弃——形状尚未封闭的编写表面(connectors 就是其中之一)。 defineStack() 会在解析前打印警告,该值也不会通过解析: defineStack: connectors.stripe.bogusKey: 'bogusKey' is not a declared connector key, so its value is dropped at load. 应将这些情况视为即将成为错误的问题——封闭其余形状是已安排的迁移,因此今天只会触发警告的键,预计之后会被拒绝。

确切的 Zod 形状——包括哪些键是可选的,以及集合项采用哪些类型——请参阅 node_modules/@objectstack/spec/src/stack.zod.ts (ObjectStackDefinitionSchema)。每个集合的项形状都位于其各自的域文件夹中(data/object.zod.ts、ui/view.zod.ts,等等)。

→ 已原样移至 references/bootstrap.md § 映射格式(键 → 名称)· § Barrel 导入模式。

严格验证

defineStack() 默认会进行验证(strict: true):

  1. Zod 模式——字段名称、类型、枚举
  2. 交叉引用——视图 / 操作 / 流程引用已定义的对象
  3. 种子数据——数据集对象存在于定义中

要禁用(高级用法——例如由其他插件提供对象):

export default defineStack(config, { strict: false });
编译产物与运行时元数据边界

ObjectStack 运行时元数据必须来自本地开发期间的源文件,或来自编译产物。不要将环境运行时配置为通过业务数据库读取或写入元数据。

# the CLI ships an `os` binary; `objectstack` is an alias for it
objectstack compile
# -> dist/objectstack.json

OS_ARTIFACT_PATH=./dist/objectstack.json objectstack dev

运行时经验法则:

场景元数据来源数据库用途
本地开发TS 文件或 dist/objectstack.json仅存储业务行
生产运行时Artifact API 响应仅存储业务行
控制平面元数据存储中的已发布 JSON环境版本、历史记录、覆盖项

生成 objectstack.config.ts 时,对象名称要简短并使用 snake_case;绝不要设置 tableName,也不要将 sys_metadata 对象添加到环境运行时清单中。


清单参考

每个栈都需要一个 manifest 来标识自己在生态系统中的身份:

manifest: {
  id: 'com.example.crm',        // Reverse domain unique ID
  version: '1.0.0',             // Semver
  type: 'app',                  // app | plugin | driver | module | ...
  name: 'Acme CRM',             // Human-readable display name
  description: 'CRM system',    // Optional description
  engines: { protocol: '^17' }, // Metadata-protocol major this app targets
}

manifest.engines.protocol: 应用所依据的元数据协议主版本。create-objectstack 会将其写入生成的每个项目中(所有三个示例应用也都包含此项)。运行时会在加载任何内容之前检查它,因此,超出版本范围的运行时会在边界处拒绝该应用,并给出准确的迁移命令,而不会等到之后才崩溃。只有在有意迁移到新的协议主版本时才更改它,绝不要为了消除版本不匹配而更改。

对象命名: 对象的 name 是规范标识符,且与物理表名相同。任何域前缀都要直接嵌入名称中(例如 name: 'crm_account');对象级别的 namespace 字段已废弃(ADR-0129 D3),加载时会被拒绝。

manifest.namespace(ADR-0048): 可选,但设置后会强制执行。当包声明 manifest.namespace: 'crm' 时,每个 object.name 都必须以 crm_ 开头,否则 defineStack 会报错(@objectstack/spec 中的 validateNamespacePrefix);旧版 <ns>__<short> 双下划线格式会被拒绝,而以 sys_ 为前缀的名称属于平台保留名称,不受此限制。命名空间也是包所有权标识键——如果安装的两个包都声明 crm,就会失败并返回 NamespaceConflictError(使用 OS_METADATA_COLLISION=warn 可将其降级为警告)。设置命名空间后,os lint 还会对名称未带命名空间前缀的 UI/自动化项(app、page、dashboard、flow、action、report、dataset)发出非致命的 naming/namespace-prefix 警告。


应用 / 平台边界

ObjectStack 应用是业务功能的简化实现:依据平台规范编写元数据,在这些技能的指导下完成,并使用 os 命令检查(验证你的工作)。绝不要重建平台负责的内容。

  • **业务功能属于应用;能力属于平台。**缺少默认值、诊断错误、规范拒绝的结构——应在上游修复。在那里提出问题;不要在此处补偿。
  • 能否由只掌握元数据、不了解这家公司的事物来编写? 不能——它编码了这家公司的特定判断(折扣上限、案件分配对象、赢单/输单的登记方式)⇒ 属于应用。能——它只检查元数据是否自洽(引用完整性、翻译覆盖率、视图成员列表、共享规则覆盖率、CRUD 往返测试、针对每个已声明职位的 RLS 探测)⇒ 属于平台。
  • 平台缺陷意味着等待平台修复。不要编写防御性代码,不要容忍不符合规范的结构,不要手写谓词重新实现平台规则,也绝不要“先合入能做的一半”——这会放弃契约优先的选择,并导致决策只执行了一半。将阻塞情况记录在平台问题中,使其可供机器识别;恢复工作前,确认你锁定的版本包含该修复(上游已合并 ≠ 你锁定的版本已包含),并重新运行该缺陷对应的复现步骤。
  • 不合适的平台默认值应该修正默认值,而不是在每个调用点绕开它。

模板

blank 是 create-objectstack 提供的唯一模板,也是默认模板:

  • 随 create-objectstack 一起打包,无需从网络获取
  • 包含一个示例对象;requires: ['automation', 'triggers'],以及 plugins: 中的三个通用连接器执行器;还有八个生成器聚合文件(objects、views、actions、flows、dashboards、apps、skills、picklists),每个 src/*/index.ts 都通过 exportsOf 交给与其名称对应的堆栈键。脚手架生成的 AGENTS.md 说明了如何向其中添加内容。文件中不包含 memory 驱动和 Hono 服务 — CLI 会在启动时自动注册两者
  • 提供干净的起点,便于根据本技能所述扩展元数据

五个已弃用的远程模板(todo、compliance、content、contracts、procurement)会按名称拒绝。

→ 原文已移至 references/bootstrap.md § 脚手架命令。


项目结构约定

每个 ObjectStack 项目都遵循以下目录结构:

my-app/
├── objectstack.config.ts    # ← THE entry point — defineStack()
├── package.json
├── tsconfig.json
└── src/
    ├── objects/              # Business object definitions
    │   ├── task.object.ts    # → exports a single object
    │   └── index.ts          # → barrel: export * from './task.object'
    ├── views/                # Optional: UI view definitions
    │   ├── task.view.ts
    │   └── index.ts
    ├── apps/                 # Optional: app definitions (nav, pages)
    │   ├── main.app.ts
    │   └── index.ts
    ├── flows/                # Optional: automation flows
    │   ├── task.flow.ts
    │   └── index.ts
    ├── actions/              # Optional: action definitions
    │   ├── task.action.ts
    │   └── index.ts
    ├── dashboards/           # Optional: dashboards
    ├── reports/              # Optional: reports
    ├── datasets/             # Optional: analytics datasets
    ├── i18n/                 # Optional: translation bundles
    └── handlers/             # Optional: runtime hook handlers
命名约定
概念约定示例
文件名{name}.{type}.tstask.object.ts、main.app.ts
机器名称snake_caseproject_task、first_name
配置键camelCasemaxLength、defaultValue
聚合导出Object.values(imported)objects: Object.values(objects)

驱动选择指南

驱动是存储层。请根据环境选择:

驱动包适用场景备注
Memory@objectstack/driver-memory开发、测试、原型设计InMemoryDriver — 重启后数据会丢失
SQL@objectstack/driver-sql生产环境(PostgreSQL、MySQL、SQLite)SqlDriver — 底层使用 Knex.js(pg / mysql / better-sqlite3 客户端)
MongoDB@objectstack/driver-mongodb生产环境(文档存储)MongoDBDriver
SQLite WASM@objectstack/driver-sqlite-wasm浏览器 / WebContainerSqliteWasmDriver — 进程内运行,无需服务端
Turso@objectstack/driver-turso边缘端、无服务器、多租户仅限 Cloud / EE — 随 ObjectStack 云端 / 企业版发行版提供,不属于开源框架。开源核心 CLI 能识别 libsql:// URL,但会明确报错(UnsupportedDriverError)
驱动接线 — 通常无需手动操作

在 os dev / os serve / os start 下,CLI 会根据数据库 URL 自行解析驱动,并为你注册 DriverPlugin(开发环境使用 memory,生产环境使用 SQL)。不要将驱动放入配置的 plugins: 数组:没有示例应用这样做,而且 plugins: 键用于 CLI 无法推断的插件(连接器执行器、自定义插件)。通过设置数据库 URL 来选择驱动,而不是编写代码。

只有在你负责运行时(通过 Runtime / ObjectKernel 嵌入,或直接启动内核的测试)时,才自行构造 DriverPlugin:

import { DriverPlugin } from '@objectstack/runtime';
import { SqlDriver } from '@objectstack/driver-sql';

new DriverPlugin(new SqlDriver({ client: 'pg', connection: process.env.DATABASE_URL }));

HTTP 层(Hono)

有两个包:

包导出项使用场景
@objectstack/honocreateHonoApp({ kernel, prefix })由你负责服务端:将 ObjectStack 路由嵌入自己的 Hono 应用 / 部署目标。
@objectstack/plugin-hono-serverHonoServerPlugin由 ObjectStack 负责服务端:这是一个用于托管 Hono 应用并打开监听套接字的内核插件(os dev / os serve 注册的就是它)。

不存在 @objectstack/adapter-* 包(没有 adapter-express / -fastify / -nextjs / -nuxt / -nestjs / -sveltekit)。要集成其他框架,请挂载 Hono 应用(符合 Web 标准的 fetch 处理程序),或自行调用分发器。

用法模式(Hono)
import { createHonoApp } from '@objectstack/hono';

// prefix defaults to '/api'.
export default createHonoApp({ kernel });

⚠️ prefix 不会改变 auth 的挂载位置。 /auth/* 挂载路径遵循 auth 服务的 basePath(AuthPlugin 默认值为 /api/v1/auth),而不是 prefix — createHonoApp({ kernel }) 会将请求路由到 better-auth 的 /api/v1/auth/*。如果 prefix 不在该 basePath 下,启动时会拒绝,并指出这两个值。

架构

createHonoApp 会创建一个 HttpDispatcher,为 auth 和发现功能挂载显式 路由,并将其他所有请求委派给它 — 因此,添加到 HttpDispatcher 的新 路由会自动生效。


运行时启动顺序

了解 ObjectStack 的启动方式有助于调试和自定义:

objectstack.config.ts
  └── defineStack({ manifest, objects, views, ... })
        │
        ▼
CLI: `os serve` / `os dev`
  1. Load .env files (NODE_ENV-based)
  2. Dynamic import of config file
  3. Create Runtime + ObjectKernel
  4. Auto-detect and register plugins (in this order):
     ├── ObjectQLPlugin (if objects defined)
     ├── DriverPlugin (memory in dev, SQL in prod)
     ├── AppPlugin (loads the defineStack bundle)
     ├── I18nServicePlugin (if translations/i18n defined)
     ├── HonoServerPlugin (registered BEFORE AuthPlugin — the server must
     │     exist for plugins that mount routes during init/start)
     ├── AuthPlugin
     ├── Split platform-app plugins (ADR-0048, optional/best-effort, after AuthPlugin):
     │     @objectstack/setup → createSetupAppPlugin   (first-run wizard)
     │     @objectstack/account → createAccountAppPlugin
     │     (@objectstack/studio is intentionally NOT default-loaded — the
     │      Console, mounted at /_console/ by `--ui`, ships its own Studio
     │      surface at /_console/studio/…)
     ├── RESTPlugin (auto-generated API)
     ├── DispatcherPlugin
     └── AIServicePlugin (cloud / EE only — reverse-mounted by a cloud host; absent in the open framework per cloud ADR-0025)
  5. Runtime.start() → init + start all plugins
  6. Server listens on the resolved port (see "Ports & networking" in Part 3)

端口解析(os dev 和 os start 都会转到 os serve): --port 标志 › $OS_PORT › $PORT › 3000。发生冲突时的行为 取决于运行模式 — 开发模式会尝试下一个空闲端口,生产模式则会明确报错。请参阅 端口与网络。

requires: — 哪些服务插件会启动

第 4 步的列表是固定核心。其他所有服务插件都需显式启用,而 堆栈根节点中的 requires: [...] 就是启用它们的方式。CLI 会通过 packages/cli/src/commands/serve.ts 中的 CAPABILITY_PROVIDERS 注册表展开每个 标记 — 其中有 19 个可选条目:

标记提供方包
automation@objectstack/service-automation — 工作流,以及任何声明式 connectors: 条目
analytics cache storage queue job messaging realtime settings sms@objectstack/service- + 标记
marketplace@objectstack/service-package
audit email sharing approvals webhooks@objectstack/plugin- + 标记
pinyin-search@objectstack/plugin-pinyin-search
mcp@objectstack/mcp
triggers@objectstack/trigger-record-change,以及 trigger-schedule 和 trigger-api

PLATFORM_CAPABILITY_TOKENS 中未列入该映射的标记,无法通过该映射 解析:

  • 受层级限制 — ai、ai-studio、i18n、ui、auth 没有提供方条目;serve.ts run() 中的专用代码块会改为启用相应层级 (ai/ai-studio 通过由意图驱动的 AI 代码块启用,其他三个通过 各自的层级代码块启用)。
  • 企业版 / 云端 — hierarchy-security 没有开源版本的提供方, 随 @objectstack/security-enterprise 一同发布,并通过 plugins[] 加载; ai-seat 和 governance 仅由云端的 objectos-runtime 解析。

权威列表是 PLATFORM_CAPABILITY_TOKENS (@objectstack/spec,kernel/platform-capabilities.ts)— 未知标记会在编写时被 defineStack 拒绝,而不是在启动时拒绝。

以下五条规则会影响你的配置:

  • 优先级: requires › tiers › --preset › 内置默认值。plugins: 中的 显式实例始终会覆盖能力解析。
  • 声明即表示需要。 如果你声明的能力所对应的提供方包不存在,就会导致启动错误;平台自动注入的能力则会尽力启用(发出警告并继续)。
  • auth 会隐含 email。 Auth 回调(密码重置、邮箱验证、魔法链接、邀请)需要邮件服务,因此 CLI 会在需要 auth 时自动追加 email。
  • 只要 plugins: 中列有连接器,就保留 automation — 连接器执行器会向其注册提供方工厂;没有它就无处注册,启动会失败。
  • 将 triggers 与 job 配对使用。 单独启用 triggers 只会启动记录变更触发器;计划触发器和相对时间触发器由 job 服务运行,因此没有 job 时,自动启动的计划工作流不会执行。
onEnable — 应用绑定运行时代码的位置

objectstack.config.ts 可以在默认堆栈旁导出 onEnable。 AppPlugin 会在启动期间调用它,并传入应用的实时运行句柄:这是声明式元数据进入命令式代码的唯一接口(注册操作处理程序、向作业提供数据句柄、预配夹具数据源)。三个示例应用都使用了它。

export const onEnable = async (ctx: { ql: { registerAction: (...a: unknown[]) => void } }) => {
  registerTaskActionHandlers(ctx.ql);
};

→ 原样移至 references/bootstrap.md § 插件加载顺序很重要 · § 编程式引导(不使用 CLI)。


→ 原样移至 references/bootstrap.md § 多应用组合。


种子数据

堆栈的 data: 集合使用 defineSeed() 编写,该函数由 objectstack-data 提供——有关 externalId 匹配、env: 作用域,以及哪些键是派生键,请参阅该项目。尤其要注意,object 是从对象定义派生而来:切勿手动填写,也不要手写原始的 data: [{ object: … }] 字面量。

mode 决定种子运行如何处理已存在的行:

模式行为
upsert(默认)根据 externalId 匹配结果插入或更新
insert始终插入(遇到重复项时失败)
update仅更新找到的记录;忽略新记录
ignore不存在时插入,否则跳过
replace⚠️ 数据丢失 — 删除并重新插入所有记录

CLI 命令

日常命令见 第 3 部分 — 运维。 引导循环速查表:

npx create-objectstack my-app
cd my-app && npm install
os dev --ui          # dev server + Console at /_console/ (auto-hops port if taken)
os validate          # metadata cross-reference checks
os compile           # produce dist/ artifact
os migrate plan      # preview metadata↔DB schema drift (additive sync never alters existing columns)
os migrate apply     # reconcile DB to metadata (loosening only; --allow-destructive for drops/tightenings)
PORT=8080 os start   # production — pin the port explicitly (see Ports & networking)

→ 原样移至 references/bootstrap.md § 完整工作示例。



→ 第 2 部分 — 插件开发与内核扩展已原样移至 references/plugin-development.md(快速参考 — 详细规则 · ObjectKernel 与 LiteKernel · 插件接口 — 快速概览 · PluginContext API · 完整插件示例 · 使用插件 · 测试插件 · 知名插件名称与服务 · MetadataPlugin 运行时边界 · 健康监控 · 功能标志);其详细规则见 rules/plugin-lifecycle.md · rules/service-registry.md · references/plugin-hooks.md。



→ 第 3 部分 — 运维:CLI、测试、部署已原样移至 references/operations.md(日常循环命令 · 构建与运行时 · 验证工作 · 端口与网络 · 数据与迁移 · 环境与部署 · 发布插件 · 测试模式 · 部署目标 · 健康与可观测性 · 常见运维陷阱)。


参考资料

完整的 Zod 架构列表(含单行说明)见 references/_index.md——其中包含指向 node_modules/@objectstack/spec/src/ 的索引。请始终 Read 源码以确认准确的字段结构;不要依赖对属性名称的记忆。

评论

支持 Markdown