#!/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 "<一句话职责>" [--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())