mcpField
B
busabase-app-creator

busabase-app-creator

github.com/busabase开发3184 次安装1 天前更新
代码仓库

关于 busabase-app-creator

Busabase App Creator 是用于创建或维护 Busabase AirApp 和可安装模板的技能。它规定应用结构、运行时、安全、部署和审核方面的技术要求,视觉与产品选择则留给用户或上层技能。

主要功能

  1. 01创建 AirApp 和可安装模板
  2. 02维护指定的现有 AirApp
  3. 03制定运行时、安全和部署要求
  4. 04使用 Busabase 资源与 ChangeRequest

适用场景

  1. 01构建由新工作区支持的 AirApp
  2. 02将应用打包为可安装模板
  3. 03在获准范围内更新现有 AirApp

安装

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

$npx skills add https://github.com/busabase/skills --skill busabase-app-creator

安装后在 Claude Code 中输入/busabase-app-creator确认已加载。

包含的文件

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

agents/
openai.yaml
assets/airapp-template/
.gitignore
airapp.json.template
package.json.template
server.js
server.py
assets/airapp-template/app/
index.html
styles.css
assets/airapp-template/app/js/
app.js
busabase-client.js
config.js
messages.js
runtime.js
assets/airapp-template/app/js/providers/
busabase-provider.js
demo-provider.js
index.js
assets/airapp-template/scripts/
check.mjs
assets/package-scripts/
sync-content.mjs
references/
app-engineering.md
deployment-and-review.md
interview-and-blueprint.md
maintenance.md
resource-model-and-security.md
runtime-and-sdk.md
template-format.md
ui-and-validation.md
scripts/
airapp-kit.mjs
airapp-kit.test.mjs
check-runtimes.test.mjs

详细介绍

Busabase App Creator

创建一个隔离的 Busabase 工作区和 AirApp,将可安装模板编写为磁盘上的文件,或维护一个经过明确标识的现有 AirApp。本技能是 AirApp 建模、模板/软件包格式、安全性、运行时工程、部署和维护的唯一技术事实来源;更高层级的工作流技能会将这些事项委托给本技能。

本契约规定的是格式和正确性,而非审美。它说明有效应用和有效模板必须包含什么——资源、手册、运行时规则、审核关卡——仅此而已。产品风格、视觉样式、布局惯例和交互润色由用户决定,或由在此基础上叠加的更高层级技能决定(例如 kelly-app-skill-creator);本技能绝不能形成会与这类上层规范冲突的偏好。

目前存在两个上层技能:面向公开目录 busabase/templates 的 busabase-template-creator,以及面向 mr-kelly/skills 的 kelly-app-skill-creator。两者都会调用本技能来确保正确性,并且只会在此基础上增加发布门槛。请注意,busabase-package-creator、busabase-skill-creator 和 busabase-app-package-creator 都是指向本技能的符号链接,并非独立技能——四个入口名称,同一份契约。

