fix(skills): 禁止自动注入完整技能内容 (#49)

## Summary

- 将 dashscope-image-gen、image-to-image、markdown、tech-diagram、xiaomi-tts
改为仅按需加载,并递增 patch 版本
- 在 Market validator 与 JSON Schema 中禁止 `disable-model-invocation: false`
- 将回归测试接入 `i18n Validate`,同步中英文技能编写规范

## Root cause and impact

这 5 个技能在首次引入时即声明 `disable-model-invocation: false`,导致完整技能正文进入普通请求的
system prompt。修改后市场技能只能声明 `true` 或省略该字段,完整内容仅在显式调用 Skill 工具后加载。

## Validation

- `uv run --quiet scripts/i18n/test_validate_i18n.py`
- `uv run --quiet scripts/i18n/validate-i18n.py`
- `uv run --quiet scripts/i18n/translate.py --check`
- `python3 -m json.tool
scripts/i18n/schema/skill-frontmatter.schema.json`
- `actionlint .github/workflows/i18n-validate.yml`
- `git diff --check`
This commit is contained in:
2026-07-14 11:55:22 +08:00
committed by GitHub
parent 5ab2994664
commit 73c94ab70e
15 changed files with 110 additions and 31 deletions

View File

@@ -58,6 +58,10 @@ jobs:
if: steps.changes.outputs.relevant == 'true' if: steps.changes.outputs.relevant == 'true'
uses: astral-sh/setup-uv@v3 uses: astral-sh/setup-uv@v3
- name: Run validator unit tests
if: steps.changes.outputs.relevant == 'true'
run: uv run --quiet scripts/i18n/test_validate_i18n.py
- name: Validate i18n - name: Validate i18n
if: steps.changes.outputs.relevant == 'true' if: steps.changes.outputs.relevant == 'true'
run: uv run --quiet scripts/i18n/validate-i18n.py run: uv run --quiet scripts/i18n/validate-i18n.py

View File

@@ -35,6 +35,7 @@ description: >- # 单字段Claude 检索用;建议含
Use this skill when the user wants to ... 用户提到 ...、...、... Use this skill when the user wants to ... 用户提到 ...、...、...
license: MIT license: MIT
version: 1.0.0 version: 1.0.0
disable-model-invocation: true # 必须为 true 或省略;禁止自动注入技能全文
metadata: metadata:
author: your-org author: your-org
updated_at: '2026-05-03' updated_at: '2026-05-03'
@@ -69,6 +70,9 @@ market:
完整 JSON Schema[`scripts/i18n/schema/skill-frontmatter.schema.json`](../scripts/i18n/schema/skill-frontmatter.schema.json) 完整 JSON Schema[`scripts/i18n/schema/skill-frontmatter.schema.json`](../scripts/i18n/schema/skill-frontmatter.schema.json)
市场技能只允许按需加载完整指令。`disable-model-invocation` 必须为 `true` 或省略;提交
`false` 会被 `i18n Validate` CI 拒绝。
--- ---
## 提交流程 ## 提交流程

View File

@@ -48,7 +48,10 @@
"enum": ["enabled", "disabled", "deprecated", "experimental"] "enum": ["enabled", "disabled", "deprecated", "experimental"]
}, },
"disable-model-invocation": { "disable-model-invocation": {
"type": "boolean" "description": "Must be true or omitted. Market skills may only load their full instructions on demand; automatic full-content injection is prohibited.",
"type": "boolean",
"const": true,
"default": true
}, },
"tags": { "tags": {
"type": "array", "type": "array",

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.10"
# dependencies = ["pyyaml>=6.0"]
# ///
"""Unit tests for market validation policies."""
from __future__ import annotations
import importlib.util
import sys
import unittest
from pathlib import Path
VALIDATOR_PATH = Path(__file__).with_name("validate-i18n.py")
SPEC = importlib.util.spec_from_file_location("market_validate_i18n", VALIDATOR_PATH)
assert SPEC is not None and SPEC.loader is not None
VALIDATOR = importlib.util.module_from_spec(SPEC)
sys.modules[SPEC.name] = VALIDATOR
SPEC.loader.exec_module(VALIDATOR)
class ModelInvocationPolicyTests(unittest.TestCase):
def validate(self, frontmatter: dict[str, object]) -> list[object]:
report = VALIDATOR.Report()
VALIDATOR.validate_model_invocation_policy(
frontmatter,
"skills/example/SKILL.md",
report,
)
return report.issues
def test_allows_true(self) -> None:
self.assertEqual([], self.validate({"disable-model-invocation": True}))
def test_allows_omitted_field(self) -> None:
self.assertEqual([], self.validate({}))
def test_rejects_false(self) -> None:
issues = self.validate({"disable-model-invocation": False})
self.assertEqual(1, len(issues))
self.assertEqual("model-invocation-policy", issues[0].rule)
def test_rejects_non_boolean_value(self) -> None:
issues = self.validate({"disable-model-invocation": "true"})
self.assertEqual(1, len(issues))
self.assertEqual("model-invocation-policy", issues[0].rule)
if __name__ == "__main__":
unittest.main()

View File

@@ -18,6 +18,7 @@ Checks:
9. Skill/Agent counts and builtin skill index match the repository contents. 9. Skill/Agent counts and builtin skill index match the repository contents.
10. Skill, Agent, and entry.json category references exist in categories.json. 10. Skill, Agent, and entry.json category references exist in categories.json.
11. entry.json pointers have the required marketplace fields and safe source URLs. 11. entry.json pointers have the required marketplace fields and safe source URLs.
12. Market Skills set `disable-model-invocation` to true or omit it; false is prohibited.
Exit codes: Exit codes:
0 = pass 0 = pass
@@ -108,6 +109,21 @@ def heading_count(text: str) -> int:
return len(HEADING_PATTERN.findall(text or "")) return len(HEADING_PATTERN.findall(text or ""))
def validate_model_invocation_policy(
frontmatter: dict[str, Any],
path: str,
report: Report,
) -> None:
"""Reject market skills that request full-content system-prompt injection."""
value = frontmatter.get("disable-model-invocation")
if value is not None and value is not True:
report.add(Issue(
path,
"model-invocation-policy",
"disable-model-invocation must be true or omitted; automatic full-content injection is prohibited",
))
def validate_skill( def validate_skill(
skill_dir: Path, skill_dir: Path,
report: Report, report: Report,
@@ -128,6 +144,8 @@ def validate_skill(
return return
assert fm is not None and body is not None assert fm is not None and body is not None
validate_model_invocation_policy(fm, f"{rel_dir}/SKILL.md", report)
name = fm.get("name", "") name = fm.get("name", "")
description = fm.get("description", "") description = fm.get("description", "")
market = fm.get("market") or {} market = fm.get("market") or {}

View File

@@ -8,11 +8,11 @@ description: >-
Use when the user mentions: generate image, draw, text-to-image, create image, Use when the user mentions: generate image, draw, text-to-image, create image,
AI painting, illustration, design picture. AI painting, illustration, design picture.
license: Complete terms in LICENSE.txt license: Complete terms in LICENSE.txt
version: 1.4.1 version: 1.4.2
type: procedural type: procedural
risk_level: low risk_level: low
status: enabled status: enabled
disable-model-invocation: false disable-model-invocation: true
provider: auto provider: auto
tags: tags:
- media - media
@@ -25,7 +25,7 @@ requires:
- Bash - Bash
metadata: metadata:
author: desirecore author: desirecore
updated_at: '2026-06-15' updated_at: '2026-07-14'
i18n: i18n:
default_locale: en-US default_locale: en-US
source_locale: zh-CN source_locale: zh-CN

View File

@@ -8,11 +8,11 @@ description: >-
换背景、换风格、图片编辑、以图生图、参考图、基于这张图、 换背景、换风格、图片编辑、以图生图、参考图、基于这张图、
把这张图改成、在这张图上、image edit、img2img。 把这张图改成、在这张图上、image edit、img2img。
license: Complete terms in LICENSE.txt license: Complete terms in LICENSE.txt
version: 1.0.1 version: 1.0.2
type: procedural type: procedural
risk_level: low risk_level: low
status: enabled status: enabled
disable-model-invocation: false disable-model-invocation: true
provider: auto provider: auto
tags: tags:
- media - media
@@ -24,7 +24,7 @@ requires:
- Bash - Bash
metadata: metadata:
author: desirecore author: desirecore
updated_at: '2026-06-12' updated_at: '2026-07-14'
i18n: i18n:
default_locale: en-US default_locale: en-US
source_locale: zh-CN source_locale: zh-CN

View File

@@ -4,7 +4,7 @@ description: >-
管理 Agent 的技能生命周期:通过 HTTP API 导入、安装、更新、删除技能, 管理 Agent 的技能生命周期:通过 HTTP API 导入、安装、更新、删除技能,
或通过 AgentFS 文件系统直接编写符合规范的 SKILL.md。Use when 用户要求 或通过 AgentFS 文件系统直接编写符合规范的 SKILL.md。Use when 用户要求
安装技能、从 URL/Git 导入技能、编写新技能、或管理已有技能。 安装技能、从 URL/Git 导入技能、编写新技能、或管理已有技能。
version: 1.0.5 version: 1.0.6
type: meta type: meta
risk_level: low risk_level: low
status: enabled status: enabled
@@ -17,7 +17,7 @@ tags:
- agentfs - agentfs
metadata: metadata:
author: desirecore author: desirecore
updated_at: '2026-05-05' updated_at: '2026-07-14'
i18n: i18n:
default_locale: en-US default_locale: en-US
source_locale: zh-CN source_locale: zh-CN
@@ -38,7 +38,7 @@ metadata:
description: >- description: >-
Manage the Skill lifecycle of an Agent: import, install, update, and delete Skills via HTTP API, or directly author standards-compliant SKILL.md files via the AgentFS filesystem. Use when the user requests to install Skills, import Skills from URL/Git, author new Skills, or manage existing Skills. Manage the Skill lifecycle of an Agent: import, install, update, and delete Skills via HTTP API, or directly author standards-compliant SKILL.md files via the AgentFS filesystem. Use when the user requests to install Skills, import Skills from URL/Git, author new Skills, or manage existing Skills.
body: ./SKILL.md body: ./SKILL.md
source_hash: sha256:eb098cb8c9bdf482 source_hash: sha256:57d9f0d8c351f884
translated_by: human translated_by: human
market: market:
icon: >- icon: >-
@@ -507,7 +507,7 @@ covering completed items, to-dos, and important decisions.
| `risk_level` | Recommended | enum | `low` / `medium` / `high` | | `risk_level` | Recommended | enum | `low` / `medium` / `high` |
| `status` | Recommended | enum | `enabled` / `disabled` | | `status` | Recommended | enum | `enabled` / `disabled` |
| `tags` | Optional | string[] | List of tags, used for search and categorization | | `tags` | Optional | string[] | List of tags, used for search and categorization |
| `disable-model-invocation` | Optional | boolean | `false` = opt-in auto-injection of full content into the system prompt; `true` (or omitted) = no auto-injection, only loaded when explicitly invoked via the Skill tool; default `true` | | `disable-model-invocation` | Optional | boolean | Must be `true` or omitted. Full-content auto-injection is prohibited; skills are loaded only when explicitly invoked via the Skill tool. |
| `requires` | Optional | object | Dependency declaration: `tools`, `optional_tools`, `connections` | | `requires` | Optional | object | Dependency declaration: `tools`, `optional_tools`, `connections` |
| `metadata` | Optional | object | Meta information: `author`, `updated_at` | | `metadata` | Optional | object | Meta information: `author`, `updated_at` |
| `market` | Optional | object | Market display metadata (only required for Skills published to the Market) | | `market` | Optional | object | Market display metadata (only required for Skills published to the Market) |

View File

@@ -447,7 +447,7 @@ metadata:
| `risk_level` | 推荐 | enum | `low` / `medium` / `high` | | `risk_level` | 推荐 | enum | `low` / `medium` / `high` |
| `status` | 推荐 | enum | `enabled` / `disabled` | | `status` | 推荐 | enum | `enabled` / `disabled` |
| `tags` | 可选 | string[] | 标签列表,用于搜索和分类 | | `tags` | 可选 | string[] | 标签列表,用于搜索和分类 |
| `disable-model-invocation` | 可选 | boolean | `false`=opt-in 自动注入完整内容到 system prompt`true` 或缺省=不自动注入,仅显式 Skill 工具调用时才加载;默认 `true` | | `disable-model-invocation` | 可选 | boolean | 必须为 `true` 或省略。禁止把技能全文自动注入 system prompt仅在显式调用 Skill 工具时加载。 |
| `requires` | 可选 | object | 依赖声明:`tools``optional_tools``connections` | | `requires` | 可选 | object | 依赖声明:`tools``optional_tools``connections` |
| `metadata` | 可选 | object | 元信息:`author``updated_at` | | `metadata` | 可选 | object | 元信息:`author``updated_at` |
| `market` | 可选 | object | 市场展示元数据(仅市场发布的技能需要) | | `market` | 可选 | object | 市场展示元数据(仅市场发布的技能需要) |

View File

@@ -16,11 +16,11 @@ description: >-
月报、邮件、对比分析、会议记录、散文、文章、作文、md、markdown、report、 月报、邮件、对比分析、会议记录、散文、文章、作文、md、markdown、report、
summary、plan、outline、memo、table、list、draft、document、notes、 summary、plan、outline、memo、table、list、draft、document、notes、
write、create、organize。 write、create、organize。
version: 1.0.0 version: 1.0.1
type: procedural type: procedural
risk_level: low risk_level: low
status: enabled status: enabled
disable-model-invocation: false disable-model-invocation: true
tags: tags:
- markdown - markdown
- md - md
@@ -28,7 +28,7 @@ tags:
- text - text
metadata: metadata:
author: desirecore author: desirecore
updated_at: '2026-05-11' updated_at: '2026-07-14'
i18n: i18n:
default_locale: en-US default_locale: en-US
source_locale: zh-CN source_locale: zh-CN

View File

@@ -5,7 +5,7 @@ description: >-
frontmatter 元数据 + L0/L1/L2 分层内容 + 脚本/参考/资产)和 Claude Code frontmatter 元数据 + L0/L1/L2 分层内容 + 脚本/参考/资产)和 Claude Code
基础格式。Use when 用户要求创建新技能、更新已有技能、或将经验封装为可复用 基础格式。Use when 用户要求创建新技能、更新已有技能、或将经验封装为可复用
的技能包。 的技能包。
version: 1.0.4 version: 1.0.5
type: meta type: meta
risk_level: low risk_level: low
status: enabled status: enabled
@@ -18,7 +18,7 @@ tags:
- authoring - authoring
metadata: metadata:
author: desirecore author: desirecore
updated_at: '2026-05-05' updated_at: '2026-07-14'
i18n: i18n:
default_locale: en-US default_locale: en-US
source_locale: zh-CN source_locale: zh-CN
@@ -39,7 +39,7 @@ metadata:
description: >- description: >-
Guides users to create and edit standards-compliant SKILL.md skill packages. Supports the DesireCore full format (frontmatter metadata + L0/L1/L2 layered content + scripts/references/assets) and the Claude Code basic format. Use when the user requests to create a new Skill, update an existing Skill, or package experience into a reusable Skill bundle. Guides users to create and edit standards-compliant SKILL.md skill packages. Supports the DesireCore full format (frontmatter metadata + L0/L1/L2 layered content + scripts/references/assets) and the Claude Code basic format. Use when the user requests to create a new Skill, update an existing Skill, or package experience into a reusable Skill bundle.
body: ./SKILL.md body: ./SKILL.md
source_hash: sha256:e14a6879bb800455 source_hash: sha256:f6aa877d100a85e1
translated_by: human translated_by: human
market: market:
icon: >- icon: >-
@@ -160,7 +160,7 @@ A SKILL.md consists of two parts: **Frontmatter (YAML metadata)** and **Body (Ma
| Field | Type | Default | Description | | Field | Type | Default | Description |
|------|------|------|------| |------|------|------|------|
| `disable-model-invocation` | boolean | `true` | `false` = opt-in auto-injection of full SKILL.md content into the system prompt (auto-loaded); `true` (or omitted) = no auto-injection, only loaded when an Agent explicitly invokes the Skill tool (aligned with Claude Skills: disabled by default, opt-in) | | `disable-model-invocation` | boolean | `true` | Must be `true` or omitted. Full SKILL.md auto-injection is prohibited; an Agent must explicitly invoke the Skill tool to load the instructions. |
| `user-invocable` | boolean | `true` | `false` = does not appear in command completion; serves only as background knowledge | | `user-invocable` | boolean | `true` | `false` = does not appear in command completion; serves only as background knowledge |
| `allowed-tools` | string[] | — | Restricts the list of tools available at execution time | | `allowed-tools` | string[] | — | Restricts the list of tools available at execution time |
| `requires` | object | — | Dependency declaration: `tools`, `optional_tools`, `connections` | | `requires` | object | — | Dependency declaration: `tools`, `optional_tools`, `connections` |

View File

@@ -100,7 +100,7 @@ SKILL.md 由两部分组成:**FrontmatterYAML 元数据)** 和 **BodyM
| 字段 | 类型 | 默认 | 说明 | | 字段 | 类型 | 默认 | 说明 |
|------|------|------|------| |------|------|------|------|
| `disable-model-invocation` | boolean | `true` | `false`=opt-in 自动注入完整 SKILL.md 内容到 system prompt(自动加载);`true` 或缺省=不自动注入,仅当 Agent 显式调用 Skill 工具才加载(与 Claude Skills 对齐:默认禁用,需显式启用) | | `disable-model-invocation` | boolean | `true` | 必须为 `true` 或省略。禁止把完整 SKILL.md 自动注入 system promptAgent 必须显式调用 Skill 工具才加载指令。 |
| `user-invocable` | boolean | `true` | `false`=不出现在命令补全,仅作为背景知识 | | `user-invocable` | boolean | `true` | `false`=不出现在命令补全,仅作为背景知识 |
| `allowed-tools` | string[] | — | 限制执行时可用的工具列表 | | `allowed-tools` | string[] | — | 限制执行时可用的工具列表 |
| `requires` | object | — | 依赖声明:`tools``optional_tools``connections` | | `requires` | object | — | 依赖声明:`tools``optional_tools``connections` |

View File

@@ -25,7 +25,7 @@
| 字段 | 类型 | 默认 | 说明 | | 字段 | 类型 | 默认 | 说明 |
|------|------|------|------| |------|------|------|------|
| `disable-model-invocation` | boolean | `true` | `false`=opt-in 自动注入完整 SKILL.md 内容到 system prompt(自动加载);`true` 或缺省=不自动注入,仅当 Agent 显式调用 Skill 工具才加载(与 Claude Skills 对齐:默认禁用,需显式启用) | | `disable-model-invocation` | boolean | `true` | 必须为 `true` 或省略。禁止把完整 SKILL.md 自动注入 system promptAgent 必须显式调用 `Skill` 工具才加载指令。 |
| `user-invocable` | boolean | `true` | `false`=不出现在命令补全,仅作为背景知识 | | `user-invocable` | boolean | `true` | `false`=不出现在命令补全,仅作为背景知识 |
| `allowed-tools` | string[] | 全部 | 限制执行时可用的工具列表(如 `["Edit", "Read", "Bash"]` | | `allowed-tools` | string[] | 全部 | 限制执行时可用的工具列表(如 `["Edit", "Read", "Bash"]` |
| `model` | string | 继承 | 覆盖使用的模型 ID`"claude-sonnet-4-20250514"` | | `model` | string | 继承 | 覆盖使用的模型 ID`"claude-sonnet-4-20250514"` |
@@ -127,10 +127,8 @@ json_output:
L0/L1/L2 是 SKILL.md **内容组织约定**Claude Skills 风格),帮助作者把摘要、原则、详细规范分层书写。**运行时并不在 L0/L1/L2 之间做"按需加载"**——一旦 skill 被加载,就是整篇 SKILL.md 内容(除 frontmatter注入 system prompt。 L0/L1/L2 是 SKILL.md **内容组织约定**Claude Skills 风格),帮助作者把摘要、原则、详细规范分层书写。**运行时并不在 L0/L1/L2 之间做"按需加载"**——一旦 skill 被加载,就是整篇 SKILL.md 内容(除 frontmatter注入 system prompt。
是否被自动加载由 `disable-model-invocation` 决定: 市场技能不允许把全文自动注入 system prompt。`disable-model-invocation` 必须为 `true`
或省略skill 仅在 Agent 显式调用 `Skill` 工具并传入对应 skill ID 后加载。
- `disable-model-invocation: false`skill 被加入自动加载列表,整篇内容随 system prompt 注入
- `disable-model-invocation: true` 或缺省时skill 不自动加载,仅当 Agent 显式调用 `Skill` 工具传入此 skill ID 时才加载
## 完整示例 ## 完整示例

View File

@@ -12,11 +12,11 @@ description: >-
Use when 用户提到 画架构图、架构图、流程图、时序图、序列图、状态图、状态机、 Use when 用户提到 画架构图、架构图、流程图、时序图、序列图、状态图、状态机、
ER图、类图、思维导图、出图、画图、可视化、画一张图、画个图、图表风格、 ER图、类图、思维导图、出图、画图、可视化、画一张图、画个图、图表风格、
暗色风格图、蓝图风格图、奶油风格图、draw diagram、architecture diagram、flowchart、sequence diagram。 暗色风格图、蓝图风格图、奶油风格图、draw diagram、architecture diagram、flowchart、sequence diagram。
version: 1.1.0 version: 1.1.1
type: procedural type: procedural
risk_level: low risk_level: low
status: enabled status: enabled
disable-model-invocation: false disable-model-invocation: true
tags: tags:
- diagram - diagram
- mermaid - mermaid
@@ -25,7 +25,7 @@ tags:
- visualization - visualization
metadata: metadata:
author: desirecore author: desirecore
updated_at: '2026-05-31' updated_at: '2026-07-14'
i18n: i18n:
default_locale: en-US default_locale: en-US
source_locale: zh-CN source_locale: zh-CN

View File

@@ -8,11 +8,11 @@ description: >-
Use when 用户提到 语音合成、文字转语音、TTS、朗读、读出来、生成语音、 Use when 用户提到 语音合成、文字转语音、TTS、朗读、读出来、生成语音、
生成音频、文本转音频、配音、念出来、小米语音、MiMo 语音、小米 TTS。 生成音频、文本转音频、配音、念出来、小米语音、MiMo 语音、小米 TTS。
license: Complete terms in LICENSE.txt license: Complete terms in LICENSE.txt
version: 1.0.2 version: 1.0.3
type: procedural type: procedural
risk_level: low risk_level: low
status: enabled status: enabled
disable-model-invocation: false disable-model-invocation: true
provider: xiaomi provider: xiaomi
tags: tags:
- media - media
@@ -26,7 +26,7 @@ requires:
- Bash - Bash
metadata: metadata:
author: desirecore author: desirecore
updated_at: '2026-05-08' updated_at: '2026-07-14'
i18n: i18n:
default_locale: en-US default_locale: en-US
source_locale: zh-CN source_locale: zh-CN