跳到主要内容

上线前 checklist

什么时候读:技能写完、交付前。逐条打勾,把未满足的列给用户。不跳条。 只核对适用的段:不碰数据表就跳过「数据表」段,不调别的技能就跳过「技能间调用」段。

形态与入口​

  • 入口是 async def execute(input_data, runtime_context)(名字、参数名、async 三项照抄;否则 create_skill / edit_skill 拒装),第二参数无默认值
  • frontmatter name 匹配 ^[a-z0-9][a-z0-9_-]*$ 且与目录名一致
  • 碰数据库 / 用 call_skill → async def;直连从 db_factory 现开现还,不读 ctx["db"]
  • 子进程型:日志走 stderr,stdout 只打最终 JSON;业务失败退出码 0 + success:false
  • 模块内确有入口函数(漏了静默降级成文档型)
  • 进程内 handler 里没有 argparse + __main__(会被判成 CLI)

输入​

  • schema.json 的 required 与实际必填一致,description 写清取值范围
  • properties 值都是对象,没有裸字符串
  • 文件参数用约定字段名,直接用平台给的绝对路径,不再拼目录
  • 不从 input_data 读身份类字段
  • 动作型:action / 参数键别名归一,别名表值集合 ⊆ 规范 action 集合(加断言),归一后回写 action_note
  • 动作型:无 action 返回 need_param=action + 清单,不按入参形状默认成写动作
  • 动作型:入口先拆 payload / input / args 包装层
  • 写动作的确认只认用户原话 / 「确认」前缀,预演返回回显收到的参数
  • 数组/对象参数过一遍「可能是 JSON 字符串」掰形

上下文​

  • 固定词表的键直接判空,未写多余 .get(k, "")
  • actor_is_admin / 身份键为空的分支已处理,未把空值当最低档位放行
  • triggered_at 当 float 用;attachments 读 type(att_type 是过渡别名);部门判断优先用 actor_department_id
  • 不靠 channel 判断调用来源(页面线会被覆盖);team_role 缺失按无权限处理(页面线不注入)
  • org_id 缺失时返回 error_type=config + non_retriable=true
  • 工号取 actor_emp_no(不读 emp_no);行级过滤依赖它的技能在真库验过「非管理员能看到自己的行」,经 call_skill 路径也验过
  • 部门路径匹配带首尾斜杠;判本级用末段

配置​

  • 密钥按四层顺序取(skill_configs[skill] → skill_configs → skill_args → ctx → env),未要求模型传密钥
  • 文档中的凭证只用 $VAR 引用,无「打印出来确认」步骤
  • 非凭证常量名不含 key/token/secret/password/credential/auth 子串;自测按子串扫
  • 需要配置:顶层 env: 结构化声明(控制台表单读)+ metadata.openclaw.requires.env / bins(执行前校验读),两处都写
  • 不需要配置:写 env: [],避免正文嗅探冒出假配置项
  • 技能目录里没有含密钥 / 内部数据的 .json .js .html 等文件(/ui/asset 免鉴权可下载,无面板也一样)

输出​

  • 失败必带 error;可自纠的标 recoverable 并给改法
  • non_retriable 只用于部署级问题
  • 部分成功显式标注成功/失败条数
  • 每条错误信息过「照着它排查会走到哪」;数字能对账
  • 产物返回 filename / local_path,未自拼下载链接
  • 大结果放可卸载字段,关键少量字段放顶层
  • 直显块:display_md 只会追加(display_only 现行对话线未实现);不许改写的文本另在角色提示词里明令不复述
  • 非幂等写操作不把 Timeout / Connection / OSError / DB 连接类异常裸抛(平台会整次重跑最多 3 次)
  • 中间文件放工作区子目录,成功即删,失败保留并点名
  • 给用户看的「下一步」不用指令式措辞,标注 for_user