不容妥协的契约

  • 使用 $busabase 处理连接、API、ChangeRequest 和审批行为。执行任何远程操作前,先阅读其 SKILL.md。
  • 交付手册和提示词,而不只是资源。 无论本次运行产出什么,其 Folder 最终都必须包含一个以应用命名的 skill 节点,并且它创建的每个节点都必须带有场景 Agent 提示词,提示词开头要引导 Agent 使用该 skill。若 Folder 中的节点只提供各自节点类型的通用提示词,就还没有完成:安装者会陷入“有数据了,接下来呢”的困惑。随着应用逐渐成形,逐步编写 skill 节点;创建每个节点时,也同步编写该节点的提示词(步骤 5,第 6 项)。要求与标准:步骤 10。
  • 一开始就确定路线,整个运行过程不得混用路线:重新安装(只需确保此 Space 中存在已构建的 bundle——见步骤 1)、create 工作区优先、create package 优先(见“Two Ways In”一节),或 maintain。在 create 中,创建一个新 Folder、至少一个新的工作流 Base、所需的原生资源,以及一个新的 AirApp;绝不附加到或修改现有业务 Base。在 maintain 中,遵循 references/maintenance.md;如果变更属于获批的维护范围,应用可以持续创建或修改相关工作区资源。
  • 每条消息只问一个决策问题。提供两个或三个具体选项,分别标为 A、B,以及可选的 C;适当时标明推荐选项,然后请用户回复字母或输入自定义答案。绝不只抛出一个没有选项的开放式访谈问题。
  • 连接前,先请用户选择 Busabase Cloud 或 Desktop。
  • 搭建脚手架前,先确定源码的归属。对于独立 AirApp,询问源码应使用临时目录,还是用户指定的持久目录。若由更高层级的 App-in-Skill 创建器委派至此,不要再次询问:将该 skill 的 AirApp 项目根目录作为完整、持久的源码。该根目录为 <skill-root>/content/<name>-app/——这是模板布局,也是包含应用的 skill 的目录结构。项目仍位于 <skill-root>/app/ 的 skill 属于旧版,尚待迁移:在原位置读取,不要因无关工作而顺带迁移(迁移还会影响 harness 路径和根脚本,因此应作为有意安排的迁移)。解析根目录时,先检查 content/<name>-app/ 下的 package.json,再检查 app/。无论哪种布局,目录中都包含 package.json、server.js、浏览器端 app/ 子目录、检查项和 lockfile;仍可通过 pnpm dev 运行,但除非用户明确要求本地预览或调试,否则委派式创建不启动本地开发。
  • 将持久化的本地项目视为规范版本。向 AirApp 提交同一份经过审查的项目文件树,但排除 .env、node_modules 和日志等仅供本地使用的文件。不要维护第二套 AirApp 实现,也绝不要留下只存在于远程端的编辑:将其读回,回写至规范本地项目,并在继续之前重新运行检查。
  • 先选择运行时:node(默认)或 python。 AirApp 的浏览器端——即 app/ 下的所有内容——两者完全相同;区别仅在于提供服务的进程。若应用本身的工作使用 Python(数据、爬取、ML),就选择 python;否则选择 node。Python AirApp 无法做到的一件事见下文“Python AirApps”。
  • 搭建新应用脚手架时,node 应用使用 Hono 加原生 HTML/CSS/JavaScript;python 应用使用标准库 server.py 模板(airapp-kit.mjs scaffold ... --runtime python);两者都不要引入 React、Vite、JSX 或应用框架构建流程。搭建脚手架时,将已安装的 SDK 打包到本地;部署后的 start 只能运行服务器。
  • 这是搭建脚手架时的默认方案,并非对你没有编写的应用作出的判定。 基于框架的 AirApp 是有效的:[email protected] 可在浏览器内引擎中启动,而 remote 引擎是普通容器,其中 Next/React 是已交付的演示。在 maintain 中评估现有应用之前,先阅读 references/runtime-and-sdk.md 中的“Which Stack Is Allowed”;绝不要把框架依赖视为违规,也不要建议将能正常运行的框架应用重写为原生 JS。此外,不要对本 skill 未搭建的项目运行 airapp-kit check——它会报错 React/Vite are forbidden.,这是误报,并非发现了问题。
  • 在 maintain 中,将规范文件树视为常规目标之前,先检查已部署的文件树是否能够自行构建——见 references/maintenance.md 中的“Is There Source Here At All?”。如果只有 dist,文件树中没有构建它的工具,且任何地方都找不到源码,那么这是停止条件,不是可供继续修改的基础:绝不要为了满足变更要求而修补压缩后的 bundle。
  • 解析最新发布的 busabase-sdk(0.99.0 或更高版本),并确认其导出 createBusabaseClient、本地 AirApp OAuth 网关、describeBusabaseAirAppRuntime、Node 凭据存储入口,以及 busabase-sdk/airapp 中的浏览器 AirApp helpers(detectAirAppRuntime、createAirAppRecords、airAppWriteMessage),然后在生成的应用中固定精确版本。脚手架会完成所有这些工作,并拒绝使用较旧的 SDK。
  • 使用 SDK 的 AirApp helpers;不要自行编写。 运行时探测、记录读取和写入,以及“已保存或正在等待审核”的结果与提示语,全部来自 busabase-sdk/airapp。脚手架已将其作为 app/vendor/busabase-airapp.js 打包到应用中(detectAirAppRuntime、createAirAppRecords、toAirAppWriteOutcome、airAppWriteMessage)。每个应用各自维护这些函数的副本,正是同一个 bug 最终需要在数十个应用中手动修复的原因。references/runtime-and-sdk.md 说明了每个函数的用法。
  • 在浏览器代码中,针对 window.location.origin 使用 createBusabaseClient。绝不硬编码绝对 Busabase URL,绝不使用已废弃的 /__busabase_api__/ 桥接前缀,也绝不在浏览器代码或 AirApp 文件中放入 API key、Bearer token、OAuth token、session cookie 或密钥。只有回环本地开发会使用 references/runtime-and-sdk.md 中定义的 Hono OAuth 边界。已部署的 AirApp 必须跳过 OAuth 门控,并使用当前查看者的同源环境会话;环境凭据只是显式的自动化/测试覆盖方式,不是用户上手流程。
  • 在 create 中,除非用户明确要求一个小型操作,否则第一个版本保持只读。无论哪种模式,任何请求的写入都必须通过 SDK 的记录 helpers 创建 ChangeRequest,并且不设置 autoMerge:对于具有写入权限的查看者,Busabase 会合并该请求;对于没有写入权限的查看者,则会将其排入审核队列。应用应说明实际发生了哪种情况。AirApp 绝不调用审核或合并操作,也绝不自行强制审核。
  • 在 create 中,只访问本次运行创建的资源。在 maintain 中,使用现有资源的准确 ID,并为新获批的资源显式填写 ID;绝不通过匹配名称或 slug 来发现或挪用无关资源。对于新需求,使用 Busabase 原生资源建模。
  • 在蓝图中声明第三方集成和 Vault 要求,不填写具体值。浏览器 AirApp 无法读取 Vault。需要使用密钥的工作必须通过可信的 Busabase Workflow,或经过明确配置的 Agent 路径执行。
  • 通过 busabase-sdk 从 Busabase 加载持久化的应用配置及工作流/领域状态,并依据能力选择原生节点:使用 Folder/Node 表示层级和身份,使用 Base 和 View 表示结构化运营状态,使用 Doc 表示持久叙述性配置,使用 Drive/File 存储资源,以及使用 Vault 引用密钥。生成的本地配置只能包含准确的已物化 ID、流程允许列表、限制、架构版本,以及非敏感的就绪状态元数据。不要将本地 JSON、SQLite、浏览器存储或演示用 provider 作为第二个持久事实来源。
  • 在 create 中,创建结构后,将每个已物化的 Folder、Node、Base、View 和资源 ID 写回蓝图。随后,生成的运行时代码必须通过稳定句柄访问这些资源,而不是列出工作区并匹配名称或 slug。具体使用哪种句柄取决于产物的绑定方式——见下文“Two Ways To Bind”;两种都正确,但路线选错会导致应用无法运行。
  • 为每个读取数据的工作流明确设定预算。交互式页面默认每个 Base 最多读取 50 条记录,以及 20 个相关的待处理 ChangeRequest;使用服务端过滤和排序,并行执行相互独立的读取,保留 nextCursor,每次用户操作只获取一页。绝不要在加载、搜索、过滤、刷新、导航、打开详情、“跳转到第 N 页”、while (cursor && n < 4) 上限循环、对 totalPages 执行 Promise.all,或为看似未生效的过滤器提供“回退”时暗中执行全量扫描——见 references/runtime-and-sdk.md 中的 § A full scan in disguise。完整导出和离线分析需要单独、明确的批处理工作流。
  • 使用用户当前对话的语言生成 UI。将消息集中管理,以便后续迭代能够添加其他语言。
  • 在 create 中,默认生成 3 至 5 条逼真的种子记录,并像其他写入一样通过 ChangeRequest 写入:省略 autoMerge,由凭据权限决定直接写入还是排队审核。
  • 在委派式 App-in-Skill create 模式中,默认使用 target-first 验证:运行确定性的静态/项目检查,将审查过的规范文件树作为 AirApp CR 提交,并在目标 Busabase 中从已合并的 HEAD 获取 UI 验收。只有在委派 skill 或用户明确要求运行 pnpm dev、本地 URL、预览或调试时,才使用 local-preview。独立创建 AirApp 时,除非用户明确选择 target-first,否则仍以 local-preview 验收。在 maintain 中,遵循 references/maintenance.md 中的验证和验收关卡。
  • 按照 $busabase 的要求进行写入:省略 autoMerge,并读取响应中的 status。 审核是权限设置,不是此 skill 强加的步骤:拥有写入权限的凭据会立即发布;权限较低的凭据会创建 ChangeRequest;两种结果都正确。不要传入 autoMerge: false,人为制造工作区并未要求的审核关卡;只有当你判断某项具体变更存在足够风险,值得无论凭据权限如何都交由他人复核时,才传入该参数。此 skill 确实会把关的是范围:在 create 中,只能写入用户在当前对话中批准的确切 Folder/Base/字段/关系结构;在 maintain 中,只能写入获批的变更集。
  • 人工把关针对的是范围,而不是每次写入。 多个 Agent 和人员经常会同时在同一个 Space 中工作;要求人工逐一点击合并,以处理已获批范围涵盖的每次写入,只会拖慢进度,并不会增加安全性。因此,一旦范围获批,就应以遵循权限设置的方式编写 AirApp 代码并写入种子数据,然后继续推进。以下三种情况仍须暂停并交由人工处理:超出获批范围的任何事项;你判断存在风险的变更——例如删除或覆盖他人写入的数据,或进行破坏性架构变更——对此应传入明确的 autoMerge: false 并说明原因;以及因凭据无权合并而返回待处理 ChangeRequest 的写入。除非用户要求处理某个具体的 ChangeRequest,否则绝不要自行批准或合并待处理的 ChangeRequest,无论它属于你还是其他 Agent。

