{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://openclaw.local/skill-template/skill-actions.schema.json", "title": "SkillActionManifest", "description": "匠厂 skill-template 对新技能的严格 Action manifest 规范(schemaVersion 1)。additionalProperties=false 表示模板推荐契约;宿主运行时可能为兼容历史 manifest 接受部分缺省字段,但新技能不应依赖缺省行为。含可选 hostEffects/steps(匠厂宿主 ≥2.8.5)与可选 hoverHint(数据管理工具栏悬停,需宿主已支持该字段)。", "type": "object", "required": ["schemaVersion", "skill", "actions"], "additionalProperties": false, "properties": { "schemaVersion": { "type": "integer", "const": 1 }, "skill": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$", "description": "与 SKILL.md metadata.openclaw.slug 一致" }, "actions": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/action" }, "description": "Action 列表。同一 placement(toolbar/row/batch)下,宿主按本数组中匹配项的相对顺序展示。toolbar/batch:表顶栏全部直接展示(无「更多操作」溢出)。row:行级入口,宿主可呈现为操作列、行右键和/或行内「⋯」(同一批 Action、同一顺序);不在本字段配置排序、截断或菜单树。调整顺序即调整数组先后。无独立 sortOrder 字段。宿主内置刷新/导出/查看等不参与本顺序。表顶栏宽时左右横排,窄时左右分栏且栏内竖排。" }, "policy": { "$ref": "#/$defs/policyDeclaration", "description": "可选。启用 Data Policy(L1/L2)。缺省或不 enabled = L0,宿主不拉 Snapshot。详见 references/POLICY.md。" }, "cellPresentation": { "$ref": "#/$defs/cellPresentationDeclaration", "description": "可选。启用数据管理呈现(P1:格子/行/列/区域)。缺省或不 enabled = P0,宿主不读标色。详见 references/CELL_PRESENTATION.md。" } }, "$defs": { "cellPresentationDeclaration": { "type": "object", "required": ["enabled"], "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "仅 true 启用;false 等同 P0。" } } }, "policyDeclaration": { "type": "object", "required": ["enabled"], "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "仅 true 启用;false 等同 L0。" }, "entrypoint": { "$ref": "#/$defs/entrypoint", "description": "enabled=true 时必填。推荐 command=policy,args 可含 {{table}}/{{skill}}/{{userId}}。" }, "appliesTo": { "type": "array", "items": { "type": "string", "enum": ["data-management"] }, "description": "缺省 [\"data-management\"]。本期宿主只实现 data-management。" } }, "allOf": [ { "if": { "properties": { "enabled": { "const": true } }, "required": ["enabled"] }, "then": { "required": ["entrypoint"] } } ] }, "placement": { "type": "string", "enum": ["toolbar", "row", "batch", "cron", "agent", "skill-detail"], "description": "稳定支持 toolbar/row/batch/cron/agent/skill-detail(对齐匠厂宿主)。row=行级入口(操作列/行右键/⋯ 等由宿主呈现,无独立 row-context-menu placement)。placements 与 executionProfile 正交,不做条件限制。" }, "mutationKind": { "type": "string", "enum": ["create", "update", "delete", "import"], "description": "可选。接管数据管理默认按钮:create=新增、update=编辑、delete=删除、import=导入。须配合非空 bind.tables;无配置时宿主仍直写已注册数据源(默认 SQLite)。import 时 UI 仍用宿主「导入数据」面板,确认后调用本 Action 写库。" }, "scalarArg": { "type": ["string", "number", "boolean"] }, "visibleWhenRule": { "description": "条件显隐规则。支持 {field,equals} / {field,in:[...]},或单键简写 {status:\"approved\"} / {status:[\"a\",\"b\"]}。", "oneOf": [ { "type": "object", "required": ["field", "equals"], "additionalProperties": false, "properties": { "field": { "type": "string", "minLength": 1 }, "equals": { "type": ["string", "number", "boolean"] } } }, { "type": "object", "required": ["field", "in"], "additionalProperties": false, "properties": { "field": { "type": "string", "minLength": 1 }, "in": { "type": "array", "minItems": 1, "items": { "type": ["string", "number", "boolean"] } } } }, { "type": "object", "minProperties": 1, "maxProperties": 1, "additionalProperties": { "oneOf": [ { "type": ["string", "number", "boolean"] }, { "type": "array", "minItems": 1, "items": { "type": ["string", "number", "boolean"] } } ] } } ] }, "inputProperty": { "type": "object", "required": ["type"], "additionalProperties": true, "properties": { "type": { "type": "string", "enum": ["string", "number", "boolean", "object"], "description": "模板 Phase 1 仅推荐 string/number/boolean;根 inputSchema.type=object 的 properties 使用基础标量类型" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": {}, "enum": { "type": "array", "minItems": 1, "description": "静态枚举取值(提交/存库用)。展示中文时配 enumNames,或绑列复用 options_json;勿用 Lookup 冒充固定小枚举。" }, "enumNames": { "type": "array", "minItems": 1, "description": "可选。与 enum 一一对应的展示文案(JSON Schema / OpenAPI 风格)。缺项或空串时宿主回退为对应 enum 原文。有对应表列时优先绑列复用 options_json(见 ACTIONS.md「静态枚举 label」)。" }, "sensitive": { "type": "boolean" }, "readOnly": { "type": "boolean", "description": "只读。有「已选择」且字段来自 inputMapping(或约定 id 字段)时,宿主 form 默认不渲染该控件,预设值仍提交;无摘要时只读展示。勿用 visibleWhen 代替(visibleWhen 隐藏不提交)。" }, "revealInForm": { "type": "boolean", "description": "可选逃生阀。true 时即使弹层有「已选择」摘要,也仍渲染该 readOnly 字段。不改变提交 payload。省略=映射只读字段在有摘要时默认折叠。" }, "column": { "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9_]*$", "description": "可选。绑定业务表物理列名;Action 弹窗(toolbar/batch)与 replaces create/update 抽屉可复用该列的中文名与 options(静态枚举 options_json 数组,或已解析的 lookup)。" }, "display_type": { "type": "string", "enum": ["textarea", "year", "year_month", "month", "date", "datetime_unix_seconds", "url", "email", "lookup", "directory", "file"], "description": "可选。表单控件提示;与 format 二选一即可。year/year_month=年或年月选择器(YYYY / YYYY-MM;month 为 year_month 别名)。lookup=关联下拉(须配 lookup 对象或绑到已有 lookup 列)。file/directory=本地路径选择(可选 pathRoot 指定起始目录,见 ACTIONS.md)。须与 CRUD display_type 语义对齐。" }, "format": { "type": "string", "enum": ["textarea", "year", "year_month", "month", "date", "datetime_unix_seconds", "url", "email", "lookup", "directory", "file"], "description": "可选。display_type 别名,语义相同。" }, "pathRoot": { "type": "string", "minLength": 1, "description": "可选。仅对 display_type/format 为 file 或 directory 有意义:原生选文件/目录对话框的起始文件夹,相对当前技能数据根(如 input/库存数据)。省略则宿主默认打开 {skill_data}/input。禁止绝对路径、盘符与 ..。Agent/CLI 忽略。见 references/ACTIONS.md「本地路径选择与 pathRoot」。" }, "lookup": { "$ref": "#/$defs/lookupConfig", "description": "可选。Action 内联 Lookup:local_sql(同库表)/ skill_cli(兄弟技能 CLI JSON)/ external_api(预留)。打开表单时由宿主解析。推荐同时设 display_type=lookup。见 ACTIONS.md「跨表引用:Lookup」。" }, "visibleWhen": { "description": "可选。表单字段条件显隐。宿主在数据管理/定时任务参数表单中:规则不满足则隐藏该字段、提交时省略、且不校验 required。Agent/CLI 无 UI 时同样按当前 input 求值后剥离隐藏字段。≠ bind.visibleWhen(行菜单),≠ Policy L3。", "allOf": [{ "$ref": "#/$defs/visibleWhenRule" }] } } }, "lookupConfig": { "type": "object", "additionalProperties": false, "properties": { "source": { "type": "string", "enum": ["local_sql", "skill_cli", "external_api"], "description": "可选。显式数据源;省略时:有 ref_table→local_sql,有 skill→skill_cli,有 url→external_api。" }, "lookup_source": { "type": "string", "enum": ["local_sql", "skill_cli", "external_api"], "description": "可选。source 别名。" }, "ref_table": { "type": "string", "minLength": 1, "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", "description": "local_sql:同库被引用表名" }, "value_column": { "type": "string", "minLength": 1, "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", "description": "提交值列;local_sql 必填;skill_cli/external_api 默认可为 id" }, "label_column": { "type": "string", "minLength": 1, "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", "description": "主文案列;local_sql 必填;skill_cli 默认可为 display_label" }, "extra_column": { "type": "string", "minLength": 1, "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", "description": "可选。第三展示列;有值时宿主拼成「value · label(extra)」" }, "filter_column": { "type": "string", "minLength": 1, "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", "description": "可选。local_sql 等值过滤列" }, "filter_value": { "type": ["string", "number", "boolean", "null"], "description": "可选。与 filter_column 配对的等值" }, "skill": { "type": "string", "minLength": 1, "description": "skill_cli:兄弟/依赖技能 slug" }, "skill_slug": { "type": "string", "minLength": 1, "description": "skill_cli:skill 别名" }, "command": { "type": "string", "minLength": 1, "description": "skill_cli:CLI 子命令(argv[0])" }, "cli_command": { "type": "string", "minLength": 1, "description": "skill_cli:command 别名" }, "args": { "oneOf": [ { "type": "array", "items": { "type": "string" } }, { "type": "string" } ], "description": "skill_cli:追加 argv;数组或逗号分隔串" }, "items_path": { "type": "string", "minLength": 1, "description": "skill_cli / external_api:stdout JSON 内选项数组点路径,默认 items" }, "url": { "type": "string", "minLength": 1, "description": "external_api(预留):HTTP URL" }, "endpoint": { "type": "string", "minLength": 1, "description": "external_api:url 别名" }, "method": { "type": "string", "enum": ["GET", "POST"], "description": "external_api:HTTP 方法,默认 GET" }, "multiple": { "type": "boolean", "description": "可选。true=多选 Lookup(存/提交 TEXT 逗号分隔 id);省略或 false=单选(默认)。" }, "presentation": { "type": "string", "enum": ["select", "paged_table"], "description": "可选。省略或 select=下拉/勾选/Chip。paged_table=分页勾选小表(编号|文案,可翻页、可本页全选)。仍是 lookup,不要新造 display_type。" }, "page_size": { "type": "integer", "minimum": 1, "maximum": 100, "description": "可选。presentation=paged_table 时每页条数,默认 10,最大 100。" } }, "oneOf": [ { "required": ["ref_table", "value_column", "label_column"], "description": "local_sql(同库表)" }, { "anyOf": [ { "required": ["skill", "command"] }, { "required": ["skill", "cli_command"] }, { "required": ["skill_slug", "command"] }, { "required": ["skill_slug", "cli_command"] } ], "description": "skill_cli(兄弟技能 CLI JSON)" }, { "anyOf": [ { "required": ["url"] }, { "required": ["endpoint"] } ], "description": "external_api(预留)" } ], "description": "Action Lookup:local_sql / skill_cli / external_api。展示:value · label;有 extra 时 value · label(extra)。宿主亦接受 camelCase。列 Lookup 仅 local_sql,见 SCHEMA.md。" }, "inputSchema": { "type": "object", "required": ["type", "properties"], "additionalProperties": false, "properties": { "type": { "const": "object" }, "required": { "type": "array", "items": { "type": "string" } }, "properties": { "type": "object", "additionalProperties": { "$ref": "#/$defs/inputProperty" } } } }, "entrypoint": { "type": "object", "required": ["type", "command", "args"], "additionalProperties": false, "properties": { "type": { "const": "cli" }, "command": { "type": "string", "minLength": 1 }, "args": { "type": "array", "items": { "$ref": "#/$defs/scalarArg" }, "description": "仅允许 string/number/boolean 标量数组" } } }, "confirmation": { "type": "object", "required": ["message"], "additionalProperties": false, "properties": { "message": { "type": "string", "minLength": 1 } } }, "bind": { "type": "object", "required": ["tables"], "additionalProperties": false, "properties": { "tables": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9_]*$", "description": "英文 snake_case 业务表名;须真实存在于技能 SQLite / _jiangchang_tables" }, "description": "数据管理表级绑定:决定 toolbar/row/batch Action 出现在哪些表。宿主兼容旧技能时,缺失 bind 可视为全表展示;新技能 toolbar Action 必须显式声明。" }, "inputMapping": { "type": "object", "additionalProperties": { "type": "string", "minLength": 1 }, "description": "可选。将 $row.$pk / $row.col / $selection.ids 等映射到 inputSchema 字段名,供 row/batch 预填。" }, "columnMapping": { "type": "object", "additionalProperties": { "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9_]*$" }, "description": "可选。将 inputSchema 属性名映射到业务表物理列名,供 Action 弹窗与 replaces create/update 抽屉复用列 displayName / lookup options。" }, "labelColumn": { "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9_]*$", "description": "可选。数据管理 Action 确认/表单弹层「已选择」摘要用的可读标签列(#id + 标签)。仅影响展示,不改变提交 payload。省略时宿主按常见列名启发(title/name 等),再不行只显示编号。" }, "selectionMode": { "type": "string", "enum": ["required", "none", "optional"], "description": "可选。数据管理勾选如何驱动本 Action:required=必须有勾选(无勾选禁用);none=忽略表勾选(不出现假「已选择」);optional=有勾选走 $selection.ids,无勾选走 pickCount/maxLeads 等空选数量字段。省略时宿主推断:有 $selection.ids 或 batch → required,否则 → none。与 placements/executionProfile 正交。" }, "visibleWhen": { "description": "可选。placements 含 row 时:按当前行原始列值决定是否出现在行菜单/行按钮(宿主已支持)。形状同表单字段 visibleWhen。省略=始终显示。≠ inputSchema 字段 visibleWhen,≠ Policy L3 预留。见 ACTIONS.md「行菜单显隐」。", "allOf": [{ "$ref": "#/$defs/visibleWhenRule" }] } }, "description": "表级绑定;toolbar 必填。可选 inputMapping / columnMapping / labelColumn / selectionMode / visibleWhen。concurrency/locks 勿写入。" }, "hostEffectId": { "type": "string", "enum": ["reloadTable", "refreshCatalog", "clearSelection"], "description": "数据管理 UI 副作用(匠厂宿主 ≥2.8.5)。reloadTable=刷新当前表(含 Data Policy);refreshCatalog=刷新技能目录;clearSelection=清空多选。" }, "hostEffects": { "type": "object", "additionalProperties": false, "properties": { "onSuccess": { "type": "array", "items": { "$ref": "#/$defs/hostEffectId" }, "uniqueItems": true, "description": "sync 退出 0,或 async 任务已被任务中心接收时触发(不是 Job 跑完)。" }, "onFailure": { "type": "array", "items": { "$ref": "#/$defs/hostEffectId" }, "uniqueItems": true, "description": "sync 失败,或 async 启动被拒时触发。" } }, "description": "可选。UI 副作用简写;省略则宿主不额外改 UI。与 placements/executionProfile/interaction 正交;cron/agent 忽略。新技能有编排需求时优先用 steps。" }, "actionStep": { "type": "object", "required": ["when", "do"], "additionalProperties": false, "properties": { "when": { "type": "string", "enum": ["before", "afterSuccess", "afterFailure"], "description": "before=CLI 前;afterSuccess/afterFailure 时机同 hostEffects.onSuccess/onFailure。" }, "do": { "type": "string", "enum": ["deleteByFk", "deleteRows", "reloadTable", "refreshCatalog", "clearSelection"], "description": "闭环操作或 UI 效果。deleteByFk/deleteRows 须配合 table(及 fk)。" }, "table": { "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9_]*$", "description": "deleteByFk / deleteRows 目标表(snake_case)。" }, "fk": { "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9_]*$", "description": "deleteByFk 时子表外键列名。" } }, "allOf": [ { "if": { "properties": { "do": { "const": "deleteByFk" } }, "required": ["do"] }, "then": { "required": ["table", "fk"] } }, { "if": { "properties": { "do": { "const": "deleteRows" } }, "required": ["do"] }, "then": { "required": ["table"] } } ] }, "action": { "type": "object", "required": ["id", "label", "description", "placements", "entrypoint", "executionProfile"], "additionalProperties": false, "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "minLength": 1 }, "label": { "type": "string", "minLength": 1 }, "description": { "type": "string", "minLength": 1 }, "hoverHint": { "type": "string", "minLength": 1, "description": "可选。数据管理工具栏悬停文案。与 description / confirmation.message 独立;省略则不显示悬停,不回退。需宿主已支持该字段。当前实现为顶栏技能按钮,不含宿主内置删除/刷新/新增/导入/导出。" }, "placements": { "type": "array", "minItems": 0, "items": { "$ref": "#/$defs/placement" }, "description": "决定 Action 出现在哪里;与 executionProfile 正交。仅 replaces 接管默认 CRUD 时可为空数组。数据管理 toolbar/row/batch 的顺序由顶层 actions 数组相对顺序决定。表顶栏 toolbar/batch 全部直接展示(无溢出菜单);row 为行级入口(操作列/行右键/⋯),不在本字段配置排序、截断或菜单树。" }, "replaces": { "$ref": "#/$defs/mutationKind" }, "entrypoint": { "$ref": "#/$defs/entrypoint" }, "inputSchema": { "$ref": "#/$defs/inputSchema" }, "confirmation": { "$ref": "#/$defs/confirmation" }, "executionProfile": { "type": "string", "enum": ["sync", "async"], "description": "sync=调用方等待结构化结果(不建 Job);async=宿主建后台 Job 并进任务中心。必须显式写出;长耗时建议 async,但不限制 placements。" }, "interaction": { "type": "string", "enum": ["auto", "direct", "confirm", "form"], "description": "数据管理等可点击入口的交互方式(与 executionProfile 正交)。direct=一点即跑;confirm=轻量确认(文案用 confirmation.message);form=参数表单;auto/省略=宿主按 inputSchema+confirmation 推断。cron 触发与 agent 忽略本字段。" }, "interactionByPlacement": { "type": "object", "additionalProperties": false, "properties": { "toolbar": { "type": "string", "enum": ["direct", "confirm", "form"] }, "row": { "type": "string", "enum": ["direct", "confirm", "form"] }, "batch": { "type": "string", "enum": ["direct", "confirm", "form"] }, "cron": { "type": "string", "enum": ["direct", "confirm", "form"] }, "agent": { "type": "string", "enum": ["direct", "confirm", "form"] }, "skill-detail": { "type": "string", "enum": ["direct", "confirm", "form"] }, "create": { "type": "string", "enum": ["direct", "confirm", "form"] }, "update": { "type": "string", "enum": ["direct", "confirm", "form"] }, "delete": { "type": "string", "enum": ["direct", "confirm", "form"] }, "import": { "type": "string", "enum": ["direct", "confirm", "form"] } }, "description": "按 placement / replaces 覆盖 interaction(只能写 concrete 模式,不能写 auto)。" }, "bind": { "$ref": "#/$defs/bind" }, "hostEffects": { "$ref": "#/$defs/hostEffects" }, "steps": { "type": "array", "maxItems": 8, "items": { "$ref": "#/$defs/actionStep" }, "description": "可选。有序宿主编排(before / afterSuccess / afterFailure);单次最多 8 步。与 hostEffects 可并存(同效果可能各跑一次)。新技能优先用 steps。省略则无额外步骤。需匠厂宿主 ≥2.8.5。" }, "authz": { "type": "object", "additionalProperties": false, "properties": { "capability": { "type": "string", "minLength": 1, "description": "可选文档/静态提示用能力名;宿主不得仅凭此显隐按钮,运行时以 policy Snapshot 为准。" } } } }, "if": { "properties": { "placements": { "contains": { "const": "toolbar" } } }, "required": ["placements"] }, "then": { "required": ["bind"] }, "allOf": [ { "if": { "required": ["replaces"] }, "then": { "required": ["bind"] } } ], "description": "concurrency/locks 为未稳定预留字段,勿写入新技能 manifest。placements 含 toolbar 或声明 replaces 时必须声明 bind.tables。无 replaces 时 placements 建议非空(模板测试强制)。" } } }