数据库直连(自己读写库时;见 spec §7A / code-facts §3.7)​

  • 进程内 async,库访问收进单一 _db(),每次从 db_factory 现开现还,没读 ctx["db"]
  • 写操作 commit;跨语句原子才用一条会话(那时才手动 rollback),否则每条各自短会话
  • 两次 DB 操作之间的慢 I/O(HTTP/调模型)期间手里无连接
  • 表名全限定 + 标识符加引号;不裸建表;upsert 前查 pg_constraint 不假设约束存在
  • _db 做成唯一 seam 可 monkeypatch 离线自测;真库端到端验过一次
  • 子进程 / 其它语言不直连;需落库拆成两个技能(落库那步进程内 async)

面板(带 ui:,或根目录有 panel.html / ui.html / index.html 才核)​

  • 本地面板:ui: 是技能目录内的 .html 相对路径且文件存在,建议放 ui/ 子目录;不想要面板的技能根目录没有 panel.html / ui.html / index.html
  • 本地面板:schema 写了 properties.action.enum,面板调的每个动作都在其中(网关只认它,不认 x-actions)
  • 本地面板:enum 里的写 / 删 / 结构类动作在 handler 内自鉴权(actor_emp_no / actor_is_admin / 业务条件),不依赖网关
  • 本地面板:ui.html 只用 src= / href= 相对路径;无 /api、/xxx 站点根路径、http(s) 绝对地址;没有 CSS url() 与 JS 相对 import
  • 本地面板:app.js 完整 ready/init/invoke/invoke_result 握手,频道 skill_panel,ready 必发
  • 本地面板:无 localStorage/sessionStorage;无 fetch 直连后端;动作返回字段名与面板 res.data.xxx 对得上
  • 本地面板:入口目录树里没有敏感文件(静态资源免鉴权公开)
  • 外部面板:ui: 是 http(s) URL;未生成本地面板文件
  • 外部面板:技能说明提醒了对接方三件事(frame-ancestors 放行 + 接 panel_token + 用 PEM 公钥验签,aud = 面板 URL 的 host[:port]、iss 默认 myinc-platform)

数据表​

  • 所有表由 create_table 建,没有一列是 SQL 补的;没用 PRIMARY KEY / BIGSERIAL / JSONB / 自定义 id、created_at
  • 初始化幂等
  • 表名全限定、写操作提交、保留字加引号、绑定参数不写 :name::type
  • SQL 通道:JSON 存 text;字段名符合标识符规则(禁 %);字符串字面量内无 :紧跟字母/数字
  • 不存在的表先查存在性;每组数据独立 try/except + rollback
  • 批量按 1 / ≤100 / 文件导入 三档选路
  • 真库端到端验过一次
  • 技能名候选列表探测(datatable 在前、nocodb 兜底),结果进环境自检
  • 需要 own 范围的表,对应角色每条线都确认注入 allow_sql=False;未注入则不配 own
  • 链/定时任务里的删除,单次命中 ≤10 行
  • 结构类操作(建表/改字段/删表)只给 owner/admin:技能线 handler 鉴权尚未恢复,需要时技能自己先判 team_role
  • 字段 type 只用枚举里的 15 个(无 JSON / 高精度数字)

文档​

  • SKILL.md < 8000 字符,细节拆 references/ 并写明何时读
  • frontmatter 是合法 YAML:值里出现「英文冒号+空格」的整句加引号(否则平台退回逐行解析,嵌套块全丢)
  • category 是 13 个合法值之一;category / cost-tier / async / env 写在顶层,不塞进 metadata
  • 文档型:任何位置都没有无意放置的 openapi.* / endpoints_whitelist.*(会被判成 API 型)
  • description 说清「什么时候该调它」,带触发词
  • 未 import 其它技能
  • 动作型的 SKILL.md 明写「action 必须传中文原词」+ 三个调用示例;帮助表左列是触发场景
  • 角色提示词(若有):明令不复述工具返回值;不许改的文本做成工具动作;可变配置先查再答;positive-examples / negative-examples 齐全

技能间调用​

  • 调 call_skill 前已 commit
  • 收件人取自业务数据,未用 actor_* 当收件人
  • 判失败看 ok / sent,未假定调用一定成功
  • 未对 async 技能使用 call_skill
  • 通知失败不回滚主业务

纪律​

  • 版本号每次发布 bump
  • 有一个不经平台、直接读磁盘的部署核对脚本
  • 每修一个 bug 留一条回归用例