两种绑定方式

工件通过两种方式之一访问其资源,具体方式决定了访问路径。 说明这一点并非吹毛求疵:同一个配置字段在一种方式中必填,在另一种方式中则禁止填写,因此跨界复制的提供方会导致应用永远无法加载。

绑定方式应用配置中的 ID解析方式适用场景
pinned是 — Space ID 以及每个 Folder/Node/Base/View ID直接使用;不进行发现workspace-first create 和 maintain,这些场景中的 ID 在搭建应用前就已存在
runtime否inspectProvisionedResources 根据每个 Base 上标记的 resourceKey 进行匹配package-first create 和所有已安装的模板,这些场景中的 ID 要等到有人安装后才会存在

通过 resourceKey 解析并非此技能禁止的按名称和 slug 重新发现。该键在安装时写入,并且对已安装的应用唯一,因此不会命中仅仅名称相同的不相关资源——禁止这样做正是为了避免这种故障模式。

两条规则确保这两种方式各安其位:

  • pinned 缺少 ID 时,绝不能回退到发现。 回退会把明确的配置错误变成悄悄读写错误资源的应用。应使用缺失的 slug 报错。
  • pinned 工件绝不能作为模板发布。 模板会在安装者的 Space 中创建全新的资源;固定 ID 指向的却是作者的资源。发布固定 ID 会把作者的节点 ID 一并发给所有安装者,而安装会先成功,之后应用却什么也读不到——或者在发生冲突时,读写他人的数据。content/<base>/base.json 是资源声明;固定 ID 则是实例化结果。将结果作为声明发布,属于类型错误。

因此,生命周期只能按一个方向进行:模板绑定为 runtime,完成安装后,才能将该安装实例固定。固定是部署上的操作,绝不是分发包的属性。

同一原则也适用于技能本身:指针桩文件——仓库本地的 SKILL.md,其中写有已部署技能节点的 ID,并在使用时获取其正文(§「两种入口」)——是对部署的固定。它让一个工作区技能服务于多个仓库,而且绝不会作为模板发布。

有选择地阅读参考资料

操作前,请完整阅读每份选定的参考资料:

需求参考资料
访谈顺序、停止规则、蓝图结构references/interview-and-blueprint.md
资源放置、原生 View、Vault 和执行安全references/resource-model-and-security.md
SDK、同源 /api/v1 访问、浏览器加载、基于真实数据的本地开发references/runtime-and-sdk.md
前端架构、响应式 UX、状态和测试矩阵references/app-engineering.md
结构创建、AirApp 部署、种子 CR、审批规则references/deployment-and-review.md
共享外壳、领域定制、本地和目标环境验证references/ui-and-validation.md
现有 AirApp 身份、资源与 UI 的持续演进,以及规范回读references/maintenance.md
包布局、busabase.json、SKILL.md frontmatter、验证 — package-first 下写入任何文件前必须阅读references/template-format.md

连接或写入之前,务必先阅读同级的 Busabase 技能 ../busabase/SKILL.md。如果端点结构不确定,应以实时 OpenAPI 为准。

工作流

1. 确定运行方式

首先区分重新安装与 create/maintain:磁盘上是否已有完整构建的 AirApp 包(委托式 App-in-Skill 的 <skill-root>/app/,或任何其他预先构建且经过审核的项目),只需要让它存在于此 Space 中——不需要访谈、不需要新蓝图,代码也不会更改?如果是,请跳过此工作流的其余部分,并使用 busabase-sdk/airapp 中的 publishAirApp(参见 references/deployment-and-review.md §「重新安装已构建的包」)。它会根据 provisionDeclaredResources 的声明解析 Folder;如果该 Space 从未有过 AirApp,就创建 AirApp;如果已有,则提出更新;并像其他写入操作一样,根据权限处理——凭据可以写入 Folder 时直接合并,否则创建 ChangeRequest。但它免去了逐个文件手动构建 ChangeRequest 的工作,而这正是过去每次重新安装都需要启动 Agent 会话、而非运行脚本的原因。这也回答了「设置脚本只创建了 Bases,没有创建 AirApp」的问题:该脚本的数据层资源配置本来就不应在同一个请求中包含 AirApp 部署(参见 airapp.ts 中关于 AirAppNodeDeclaration 的说明——可执行代码与数据层的结构性请求是分开的),它应该将 publishAirApp 作为明确的下一步来调用,而不是把 AirApp 留在那里,等别人发现它缺失。

