Files
Leroy d3e9bd45bd LeMetaSkill v1.1.0:跨 runtime(ZCode/Claude Code/Codex)的 Agent Skill 创建与迭代工坊
- SKILL.md 双工作流(创建/迭代)+ 两道门(验料/通用化)+ 三档位
- 7 篇方法论 references + 3 个纯标准库脚本(scaffold/validate/trigger_eval)
- 自身触发用例 16 条 + 先例研究/创建/迭代证据报告
- 方法论吸收自 qiaomu-meta-skill 与 luban-skill,取舍见 reports/prior-art.md
2026-10-05 12:09:22 +08:00

127 lines
4.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""LeMetaSkill 起草脚手架:按档位生成"出生即合规"的 skill 骨架。
档位与产出:
- draft 仅 SKILL.md(来自 assets/SKILL.template.md)
- shared + evals/trigger_cases.json 用例模板 + README.md(三节起步)
- rigorous + reports/ 证据目录约定
用法: python3 scaffold.py <name> "<一句话职责>" [--tier draft|shared|rigorous] [--target 目录]
"""
from __future__ import annotations
import argparse
import re
import sys
from pathlib import Path
TIERS = ("draft", "shared", "rigorous")
README_TEMPLATE = """# {name}
> {tagline}
**状态**:{tier} 档,个人/项目内使用。
## 它解决什么问题
【TODO:2-3 句,第二人称说清痛点和交付物】
## 触发方式
- 【TODO:用户真实会说的原话 3-8 条】
## 安全边界
【TODO:不会做什么、什么时候停下来问用户】
"""
REPORTS_README = """# reports/ —— 运行证据
存放本 skill 的可复查证据,约定:
- `trigger-eval.json` trigger_eval.py 的输出(含手工补记的 live_turns 实测段)
- `creation-handoff.md` 创建交付报告(rigorous 档)
- `iteration-<日期>.md` 每轮迭代的改动报告与回炉清单
诚实条款:验证不了的写「证据缺失」,不编造;计划中的工作不是证据。
"""
CASES_TEMPLATE = """{
"_说明": "填入用户真实会说的话:应触发/不应触发/边界各若干条。family 标注场景族,便于回归分析。",
"recommended_threshold": 0.3,
"negative_patterns": ["不要做成 skill", "只要总结", "翻译一下"],
"should_trigger": [
{"text": "【TODO:用户原话】", "family": "cn_case_1"}
],
"should_not_trigger": [
{"text": "【TODO:相邻但不该触发的原话】", "family": "near_task"}
],
"near_neighbor": []
}
"""
def main() -> int:
ap = argparse.ArgumentParser(description="生成 skill 骨架")
ap.add_argument("name")
ap.add_argument("tagline")
ap.add_argument("--tier", choices=TIERS, default="draft")
ap.add_argument("--target", type=Path, default=None)
args = ap.parse_args()
name = args.name.strip().lower()
if not re.fullmatch(r"[a-z0-9]+(-[a-z0-9]+)*", name):
print(f"✘ name 必须是 kebab-case(小写字母数字+连字符): {name!r}")
return 1
target = (args.target or Path(".agents/skills") / name).resolve()
if target.exists() and any(target.iterdir()):
print(f"✘ 目标目录已存在且非空: {target}(不覆盖,确认后手动清理)")
return 1
target.mkdir(parents=True)
# 模板:优先读 assets/SKILL.template.md,缺失时用内置兜底
template_path = Path(__file__).resolve().parent.parent / "assets" / "SKILL.template.md"
if template_path.is_file():
template = template_path.read_text(encoding="utf-8")
else:
template = (
"---\nname: {name}\ndescription: |\n {tagline}\n 【TODO:做什么/何时触发,2-3 句 + 触发原话】\n"
" 不要用于:【TODO:负触发,至少 2 条】。\n---\n\n# {name}\n\n【TODO:工作流正文】\n"
)
(target / "SKILL.md").write_text(
template.replace("{{name}}", name).replace("{{tagline}}", args.tagline),
encoding="utf-8",
)
print(f"✔ {target / 'SKILL.md'}")
if args.tier in ("shared", "rigorous"):
cases_dir = target / "evals"
cases_dir.mkdir(exist_ok=True)
(cases_dir / "trigger_cases.json").write_text(CASES_TEMPLATE, encoding="utf-8")
print(f"✔ {cases_dir / 'trigger_cases.json'}(待填真实原话)")
(target / "README.md").write_text(
README_TEMPLATE.format(name=name, tagline=args.tagline, tier=args.tier), encoding="utf-8"
)
print(f"✔ {target / 'README.md'}")
if args.tier == "rigorous":
reports = target / "reports"
reports.mkdir(exist_ok=True)
(reports / "README.md").write_text(REPORTS_README, encoding="utf-8")
print(f"✔ {reports / 'README.md'}")
print(
f"\n下一步:\n"
f"1. 填 TODO(grep -rn 'TODO' {target})——先写好 description 再写正文;\n"
f"2. python3 scripts/validate_skill.py {target};\n"
f"3. 填好用例后 python3 scripts/trigger_eval.py {target},再做真实对话实测。"
)
return 0
if __name__ == "__main__":
sys.exit(main())