否则,请逐一提问,并使用带字母编号的选项;已明确说明的信息可跳过:

  1. 创建新的工作区应用,还是维护现有 AirApp?
  2. 部署到 Busabase Cloud,还是 Desktop?
  3. 对于独立 AirApp,将生成的源代码保存在临时目录还是持久目录中?对于委托式 App-in-Skill,记录提供的 <skill-root>/app/ 项目根目录,并跳过此问题。
  4. 记录验证模式。委托式 App-in-Skill 创建默认使用 target-first;只有在用户明确提出要求时才选择 local-preview。独立创建默认使用现有的 local-preview,除非用户明确要求使用 target-first。
  5. 在 create 中,从哪里开始——工作区优先还是软件包优先?请参见下文 §「两种切入方式」。在 maintain 中跳过此问题。
  6. 在 create 中,AirApp 应帮助用户查看或管理什么?在 maintain 中,具体涉及哪个 Space、AirApp 节点 ID,以及哪项行为或运行时更改?

对于 Cloud,使用通过 busabase-cli login 选择的连接,并确认目标 Space。对于 Desktop,确认本地 Busabase URL。切勿输出 .env 内容或令牌值;只展示已脱敏的就绪状态。

1a. 两种入口

create 有两个起点。它们的区别仅在于文件最初存放在哪里;最终都会汇聚为同一个成品,而且任何一种方式都不能跳过另一种方式的验证。

该选哪种方式取决于要制作什么,而不是个人偏好:

  • 制作 技能(一个将存放在技能仓库中的目录)→ 包优先。包含应用的技能就是模板;以其他方式编写,意味着先写文件,再将它们与 Space 对齐。

  • 为单个工作区制作应用,且不要求生成可分发的产物 → 工作区优先。

  • 尚不确定,或仍在决定具体形态 → 工作区优先,最后如果值得分享,再导出。

  • 为已经部署在工作区中的技能提供仓库访问(“我们的其他仓库也想使用同一个技能”)→ 两种方式都不适用。不要在每个仓库中各导出一份副本——副本会逐渐产生差异。应在每个使用方仓库中编写一个指针存根:最精简的本地 SKILL.md,其中只包含 frontmatter 中真正的触发 description、下面的获取命令,以及 Space/节点表。

    npx --yes busabase-cli@latest skills read-file --node-id <id> --file-path SKILL.md --output json
    

    两个标志都有各自的用途。只有 --output json 才会返回完整正文:默认文本输出会将正文压缩成一行预览——在真实服务上测得,一个 40 KB 的技能返回内容只有 426 字节,并以省略号结尾;JSON 格式则会返回全部 40652 个字符以及 contentHash。@latest 用于防止另一种问题:npx 可能会使用缓存的旧版 CLI,而其中可能根本没有这个子命令。

    存根会固定 ID,因此上文关于 pinned 的规则完全适用:绝不能将其作为模板发布;获取失败就必须停止——Agent 不能根据那一行描述自行编造操作流程。

工作区优先(在形态仍未确定时应选择此方式)。按照下方工作流,在实时 Space 中构建 Folder、Bases 和 AirApp,让其使用真实数据运行;只有在用户希望将其分发时,才在之后导出(§“将完成的应用发布为可安装模板”)。这样生成的模板,记录的就是确实运行成功的成果。

包优先(用于编写技能或模板的方式:新的 app-skill、对 busabase/templates 的贡献,或没有可用于构建的 Space 时)。编写第一个文件之前,请完整阅读 references/template-format.md——其中包含目录布局、manifest 和 frontmatter 的格式、记录上限,以及模板不符合资格的情形。先在磁盘上编写软件包,然后将其安装到临时 Space 中进行验证:

npx --yes busabase-cli@latest install <path-or-repo-url> --into-folder <scratch>

每次调用 npx 时都要保留 @latest:否则,npx 会运行它找到的任何 busabase-cli(全局安装的版本,或父目录中的 node_modules),而它可能是旧版 check/install/export。如果需要长时间反复调用,可在每个会话中运行一次 npm i -g busabase-cli@latest,然后直接调用 busabase-cli。

包优先流程只有在完成安装并打开后才算结束。 这不是形式主义。软件包可能满足所有静态规则——验证器显示通过,目录中也列出了它——但应用自身的配置流程仍可能出错,因为从软件包安装时读取的是 content/<base>/base.json,并不会验证应用自身用于配置的声明。确实发生过一次这样的缺陷:应用配置中的 Base slug 被遗漏,模板安装完全正常,但应用却无法创建自己的表。只有实际安装并打开应用才能发现这个问题。

两种路径都必须遵守本文档的其他所有要求。包优先并不意味着可以手写一个忽略运行时契约的 AirApp;工作区优先也不意味着可以发布一个从未编写过 SKILL.md 的模板。

2. 按模式路由

对于 maintain,请完整阅读并遵循 references/maintenance.md。从规范应用开始,并保留已批准变更集之外的所有内容。已批准的迭代可以创建、更新、移动或移除相关资源、架构、数据、文件和 UI。不要继续执行仅适用于创建流程的隔离工作区工作流。

对于 create,请继续执行步骤 3–9。所有隔离和蓝图审批规则仍为强制要求。

步骤 3–9 以工作区优先的方式编写。在包优先路线中,步骤相同,只需更改写入目标——操作规范保持不变,但 API 调用要等到验证安装时才会发生:

步骤工作区优先的做法包优先的替代做法
3–4 探索、蓝图相同——访谈和获批蓝图不会改变相同
5 创建结构在 Space 中创建 Folder/Bases/Views写入 busabase.json、content/_folder.json、content/<base>/base.json
6 搭建 AirApp搭建后部署在 content/<name>-app/ 中搭建(包含 _node.json;测试/锁文件使用 .busabaseignore)
7 验证本地检查 + UI 验收本地检查相同;UI 验收在步骤 9 的临时安装中进行
8 作为 ChangeRequest 部署提交 AirApp CR无——步骤 9 中的安装就是提议变更的方式
9 填充数据并验证填充 CR,运行合并后的 HEAD写入 records.ndjson(每个 Base ≤50 条),运行 busabase-cli index . --repo <owner/repo> -o templates.json,然后将 busabase-cli install 安装到临时 Space 中,合并、打开应用并读回数据

随着操作进展编写手册,不要等到最后:在这条路线中,SKILL.md 直接编写(无需从 Skill 节点导出),且只能提及 content/ 中实际包含的资源。

3. 探索产品

遵循 references/interview-and-blueprint.md 中以选项优先的交互约定。每次继续提出一个带字母选项的问题,直到确认以下事项:

  • 应用名称和一句话说明其目标;
  • 受众及其定期执行的工作;
  • 业务对象及其关系;
  • 原生制品:Views、Docs、文件、Whiteboards、Forms、Workflows 或 HTML;
  • 生命周期/状态值及重要日期;
  • 首屏、列表/详情视图、指标、筛选条件和搜索;
  • 每个 Base 的详情模式(ui.detail_modes):当记录本身就是一个工作空间(包含相关列表、长内容、共享链接)时使用 page;当用户需要浏览大量记录并修改一两个字段时使用 drawer;当视图是需要逐条处理记录的队列时使用 split;
  • 需要人工关注的状态;
  • 是否需要会生成 ChangeRequest 的小型操作;
  • 外部集成是否需要受信任的 Workflow/Agent,以及所需的 Vault 名称;
  • 品牌限制,或是否允许推断出简洁低调的运营风格。

不要让用户设计表格。将他们的描述转化为精简、连贯的模型;模型较大时发出提醒,并在用户确认较大范围后保留其选择。

4. 提交一份审批蓝图

创建机器可读的 blueprint.json,并向用户展示简洁的可读内容,其中包含:

  1. 用户故事。
  2. 页面和导航地图。
  3. 文件夹/资源关系图,包括 Bases、本机 Views、Docs、Drives 和可选节点。
  4. 字段、类型、必填值、选择项和 View 配置。
  5. 种子记录和初始产物大纲。 5a. 按节点列出的场景清单——用户可以要求 Agent 对每个节点执行哪些操作。 根据用户故事中反复出现的任务,以及你刚刚编写的 Actions 允许列表来推导;不要另创一套词汇。每个场景单独一行,措辞应贴近用户的表达方式(例如“记录一次客户拜访”),并按所属节点分组。这些内容将成为步骤 5 中每个节点的 agentPrompts,必须纳入审批,因为用户实际审批的问题是“我可以要求它做什么”。
  6. 操作流程能力矩阵、每屏数据预算和操作允许列表。
  7. Vault 要求的名称和可信执行方,不得包含机密值。
  8. 产品引导版本、必填字段、Busabase 完成资源、验证方式和解锁的能力;或说明为空契约并给出理由。
  9. 明确的排除项和风险。

运行:

node <skill-dir>/scripts/airapp-kit.mjs validate-blueprint --blueprint <path>/blueprint.json

请用户明确做出一项蓝图决策:批准、修改或停止。未经批准,不得创建远程结构。

5. 创建已批准的结构

获得批准后:

  1. 重新读取目标 Space/工作区,并检查是否存在 slug 冲突。
  2. 生成唯一 slug;绝不复用匹配的现有节点。
  3. 创建蓝图所表示的 Folder、Bases、字段、关系、本机 Views、Docs、Drives 和已批准的可选资源。 新建的 Base 默认附带一个 “Grid view”(包含每条记录和每个字段),除非跳过;并且 Base 会默认打开最左侧的 View。因此,如果蓝图为 Base 指定了自己的 Views,请使用 --skip-default-view(node_create 的 skipDefaultView,REST 的 defaultView: false)创建该 Base,然后按蓝图顺序创建 Views——Base 会打开第一个 View,之后的 export --template 也会原样导出这些 Views。如果蓝图未为 Base 指定 Views,则保留默认的 Grid view,并像记录其他 View 一样记录其 view_id。Base 必须始终保留一个 View。
  4. 省略 autoMerge:用户已批准此精确结构,因此凭据可以合并的内容现在都会合并。仅当你判断某个步骤有风险时,才明确传入 autoMerge: false(参见上文的范围规则)。
  5. 回读已实例化的资源,并在搭建前将每个 Folder/Node/Base/View/资源 ID 写入 blueprint.json。
  6. 每个节点创建后,立即根据已批准蓝图中的场景清单(步骤 4,第 5a 项)写入该节点的 agentPrompts——参见步骤 10,了解格式、CLI 调用方式和撰写标准。只有当有人打开节点后能看到可以请求执行的操作时,该节点才算“已创建”;如果拖到最后再写,就会基于你不再查看的应用记忆来编写提示词。

如果返回状态不是 materialized/merged,则停止并报告 CR,不得假装结构已存在。

6. 搭建并自定义 AirApp

解析最新 SDK 版本并搭建项目:

node <skill-dir>/scripts/airapp-kit.mjs scaffold \
  --blueprint <path>/blueprint.json \
  --output <chosen-source-dir>

对于委托式 App-in-Skill,<chosen-source-dir> 必须是 <skill-root>/app/。因此,生成的项目位于 <skill-root>/app/package.json,而浏览器文件位于 <skill-root>/app/app/。这种嵌套命名是有意为之:外层目录是该技能打包的项目,内层目录是 AirApp 静态文件树。搭建工具仍会拒绝覆盖非空目录;应通过维护模式更新现有的规范项目,而不是盲目替换。

搭建工具会拒绝尚未实例化的蓝图。它会复制经过测试的 Hono/vanilla 外壳,锁定解析出的 SDK 版本(0.99.0 或更高版本),将确切的 Folder/Node/Base/View/资源 ID 以及非机密的 Vault 要求写入部署配置,安装依赖,验证 SDK 客户端导出和浏览器 AirApp 辅助工具,创建浏览器捆绑文件(客户端使用 app/vendor/busabase-sdk.js,AirApp 辅助工具使用 busabase-airapp.js,连接门控使用 busabase-airapp-gate.js),并创建锁文件。这些捆绑文件属于经过审核的 AirApp 源码,因此 Nodepod 无需运行构建工具。自定义生成的领域 UI 和投影,使其符合获批的蓝图;生产模式下不要保留通用占位标签或演示实体。

将提供方分开:

  • 演示提供方:仅提供确定性的本地 UI 数据。
  • Busabase 提供方:仅通过 SDK,针对应用自身来源上的 /api/v1,访问获批的规范资源和待处理 CR 摘要。它通过 createAirAppRecords 读取和写入记录,只保留应用自身的规则(其程序允许列表,以及记录如何映射到 UI 行),绝不暴露 Vault,也不会悄悄回退到演示数据。

搭建工具还会将每个 change_request 类型的蓝图操作渲染为开放记录上的小型表单(ui.actions[].fields,仅限可编辑字段类型),并告知用户更改已保存还是正在等待审核。只读应用不会渲染这些表单。请扩展这一路径,而不是另写一套。它只会编辑开放记录:刻意不提供“新建记录”表单(参见 references/runtime-and-sdk.md § Optional Actions),因此,若获批的蓝图需要该功能,请自行添加。

本地 Hono 搭建模板还必须包含 references/runtime-and-sdk.md 中的 OAuth 路由和代理约定。生成的设置界面可以自定义标签和布局,但必须使用 createBusabaseAirAppLocalGateway(),且只能在环回文档来源上调用该约定;不得另行实现令牌存储,也不得将凭据发送给浏览器 JavaScript。在 AirApp 中,绝不要显示本地连接界面,也不要调用 /auth/status 或 /auth/start。

在 UI 中明确说明数据访问限额。每个 Base 使用其蓝图中的 read_limit(默认值为 50,允许范围为 1–50)和生成配置中的 readLimit;渲染时,待处理的 ChangeRequest 数量仍不得超过 20。每次续取只获取一个有界分页。如果存在 nextCursor,请显示 + 或等效标记,并提供“加载更多”,而不是在后台循环加载所有分页。搜索和筛选必须明确说明仅适用于已加载的行,或执行带防抖的服务器端筛选分页查询;不得悄悄扫描整个 Base。

7. 验证并获取 UI 验收

始终运行:

pnpm check                 # node runtime
node --check server.js     # node runtime
node scripts/check.mjs     # python runtime (no package.json, so no `pnpm check`)
python3 -m py_compile server.py   # python runtime

pnpm check 是搭建模板自身的质量门槛。当应用随软件包或模板一起发布时,还要对该软件包运行平台检查器;其 airapp 层会应用相同的约定(运行时检测、有界读取,以及对任何值不是字面量 true 的 autoMerge 执行 airapp/forced-review):

npx --yes busabase-cli@latest check <package-dir>

绑定到单个工作区 ID 的应用(workspace-first)不能作为模板发布,因此其中的 package/workspace-ids 检查结果是预期的;请查看 airapp 层。

Python AirApps

使用同一脚本并添加 --runtime python 即可创建一个:

node <skill-dir>/scripts/airapp-kit.mjs scaffold --blueprint <path>/blueprint.json \
  --output <chosen-source-dir> --runtime python

python 应用包含 airapp.json、server.py,以及与 Node 应用相同的 app/ 子目录,不包含 package.json(Busabase 会将其识别为 Node 应用)。它会自行声明命令,因为 Busabase 没有 npm 脚本可供读取:

{ "runtime": "python", "install": "…", "start": "python3 server.py" }

不要声明 port。如果不声明,宿主引擎会将一个空闲端口通过 PORT 传给应用(server.py 会读取该值),并从 listening on port N 这一行中找到该端口;固定使用 3000 会导致这台机器上的第二个 Python 应用,或任何其他已占用 3000 的程序因 Address already in use 而崩溃。

浏览器端需要与 Node 应用相同的三个 bundle。 app/index.html 和 app/js/ 会在加载时导入 app/vendor/busabase-sdk.js、busabase-airapp.js 和 busabase-airapp-gate.js。Python 应用没有 package.json 可用来运行 build:sdk,因此脚手架会在临时目录中运行模板自带的 build:sdk 脚本,然后将生成的文件复制到 app/vendor/。缺少这些文件时,应用会打开为空白页面,唯一线索是 gate bundle 返回 404;现在 node scripts/check.mjs 也会因缺少这些文件而失败。

Python AirApp 仅可托管运行,这一点不应设法绕过。 server.js 中的 /auth/* 路由和带凭证的 /api/v1 代理,来自 busabase-sdk 的本地 AirApp OAuth 网关。这些功能是为了让在 Busabase 之外运行的应用能够获取自己的凭证。我们不会在 Python 中重新实现这个网关:将认证流程移植到第二种语言,只会导致两种实现逐渐偏离,而发生偏离的部分就是安全边界。

在 Busabase 内部,没有任何功能缺失——浏览器的 /api/v1 调用与页面同源,并携带查看者的会话,因此无需经过网关。独立运行时,会显示连接 gate(与 Node 应用相同),而 server.py 会对 /auth/* 请求返回说明,而不是简单地返回 404。如果应用确实需要独立运行并使用自己的凭证,请用 node 编写。

然后按照 references/ui-and-validation.md 中选定的验证模式进行操作。

对于 target-first,不要启动 pnpm dev,也不要报告本地主机 URL。静态检查加上获批的蓝图,足以授权以考虑权限的方式编写 AirApp(步骤 8)。桌面端、手机端、交互、环境会话和真实数据验收,都要在步骤 9 的合并后 HEAD 上进行——在该 Run 完成之前,请在报告中说明 UI 验收仍待进行。

对于明确选择的 local-preview,运行 pnpm dev,使用 ?demo=1 打开实际的本地 URL,并在提交前验证桌面端和 390px 移动端布局。

在 local-preview 模式下,提交任何内容前都要使用真实数据进行验证。打开不带 ?demo=1 的本地 URL,选择 Busabase Cloud 或输入自定义的 Busabase 源站,然后完成浏览器 OAuth 流程。此交互路径不应要求 CLI 登录、设备码或粘贴 API 密钥。

非交互式 CI 和明确的操作员测试仍可使用环境引导:

BUSABASE_BASE_URL=http://localhost:15419 pnpm dev              # Desktop / OSS
BUSABASE_BASE_URL=https://busabase.com \
  BUSABASE_API_KEY=… BUSABASE_SPACE_ID=… pnpm dev              # Cloud

确认已配置的 Bases 返回真实记录。本地交互路径通过委托的 API 权限授权来认证用户;已部署的 AirApp 则使用查看者的环境会话,因此步骤 9 中的目标 Run 仍需验证这条不同的权限和嵌入路径。

在 local-preview 模式下,持续迭代,直到用户明确接受 UI 后再提交。在 target-first 模式下,每次目标 Run 后都要迭代;每个修订版都是独立的 AirApp ChangeRequest,并以考虑权限的方式编写。

8. 通过 ChangeRequest 部署 AirApp

在新 Folder 下创建一个新的 AirApp,其中包含完整且已验证的文件树,并设置 mergeMode: "replace"。省略 autoMerge 并读取结果:能够写入 Folder 的凭据会直接发布应用,权限较弱的凭据会生成待处理的 ChangeRequest;这两种结果都应如实报告。记录验证方式是 target-first 还是 local-preview。

报告发生了什么——合并时的 AirApp 节点 ID,等待人工处理时的 CR ID——以及主要安全事实:

  • 已部署的应用以当前查看用户的浏览器会话进行身份验证;
  • 未嵌入 API 密钥;
  • 列出的只读过程;
  • 列出的会生成 ChangeRequest 的过程(如果有);
  • 未直接修改规范数据。

如果已合并,直接进入第 9 步。如果因凭据无法合并而处于待处理状态,告知用户需要有人拥有该 Folder 的写入权限;除非用户明确要求处理该 CR,否则不要自行批准。种子记录不依赖 AirApp,因此在其等待期间仍要写入这些记录(第 9 步)——只有目标 Run 需要等到 AirApp 合并后才能运行。

9. 写入种子数据并验证真实数据

通过 ChangeRequest 写入 3 到 5 条真实感强的记录,并像其他操作一样遵循权限要求。遵守关系依赖:在子记录关系中使用规范 ID 前,先读回已合并的父记录,除非实时 API 明确支持临时记录引用。

AirApp 和种子记录都已合并后(由你写入,或由人工合并排队等待的记录):

  1. 读回规范记录。
  2. 请用户在目标 Busabase 中运行已合并的 AirApp。
  3. 验证所选部署路径、Base 发现、数据非空、空状态、浏览器控制台、桌面布局和 390px 手机布局。在 target-first 模式下,这是必需的首个 UI 验收关卡,而不是本地验收后的后续步骤。
  4. 分别诊断 bridge、session 和 space/schema 故障。

不支持运行处于待处理状态的 AirApp CR。实际运行合并后的 HEAD 之前,绝不要声称已完成目标环境验证。

10. 手册与提示词——结构和最终检查

这些内容应在整个运行过程中编写,而不是留到这里:随着应用逐步成形,编写 skill 节点;创建每个节点时,也要编写该节点的提示词(第 5 步第 6 项)。本步骤用于定义它们的结构,并在宣布运行完成前检查是否有遗漏。

资源只是安装内容的一半。另一半是非专家如何使用它们,内容分布在两个位置:

Folder 的 skill 节点。 在 Folder 中创建一个 skill 节点,以应用命名——说明 Bases 的含义、每个字段的用途、工作流,以及应用绝不可执行的操作。采用 package-first 方式时,这是安装程序提取并放入该节点的根目录 SKILL.md;采用 workspace-first 方式时,则直接创建该节点。$busabase 会告知每个 Agent 在向该 Folder 写入内容前先阅读它,因此这是让应用能够自我驱动的唯一文档。一个 Folder 可以包含多个 skill;每个节点的名称都应与其 skill 的 frontmatter name 相同。

每个节点上的场景提示词。 这些并非在此处临时编写,而是用户已在蓝图中批准的逐节点场景列表(第 4 步第 5a 项),并需完整写出。每个 Base、Doc、AirApp 和 Drive 都应包含适用于自身的提示词。

场景的来源。 蓝图中的用户故事确定一个受众和一项反复执行的工作;Actions allowlist 列出应用可以执行的操作。场景是两者的交集:该受众经常使用此节点执行的一项工作。例如,作为销售代表,我想为客户记录拜访笔记 加上 Visits Base ⇒“记录一次客户拜访”“展示本季度我们与该客户讨论的所有内容”。如果某个候选提示词无法追溯到用户故事,要么它不属于此应用,要么用户故事不完整——应修正用户故事,而不是提示词列表。 标准。 当提示词用用户自己的措辞说出其需求,并让 Agent 自行推断操作时,它才值得保留。以下两种误区都很容易陷入:

❌✅原因
“在 Visits 中创建记录”“记录一次客户拜访”第一种只是贴上 Base 名称的 API 调用;节点类型自带的提示词已经涵盖了它。
“将状态字段更新为 closed-won”“将这笔交易标记为已赢单,并记录原因”第一种告诉 Agent 要写入哪一列;第二种告诉它发生了什么,而这正是技能工作流的用途。
每个字段一个提示词每个节点 2–5 个,每个常见任务一个如果提示词列表长得和架构一样,那它就是架构,而不是值得提出的事项菜单。

每个节点写 2–5 个。少于两个通常意味着该节点没有自己的任务,提示词应放到父节点上;多于五个通常意味着混入了字段级操作。

每个正文开头都要点明技能:

Read the `crm-visits` skill in this folder and follow its workflow, then add a visit record with
today's date, the contact I name, and a one-line summary.

只写任务。Busabase 会在每个提示词开头加入点明其节点的句子—— Target: the Busabase Base "Visits" (nodeId: nod_…), in space "Acme" (spaceId: spc_…).——与内置提示词开头的句子相同,因此不要写 {target}。仍包含它的旧版正文会继续生效:单独一行的 {target} 会被删除;在句子中的 {target} 会被识别为节点名称。

使用 CLI 编写,CLI 会在发送前进行验证:

npx --yes busabase-cli@latest nodes set-agent-prompts --node-id <nodeId> --file prompts.json

prompts.json 是由 { key, label, body, intent? } 组成的列表。label 是用户从列表中选择的内容(≤80 个字符);body 是 Agent 接收的任务,Busabase 会在其前面添加节点/空间目标行;intent 为 read-only 或 change(默认为 change)。 限制:每个节点最多 50 个提示词,每种区域设置的正文最多 8 KiB。如果应用支持多语言,label 和 body 都可以使用 i18n 对象({ "en": "…", "zh-CN": "…" })。

优先采用打包方式:将同一列表写入每个节点的 sidecar(_node.json、_folder.json、base.json、file 节点的 .node.json 或 Doc 的 frontmatter)中的 agentPrompts,使其在导出 → 安装后仍能保留。busabase-cli check 会对没有技能节点的包以及没有提示词的节点发出警告。

最后检查。 在确认完成标准之前,列出 Folder 的所有节点,并逐一确认每个节点都有提示词,且这些提示词能让人而不是 API 识别为自己的任务。优先采用打包方式,运行 busabase-cli check,并将 template/node-without-prompts 警告视为待办清单,而不是杂音。如果某个节点在最后检查时仍然空空如也,说明创建时漏掉了定义中的第 5 步后半部分;请返回并根据节点的实际情况编写提示词。

完成标准

对于 create,仅当以下条件全部满足时才算完成:

  • 已批准的文件夹、Bases、视图、制品和可选资源已存在于所选的 Cloud Space 或桌面工作区中;
  • AirApp 源代码通过检查,且已通过合并后的 Busabase HEAD 中的目标优先验收,或已明确选择本地预览验收并随后执行目标 Run;
  • AirApp 写入已成功完成——要么直接合并,要么作为凭证无权合并的 ChangeRequest 留存;并且结果已经回读确认,而非仅凭假设;
  • 已回读确认规范种子记录;
  • 文件夹中有一个以应用名称命名的 skill 节点,且本次运行创建的每个节点都带有情景 Agent 提示词,其正文中写明该技能,并且每个提示词都可追溯到已批准蓝图中的一个情景(第 4–5 步;结构见第 10 步);
  • 已合并的 AirApp 能在目标环境中针对真实数据运行;
  • 运行时配置包含精确的、已实例化的文件夹/节点/Base/视图/资源 ID 及非机密的 Vault 要求,并且每个交互式读取路径都有界限、经过适当筛选且明确分页;
  • 文件、日志、截图或聊天中均未出现机密信息;
  • 本地交互式身份验证使用 PKCE 和位于 ~/.busabase/airapps 下、仅所有者可访问的每 AirApp 注册;无需 CLI 登录,也无需在浏览器中显示凭证;
  • 报告实际节点 URL、CR ID、源目录、SDK 版本和剩余限制。
  • 如果由 App-in-Skill 创建者委派,则委派方技能的 AirApp 项目根目录(<skill-root>/content/<name>-app/;尚未迁移的技能使用 <skill-root>/app/)仍是规范本地项目,继续支持 pnpm dev,但默认不启动,并且已合并的 AirApp 可追溯至同一份经过审查的源代码树。

对于 package-first create 运行,还需满足:软件包安装到临时 Space 时没有警告,AirApp 能在其中打开并读取真实数据,SKILL.md 只列出软件包实际附带的资源,并且在临时 Space 中打开已安装节点时,显示的是其编写的提示词(而非节点类型的默认提示词)。通过验证器只是前置条件,绝非完成标志。

对于 maintain,请使用 references/maintenance.md 中单独规定的完成标准。

将已完成的应用发布为可安装模板

仅在用户提出要求时执行。一个工作区中的可运行应用就是交付成果;模板是更进一步的步骤,意味着“任何人都应该能够安装它”。

不要手动编写软件包布局——导出刚构建并验证过的应用,这样发布的模板就是实际运行过的内容,而不是对它的另一份描述:

npx --yes busabase-cli@latest export <folder-slug> -o ./<name> --template

这会写入 Template Center 读取的布局:将文件夹的 Skill 节点提升到软件包根目录,作为 SKILL.md;生成包含目录元数据的 busabase.json;并将资源放入 content/。Base slug 会按应用声明的形式还原,而不是工作区安装时使用的带前缀形式。如果文件夹还没有 Skill 节点,则会根据其结构生成一份 SKILL.md 草稿——其中会故意保留大量 TODO,因为 Agent 会依据该文件的内容采取行动,对表格含义作出看似合理的猜测,还不如明确留空。请与用户一起补全这些内容。

打开拉取请求之前,请先检查:

npx --yes busabase-cli@latest check ./<name> --strict                                       # the contract
npx --yes busabase-cli@latest index . --repo busabase/templates -o templates.json --check   # the catalog
cd templates/<name> && node scripts/sync-content.mjs --check                   # only if it has one

check 会从目录中读取上述规则,并分别报告每个适用层——package、skill、template、airapp。不适用的层会显示 –,绝不会显示 ✓。这是静态检查:不会安装任何内容,也不会运行模板自身的代码,因此在构建过程中应反复运行,而不只是提交前运行。错误会导致用户无法安装;警告则是值得在审查中说明理由的默认设置,使用 --strict 时,警告也会导致检查失败。将其指向仓库根目录可扫描所有模板;开发应用时可使用 --only airapp;在 CI 中可使用 --json。

第二个命令回答的是另一个问题——仓库的目录文件是否为最新;两者互不替代。

模板通过拉取请求提交到 https://github.com/busabase/templates。该仓库的 AGENTS.md 载有其自身约定(模板应放置的位置、生成的内容以及不符合要求的情形)。打开 PR 之前请先阅读;不要在这里复述或覆盖其中的约定。

停止条件

出现以下情况时,请停止并询问如何处理:

  • 目标环境或 Space 不明确;
  • 无法进行身份验证;
  • 在 create 中,用户尚未批准蓝图;
  • 请求的操作会绕过 ChangeRequests;
  • 实时 API 行为与本 Skill 冲突;
  • SDK 缺少 createBusabaseClient,或未通过 Nodepod 验证;
  • 合并后无法验证 Cloud/Desktop Run;
  • 在 maintain 中,已部署的树是构建输出,其中没有生成它的源代码,并且在任何地方都找不到源代码——请参阅 references/maintenance.md 中的“此处到底有没有源代码?”。

评论

支持 Markdown