feat: open source yao-meta-skill

This commit is contained in:
yaojingang
2026-03-31 19:59:29 +08:00
commit d4eccba69e
19 changed files with 1364 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
.DS_Store
dist/
*.zip
__pycache__/
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Yao Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+133
View File
@@ -0,0 +1,133 @@
# Yao Meta Skill
`yao-meta-skill` is a meta-skill for building other agent skills.
It turns rough workflows, transcripts, prompts, notes, and runbooks into reusable skill packages with:
- a clear trigger surface
- a lean `SKILL.md`
- optional references, scripts, and evals
- neutral source metadata plus client-specific adapters
## What It Does
This project helps you create, refactor, evaluate, and package skills as durable capability bundles rather than one-off prompts.
The design logic is simple:
1. Capture the real recurring job behind the user's request.
2. Set a clean skill boundary so one package does one coherent job.
3. Optimize the trigger description before over-writing the body.
4. Keep the main skill file small and move details into references or scripts.
5. Add quality gates only when they pay for themselves.
6. Export compatibility artifacts only for the clients you actually need.
## Why It Exists
Most teams keep valuable operating knowledge scattered across chats, personal prompts, oral habits, and undocumented workflows. This project converts that hidden process knowledge into:
- discoverable skill packages
- repeatable execution flows
- lower-context instructions
- reusable team assets
- compatibility-ready distributions
## Repository Structure
```text
yao-meta-skill/
├── SKILL.md
├── README.md
├── LICENSE
├── .gitignore
├── agents/
│ └── interface.yaml
├── references/
├── scripts/
└── templates/
```
## Core Components
### `SKILL.md`
The main skill entrypoint. It defines the trigger surface, operating modes, compact workflow, and output contract.
### `agents/interface.yaml`
The neutral metadata source of truth. It stores display and compatibility metadata without locking the source tree to one vendor-specific path.
### `references/`
Long-form material that should not bloat the main skill file. This includes design rules, evaluation guidance, compatibility strategy, and quality rubrics.
### `scripts/`
Utility scripts that make the meta-skill operational:
- `trigger_eval.py`: checks whether a trigger description is too broad or too weak
- `context_sizer.py`: estimates context weight and warns when the initial load gets too large
- `cross_packager.py`: builds client-specific export artifacts from the neutral source package
### `templates/`
Starter templates for simple and more advanced skill packages.
## How To Use
### 1. Use the skill directly
Invoke `yao-meta-skill` when you want to:
- create a new skill
- improve an existing skill
- add evals to a skill
- convert a workflow into a reusable package
- prepare a skill for wider team adoption
### 2. Generate a new skill package
The typical flow is:
1. describe the workflow or capability
2. identify trigger phrases and outputs
3. choose scaffold, production, or library mode
4. generate the package
5. run the sizing and trigger checks if needed
6. export target-specific compatibility artifacts
### 3. Export compatibility artifacts
Examples:
```bash
python3 scripts/cross_packager.py ./yao-meta-skill --platform openai --platform claude --zip
python3 scripts/context_sizer.py ./yao-meta-skill
python3 scripts/trigger_eval.py --description "Create and improve agent skills..." --cases ./cases.json
```
## Advantages
- **Neutral by default**: source files stay vendor-neutral, while adapters are generated only when needed.
- **Context efficient**: the project explicitly pushes detail out of the main skill file.
- **Evaluation-aware**: trigger and sizing checks are built into the workflow.
- **Reusable**: the output is a package, not just a paragraph of prompt text.
- **Portable**: compatibility is handled through packaging rather than duplicating source files for every client.
## Best Fit
This project is best for:
- agent builders
- internal tooling teams
- prompt engineers moving toward structured skills
- organizations building reusable skill libraries
## Documentation
- Chinese introduction: [docs/README.zh-CN.md](docs/README.zh-CN.md)
- Japanese introduction: [docs/README.ja-JP.md](docs/README.ja-JP.md)
## License
MIT. See [LICENSE](LICENSE).
+177
View File
@@ -0,0 +1,177 @@
---
name: yao-meta-skill
description: Create, refactor, evaluate, and package agent skills from workflows, transcripts, prompts, docs, or rough notes. Use when asked to create a skill, turn a repeated process into a reusable skill, improve an existing skill, optimize skill triggering, add evals, or prepare a skill for team reuse. Relevant for meta-skills, skill factories, skill templates, skill QA, and cross-platform skill packaging.
metadata:
author: Yao Team
philosophy: "structured design, evaluation loop, template ergonomics, operational packaging"
---
# Yao Meta Skill
Build skills as reusable products, not long prompts.
## Core Rules
- Treat a skill as a maintained capability package.
- Write the frontmatter `description` early; it is the main trigger surface.
- Keep `SKILL.md` lean. Put detail in `references/`, deterministic logic in `scripts/`, and output artifacts in `assets/`.
- Use the lightest process that still protects quality.
- Package for reuse only when the user actually needs reuse.
## Use Cases
Use this skill to:
- create a new skill
- turn a workflow, runbook, transcript, or prompt set into a skill
- improve a skill's boundary, description, evals, or packaging
- design a team skill template or skill-library standard
- migrate a skill toward the Agent Skills open format
## Modes
Choose the lightest mode that fits.
### Scaffold
Use for exploratory or personal skills.
Deliver:
- `SKILL.md`
- `agents/interface.yaml`
- `references/` only if clearly needed
### Production
Use for reusable team skills.
Deliver:
- concise package structure
- focused `references/`
- `scripts/` when prose would be brittle or repetitive
- `evals/` when output quality can be checked
### Library
Use for important organizational skills or meta-skills.
Add:
- trigger positives, negatives, and near neighbors
- revision rubric
- packaging guidance
- maintenance metadata when useful
## Factory Components
Use these when they materially improve quality:
- `templates/basic_skill.md.j2`
- `templates/complex_skill.md.j2`
- `scripts/trigger_eval.py`
- `scripts/context_sizer.py`
- `scripts/cross_packager.py`
## Workflow
### 1. Capture the real job
Infer:
- the recurring task or decision
- likely trigger phrases and contexts
- expected outputs
- what must be deterministic
- whether the skill is personal, team, or cross-platform
Keep discovery lean. Default to no more than two clarification rounds unless guessing is risky.
### 2. Set the boundary
One skill should usually have:
- one capability family
- one trigger surface
- one coherent workflow
Split oversized skills. Move variants into `references/` or sibling skills.
### 3. Design the trigger
The `description` should say:
- what the skill does
- when to use it
- phrases, artifacts, or file types that should trigger it
- adjacent cases that are easy to miss
For important skills, create `should_trigger`, `should_not_trigger`, and near-neighbor prompts. Use `scripts/trigger_eval.py` when helpful.
### 4. Write the package
Default structure:
```text
skill-name/
├── SKILL.md
├── agents/interface.yaml
├── references/
├── scripts/
├── assets/
└── evals/
```
Only create folders that earn their keep. Start from the basic template unless the skill clearly needs the complex one.
### 5. Add quality gates
Use the minimum useful QA:
- basic: structure and naming check
- standard: realistic prompts and expected outcomes
- advanced: trigger evals, benchmark comparisons, revision loop
For production or library-grade skills, run `scripts/context_sizer.py` before finalizing.
### 6. Package for reuse
If team reuse matters, include:
- stable folder name
- aligned `agents/interface.yaml`
- minimal tool assumptions
- version or maintenance metadata when useful
- target-specific packaging only for requested platforms
Use `scripts/cross_packager.py` when packaging artifacts are needed.
### 7. Report the result
Summarize:
- what was packaged
- what trigger surface was chosen
- what was excluded
- what quality gates exist
- what should be improved next
## Output Contract
Unless the user asks otherwise, produce:
1. a working skill directory
2. a trigger-aware `SKILL.md`
3. aligned `agents/interface.yaml`
4. references only where they reduce context bloat
5. optional scripts, evals, and `manifest.json` when justified
## Reference Map
- [Skill Design Guidelines](references/skill_design_guidelines.md)
- [Client Compatibility](references/client-compatibility.md)
- [Comparative Analysis](references/comparative-analysis.md)
- [Meta-Skill Rubric](references/design-rubric.md)
- [Skill Template](references/skill-template.md)
- [Trigger And Eval Playbook](references/eval-playbook.md)
+10
View File
@@ -0,0 +1,10 @@
interface:
display_name: "Yao Meta Skill"
short_description: "Create robust, trigger-aware agent skills"
default_prompt: "Use $yao-meta-skill to turn my workflow, prompt set, or rough notes into a production-ready skill with strong triggering, lean structure, and an eval plan."
compatibility:
canonical_format: "agent-skills"
adapter_targets:
- "openai"
- "claude"
- "generic"
+57
View File
@@ -0,0 +1,57 @@
# Yao Meta Skill 日本語紹介
`yao-meta-skill` は「スキルを作るためのスキル」です。
目的は、長いプロンプトを書くことではなく、散在したワークフロー、会話ログ、運用ノウハウ、手順書を、再利用可能で評価可能かつ配布可能なスキルパッケージに変換することです。
## 基本ロジック
処理の流れは次の 6 段階です。
1. ユーザーが本当に繰り返している仕事を特定する
2. スキルの境界を明確にし、1 つのパッケージで役割を混在させない
3. 本文を長くする前に、トリガー用 description を最適化する
4. `SKILL.md` を小さく保ち、詳細は `references/``scripts/` に分離する
5. 必要な場合にだけ評価や品質ゲートを追加する
6. 必要なクライアント向けにだけ互換アダプタを生成する
## 使い方
次のようなケースに向いています。
- 新しい skill を作る
- 既存 skill を改善する
- workflow を skill 化する
- skill に eval を追加する
- チーム向けに skill を共有または公開する
一般的な流れ:
1. 対象となる workflow や能力を説明する
2. トリガー条件と期待出力を整理する
3. `Scaffold``Production``Library` モードを選ぶ
4. skill パッケージを生成する
5. トリガー評価とコンテキストサイズチェックを実行する
6. 必要なクライアント向け互換パッケージを出力する
## 強み
- **中立的な設計**: ソースツリーは単一ベンダーのパスに依存しない
- **コンテキスト効率**: メインファイルを小さく保つ前提で設計されている
- **評価可能**: トリガー評価とサイズ計測の仕組みを含む
- **再利用しやすい**: 出力が単発プロンプトではなく skill パッケージになる
- **互換性重視**: 複数クライアント対応をソース複製ではなくパッケージ生成で実現する
## リポジトリ構成
- `SKILL.md`: メインエントリ
- `agents/interface.yaml`: 中立的なメタデータ源
- `references/`: 長い説明や設計ルール
- `scripts/`: 評価、サイズ計測、互換パッケージ生成
- `templates/`: 基本テンプレートと複雑テンプレート
## 想定ユーザー
- agent 用の能力ライブラリを構築する人
- 内部自動化や知識資産化を進めるチーム
- prompt engineering から skill engineering に進みたい個人や組織
+57
View File
@@ -0,0 +1,57 @@
# Yao Meta Skill 中文介绍
`yao-meta-skill` 是一个“生成技能的技能”。
它的目标不是再写一段更长的提示词,而是把零散的工作流、聊天记录、经验规则和运行手册,沉淀成可复用、可评估、可分发的技能包。
## 核心逻辑
它的工作逻辑分成六步:
1. 识别用户真正反复要做的事情
2. 给技能划定清晰边界,避免一个技能包做太多事
3. 优先优化触发描述,而不是先把正文写得很长
4. 把主 `SKILL.md` 保持精简,细节放进 `references/``scripts/`
5. 只在必要时加入评测和质量门槛
6. 只为真正需要的客户端生成兼容适配文件
## 怎么使用
适合这些场景:
- 创建新 skill
- 优化已有 skill
- 把 workflow 转成 skill
- 给 skill 增加 eval
- 为团队开源或共享 skill
常见使用流程:
1. 描述你的目标流程或能力
2. 明确触发语境和产出结果
3. 选择 `Scaffold``Production``Library` 模式
4. 生成 skill 包
5. 运行触发检查和上下文体积检查
6. 按目标客户端导出兼容产物
## 优势与特点
- **默认中性**:源码结构不绑定单一厂商路径
- **上下文节省**:强调主入口精简和按需加载
- **可评测**:自带触发检查与体积检查工具
- **可复用**:产物是完整 skill 包,不是一段一次性 prompt
- **可兼容**:通过打包阶段生成适配层,而不是在源码中堆叠多套品牌文件
## 仓库结构
- `SKILL.md`:主入口
- `agents/interface.yaml`:中性元数据源
- `references/`:长文档和规则说明
- `scripts/`:评测、体积分析、兼容打包脚本
- `templates/`:基础模板与复杂模板
## 适合谁
- 构建 agent 能力库的人
- 做内部自动化和知识沉淀的团队
- 想把 prompt 工程升级成 skill 工程的个人或组织
+18
View File
@@ -0,0 +1,18 @@
{
"name": "yao-meta-skill",
"version": "1.1.0",
"owner": "Yao Team",
"updated_at": "2026-03-31",
"review_cadence": "quarterly",
"target_platforms": [
"openai",
"claude",
"generic",
"agent-skills-compatible"
],
"factory_components": [
"templates",
"references",
"scripts"
]
}
+34
View File
@@ -0,0 +1,34 @@
# Client Compatibility
This skill package uses a neutral source-of-truth file:
- `agents/interface.yaml`
That file is the canonical metadata source for display name, short description, default prompt, and adapter targets.
## Compatibility Strategy
Use a two-layer model:
1. **Canonical source**
- Keep brand-neutral metadata in `agents/interface.yaml`.
- Keep behavior in `SKILL.md`, `references/`, and `scripts/`.
2. **Adapter outputs**
- Generate client-specific metadata only when exporting or packaging.
- Do not keep vendor-specific metadata files in the source tree unless a client strictly requires them.
## Supported Targets
The current adapter flow is designed for:
- OpenAI-compatible clients
- Claude-compatible clients
- generic Agent Skills clients
## Compatibility Rules
- Keep `SKILL.md` as the primary behavior definition.
- Keep client metadata minimal and presentation-focused.
- Avoid putting client-specific logic in the main workflow.
- Prefer packaging-time conversion over source-tree duplication.
+113
View File
@@ -0,0 +1,113 @@
# Comparative Analysis
This reference distills four meta-skill archetypes into one design system.
## Shared Logic
All four approaches converge on the same model:
1. A skill is a folderized capability package, not a prompt snippet.
2. Frontmatter description is the trigger surface.
3. Long instructions should be split by progressive disclosure.
4. Skills are most valuable for repeated, multi-step, tool-using workflows.
5. Skills become more valuable when they are portable, maintainable, and shareable.
## Structure-First Creator
Primary strengths:
- clear structure and boundary discipline
- strong context-efficiency mindset
- good guidance on progressive disclosure
- pragmatic skeleton for authoring without overbuilding
Primary gaps:
- lighter on trigger benchmarking than the eval-first archetype
- lighter on distribution and registry than the factory archetype
- less opinionated on organizational operations beyond good authoring practice
Use it for:
- canonical package structure
- concise writing standard
- deciding what belongs in `SKILL.md` vs `references/`
## Eval-First Creator
Primary strengths:
- eval-first mindset
- explicit trigger optimization
- positive and negative prompt testing
- iterative improvement loop with benchmark thinking
Primary gaps:
- heavier process cost
- more suitable for high-value skills than quick one-offs
- some workflow assumptions are tied to a specific runtime style
Use it for:
- trigger eval design
- benchmark loops
- systematic improvement of important skills
## Template-First Scaffold
Primary strengths:
- fast onboarding
- clean scaffold
- easy explanation of required fields
- good for normalizing team authoring habits
Primary gaps:
- shallow evaluation model
- limited operations guidance after scaffolding
- more a template than a full skill engineering system
Use it for:
- starter layout
- contributor onboarding
- low-friction authoring workflow
## Factory-First Builder
Primary strengths:
- strongest productization instinct
- cross-platform packaging and export thinking
- validation, security, staleness, and registry mindset
- closest to a skill factory instead of a skill template
Primary gaps:
- heavier system and maintenance cost
- portability requires adaptation layers in practice
- may be excessive for small personal skills
Use it for:
- distribution and registry model
- packaging lifecycle
- maintenance and governance thinking
## Yao Synthesis
The right synthesis is:
- **structure-first for clarity**
- **eval-first for reliability**
- **template-first for onboarding**
- **factory-first for operations and scale**
That combination yields a meta-skill that is:
- lightweight enough to use often
- rigorous enough for important skills
- structured enough for team adoption
- operational enough for long-term reuse
+68
View File
@@ -0,0 +1,68 @@
# Meta-Skill Rubric
Score each generated skill from 1 to 5 on each dimension.
## 1. Trigger Clarity
Questions:
- Does the description say what the skill does?
- Does it say when to use it?
- Does it include realistic trigger phrases and adjacent cases?
- Is it likely to reduce under-triggering?
## 2. Boundary Clarity
Questions:
- Is the skill solving one coherent capability family?
- Are unrelated tasks excluded?
- Are variants separated cleanly into references or sibling skills?
## 3. Context Efficiency
Questions:
- Is `SKILL.md` lean?
- Are details pushed into `references/`?
- Are scripts used where prose would be brittle or repetitive?
## 4. Execution Reliability
Questions:
- Are the workflow steps actionable?
- Are critical constraints explicit?
- Are deterministic steps captured in scripts or templates?
- Is there a clear failure-handling path?
## 5. Evaluation Quality
Questions:
- Are there realistic usage prompts?
- Are there trigger positives and negatives for important skills?
- Is there a way to compare revisions?
## 6. Reuse And Maintenance
Questions:
- Can another teammate discover and reuse the skill?
- Is `agents/interface.yaml` aligned with the package?
- Are ownership and future iteration obvious?
## 7. Portability
Questions:
- Does the package stay close to the open format?
- Are tool-specific assumptions minimized or isolated?
- Can the skill be adapted to another compatible client without rewrite?
## Interpretation
- `30+`: production-ready
- `24-29`: solid but improve weak dimensions
- `18-23`: usable draft, not yet robust
- `<18`: redesign the boundary or trigger strategy
+69
View File
@@ -0,0 +1,69 @@
# Trigger And Eval Playbook
Use this playbook for skills that matter enough to test.
## A. Trigger Evaluation
Create three prompt buckets:
### 1. Should Trigger
Prompts that clearly need the skill.
Goal:
- verify recall
### 2. Should Not Trigger
Prompts that are clearly outside the skill boundary.
Goal:
- verify precision
### 3. Near Neighbors
Prompts that look similar but should use another skill or no skill.
Goal:
- catch false positives and ambiguous routing
## B. Execution Evaluation
For each important use case, create 1 to 3 realistic prompts with:
- user-like phrasing
- representative inputs or file types
- expected output description
- key checks
## C. Revision Loop
When a skill underperforms:
1. Fix boundary or description problems before adding more body text.
2. Move brittle logic into scripts or templates.
3. Split reference content if `SKILL.md` becomes bloated.
4. Re-run the same eval set before expanding scope.
## D. Minimum QA By Skill Tier
### Personal skill
- 2 realistic prompts
- manual review
### Team skill
- 3 to 5 realistic prompts
- trigger positives and negatives
- one revision loop
### Infrastructure or meta-skill
- 5+ execution prompts
- trigger positives, negatives, and near neighbors
- benchmark notes across revisions
- ownership and drift review
+74
View File
@@ -0,0 +1,74 @@
# Skill Template
Use this skeleton when generating a new skill.
```markdown
---
name: skill-name
description: Describe what the skill does and when to use it. Include realistic trigger phrases, task types, artifacts, or adjacent scenarios that should activate it.
metadata:
author: Your team
---
# Skill Title
One-sentence summary of the capability.
## When To Use This Skill
- Trigger scenario 1
- Trigger scenario 2
- Trigger scenario 3
## Workflow
### 1. Understand the request
- Identify the actual job to be done
- Check assumptions and inputs
### 2. Choose the path
- Use path A when ...
- Use path B when ...
### 3. Execute
- Step 1
- Step 2
- Step 3
### 4. Validate
- Minimum acceptance checks
## Reference Map
- Read `[topic-a](references/topic-a.md)` when ...
- Read `[topic-b](references/topic-b.md)` when ...
```
## Optional Folders
Create only when justified:
- `agents/interface.yaml`
- `references/`
- `scripts/`
- `assets/`
- `evals/`
## agents/interface.yaml Template
```yaml
interface:
display_name: "Human Friendly Name"
short_description: "Short capability summary"
default_prompt: "Use $skill-name to ..."
compatibility:
canonical_format: "agent-skills"
adapter_targets:
- "openai"
- "claude"
- "generic"
```
+67
View File
@@ -0,0 +1,67 @@
# Skill Design Guidelines
This document captures the operating rules for `yao-meta-skill`.
## 1. Treat Skill Creation As Product Design
A generated skill should answer these questions clearly:
- What exact recurring job does this package improve?
- Who is the intended user or agent?
- What is in scope and out of scope?
- What should be stable across runs?
- What is expected to evolve over time?
## 2. Separate Three Kinds Of Content
Put each kind of content in the right place:
- `SKILL.md`: core workflow, trigger surface, decision rules
- `references/`: detailed domain material, examples, schemas, policy docs
- `scripts/`: deterministic or brittle operations
If you mix all three into `SKILL.md`, quality and maintainability drop fast.
## 3. Use A Trigger Matrix
Every important skill should have a trigger matrix:
- positive prompts
- clear negatives
- near neighbors
The goal is not just "can it trigger", but "does it trigger at the right boundary".
## 4. Keep The Body Small On Purpose
Do not optimize only for completeness.
Optimize for:
- low context cost
- clear branch selection
- discoverable references
- safe defaults
## 5. Add Lifecycle Metadata Only When It Helps
For personal or disposable skills, extra metadata can be noise.
For shared skills, a `manifest.json` is useful for:
- owner
- version
- updated_at
- target platforms
- review cadence
## 6. Prefer Progressive Industrialization
Move through these stages:
1. Working draft
2. Trigger-hardened draft
3. Reusable team skill
4. Governed skill asset
Do not start every skill at stage 4.
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
import argparse
import json
from pathlib import Path
TEXT_EXTS = {".md", ".txt", ".yaml", ".yml", ".json", ".py", ".sh", ".js", ".ts"}
def estimate_tokens(text: str) -> int:
# Fast heuristic suitable for local gating.
return max(1, len(text) // 4)
def read_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8")
except UnicodeDecodeError:
return path.read_text(encoding="utf-8", errors="ignore")
def classify(path: Path) -> str:
parts = set(path.parts)
if path.name == "SKILL.md":
return "skill_body"
if "references" in parts:
return "reference"
if "scripts" in parts:
return "script"
if "assets" in parts:
return "asset"
if path.suffix in TEXT_EXTS:
return "other_text"
return "binary_or_other"
def summarize(skill_dir: Path) -> dict:
files = []
total_tokens = 0
initial_tokens = 0
for path in sorted(skill_dir.rglob("*")):
if not path.is_file():
continue
kind = classify(path)
if kind in {"binary_or_other", "asset"} and path.suffix not in TEXT_EXTS:
size = path.stat().st_size
files.append({"path": str(path.relative_to(skill_dir)), "kind": kind, "bytes": size})
continue
text = read_text(path)
tokens = estimate_tokens(text)
record = {
"path": str(path.relative_to(skill_dir)),
"kind": kind,
"chars": len(text),
"estimated_tokens": tokens,
}
files.append(record)
total_tokens += tokens
if kind in {"skill_body", "other_text"}:
initial_tokens += tokens
return {
"skill_dir": str(skill_dir),
"estimated_initial_load_tokens": initial_tokens,
"estimated_total_text_tokens": total_tokens,
"warning": initial_tokens > 2000,
"files": files,
}
def main() -> None:
parser = argparse.ArgumentParser(description="Estimate context size for a skill package.")
parser.add_argument("skill_dir", help="Path to the skill directory")
parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON")
args = parser.parse_args()
report = summarize(Path(args.skill_dir).resolve())
if args.json:
print(json.dumps(report, ensure_ascii=False, indent=2))
return
print(f"Skill: {report['skill_dir']}")
print(f"Estimated initial-load tokens: {report['estimated_initial_load_tokens']}")
print(f"Estimated total text tokens: {report['estimated_total_text_tokens']}")
print(f"Initial-load warning (>2000): {'YES' if report['warning'] else 'NO'}")
print("")
for file in report["files"]:
if "estimated_tokens" in file:
print(f"{file['kind']:12} {file['estimated_tokens']:6}t {file['path']}")
else:
print(f"{file['kind']:12} {file['bytes']:6}b {file['path']}")
if __name__ == "__main__":
main()
+171
View File
@@ -0,0 +1,171 @@
#!/usr/bin/env python3
import argparse
import json
import shutil
import zipfile
from pathlib import Path
def read_simple_yaml(path: Path) -> dict:
lines = path.read_text(encoding="utf-8").splitlines()
data: dict = {}
stack: list[tuple[int, dict]] = [(0, data)]
for raw_line in lines:
if not raw_line.strip() or raw_line.lstrip().startswith("#"):
continue
indent = len(raw_line) - len(raw_line.lstrip(" "))
line = raw_line.strip()
while len(stack) > 1 and indent <= stack[-1][0]:
stack.pop()
parent = stack[-1][1]
if line.startswith("- "):
item = line[2:].strip().strip("'\"")
existing = parent.setdefault("__list__", [])
existing.append(item)
continue
if ":" not in line:
continue
key, value = line.split(":", 1)
key = key.strip()
value = value.strip()
if value == "":
child: dict = {}
parent[key] = child
stack.append((indent, child))
else:
parent[key] = value.strip("'\"")
return data
def read_frontmatter(skill_md: Path) -> dict:
text = skill_md.read_text(encoding="utf-8")
if not text.startswith("---"):
return {}
parts = text.split("---", 2)
if len(parts) < 3:
return {}
data = {}
for line in parts[1].splitlines():
if ":" not in line:
continue
key, value = line.split(":", 1)
data[key.strip()] = value.strip().strip("'\"")
return data
def read_interface(skill_dir: Path) -> dict:
path = skill_dir / "agents" / "interface.yaml"
if not path.exists():
return {}
raw = read_simple_yaml(path)
compatibility = raw.get("compatibility", {})
targets = compatibility.get("adapter_targets", {})
if isinstance(targets, dict) and "__list__" in targets:
compatibility["adapter_targets"] = targets["__list__"]
raw["compatibility"] = compatibility
return raw
def build_manifest(skill_dir: Path, platform: str) -> dict:
frontmatter = read_frontmatter(skill_dir / "SKILL.md")
interface = read_interface(skill_dir).get("interface", {})
compatibility = read_interface(skill_dir).get("compatibility", {})
return {
"name": frontmatter.get("name", skill_dir.name),
"description": frontmatter.get("description", ""),
"version": frontmatter.get("version", "1.0.0"),
"platform": platform,
"skill_root": skill_dir.name,
"display_name": interface.get("display_name", skill_dir.name),
"short_description": interface.get("short_description", ""),
"default_prompt": interface.get("default_prompt", ""),
"canonical_metadata": "agents/interface.yaml",
"adapter_targets": compatibility.get("adapter_targets", []),
}
def write_yaml_like(path: Path, payload: dict) -> None:
interface = payload.get("interface", {})
lines = ["interface:"]
for key in ("display_name", "short_description", "default_prompt"):
value = interface.get(key, "")
lines.append(f' {key}: "{value}"')
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
def write_adapter(skill_dir: Path, out_dir: Path, platform: str) -> Path:
target_dir = out_dir / "targets" / platform
target_dir.mkdir(parents=True, exist_ok=True)
payload = build_manifest(skill_dir, platform)
if platform == "openai":
meta_dir = target_dir / "agents"
meta_dir.mkdir(parents=True, exist_ok=True)
write_yaml_like(
meta_dir / "openai.yaml",
{
"interface": {
"display_name": payload["display_name"],
"short_description": payload["short_description"],
"default_prompt": payload["default_prompt"],
}
},
)
payload["install_hint"] = f"Use the packaged skill and include targets/openai/agents/openai.yaml when the client expects OpenAI-style interface metadata."
elif platform == "claude":
notes = target_dir / "README.md"
notes.write_text(
f"# Claude-Compatible Package\n\nUse `{skill_dir.name}` with its neutral source files. This target does not require vendor metadata by default.\n",
encoding="utf-8",
)
payload["install_hint"] = f"Use the packaged skill directly; this target relies on SKILL.md and optional neutral metadata."
else:
payload["install_hint"] = f"Use {skill_dir.name} as an Agent Skills compatible package."
path = target_dir / "adapter.json"
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
return path
def make_zip(skill_dir: Path, out_dir: Path) -> Path:
zip_path = out_dir / f"{skill_dir.name}.zip"
with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
for path in skill_dir.rglob("*"):
if path.is_file():
zf.write(path, arcname=str(path.relative_to(skill_dir.parent)))
return zip_path
def copy_manifest(skill_dir: Path, out_dir: Path) -> Path:
manifest_path = out_dir / "manifest.json"
manifest_path.write_text(
json.dumps(build_manifest(skill_dir, "generic"), ensure_ascii=False, indent=2),
encoding="utf-8",
)
return manifest_path
def main() -> None:
parser = argparse.ArgumentParser(description="Generate lightweight cross-platform packaging artifacts.")
parser.add_argument("skill_dir", help="Path to the skill directory")
parser.add_argument("--platform", action="append", default=[], help="Target platform: openai, claude, generic")
parser.add_argument("--output-dir", default="dist", help="Output directory")
parser.add_argument("--zip", action="store_true", help="Create a zip package")
args = parser.parse_args()
skill_dir = Path(args.skill_dir).resolve()
out_dir = Path(args.output_dir).resolve()
if out_dir.exists():
shutil.rmtree(out_dir)
out_dir.mkdir(parents=True)
manifest = copy_manifest(skill_dir, out_dir)
generated = [str(manifest)]
for platform in (args.platform or ["generic"]):
generated.append(str(write_adapter(skill_dir, out_dir, platform)))
if args.zip:
generated.append(str(make_zip(skill_dir, out_dir)))
print(json.dumps({"output_dir": str(out_dir), "generated": generated}, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
import argparse
import json
import re
from pathlib import Path
WORD_RE = re.compile(r"[a-zA-Z0-9][a-zA-Z0-9_-]*")
def words(text: str) -> set[str]:
return {w.lower() for w in WORD_RE.findall(text)}
def load_cases(path: Path) -> dict:
return json.loads(path.read_text(encoding="utf-8"))
def extract_description(text: str) -> str:
if not text.startswith("---"):
return text
parts = text.split("---", 2)
if len(parts) < 3:
return text
frontmatter = parts[1].splitlines()
for line in frontmatter:
if line.strip().startswith("description:"):
return line.split(":", 1)[1].strip().strip("'\"")
return text
def score_prompt(description_words: set[str], prompt: str) -> float:
prompt_words = words(prompt)
if not prompt_words:
return 0.0
overlap = description_words & prompt_words
return len(overlap) / len(prompt_words)
def evaluate(description: str, cases: dict, threshold: float) -> dict:
desc_words = words(description)
results = {"should_trigger": [], "should_not_trigger": []}
fp = 0
fn = 0
for bucket in ("should_trigger", "should_not_trigger"):
for prompt in cases.get(bucket, []):
score = score_prompt(desc_words, prompt)
predicted = score >= threshold
expected = bucket == "should_trigger"
passed = predicted == expected
if not passed and expected:
fn += 1
if not passed and not expected:
fp += 1
results[bucket].append(
{
"prompt": prompt,
"score": round(score, 3),
"predicted_trigger": predicted,
"passed": passed,
}
)
return {
"threshold": threshold,
"false_positives": fp,
"false_negatives": fn,
"results": results,
}
def main() -> None:
parser = argparse.ArgumentParser(description="Heuristic trigger quality evaluator.")
parser.add_argument("--description", help="Description string to evaluate")
parser.add_argument("--description-file", help="Read description text from file")
parser.add_argument("--cases", required=True, help="JSON file with should_trigger and should_not_trigger arrays")
parser.add_argument("--threshold", type=float, default=0.18, help="Token overlap threshold")
args = parser.parse_args()
description = args.description
if args.description_file:
description = extract_description(Path(args.description_file).read_text(encoding="utf-8"))
if not description:
raise SystemExit("Provide --description or --description-file")
report = evaluate(description, load_cases(Path(args.cases)), args.threshold)
print(json.dumps(report, ensure_ascii=False, indent=2))
if report["false_positives"] > 2:
raise SystemExit(2)
if __name__ == "__main__":
main()
+42
View File
@@ -0,0 +1,42 @@
---
name: {{ skill_name }}
description: {{ description }}
metadata:
author: {{ author }}
---
# {{ title }}
{{ summary }}
## When To Use This Skill
{% for item in when_to_use %}
- {{ item }}
{% endfor %}
## Workflow
### 1. Understand the request
{% for item in understand_steps %}
- {{ item }}
{% endfor %}
### 2. Execute
{% for item in execute_steps %}
- {{ item }}
{% endfor %}
### 3. Validate
{% for item in validate_steps %}
- {{ item }}
{% endfor %}
## Reference Map
{% for item in reference_map %}
- {{ item }}
{% endfor %}
+61
View File
@@ -0,0 +1,61 @@
---
name: {{ skill_name }}
description: {{ description }}
metadata:
author: {{ author }}
version: {{ version }}
---
# {{ title }}
{{ summary }}
## When To Use This Skill
{% for item in when_to_use %}
- {{ item }}
{% endfor %}
## Operating Contract
- Primary output: {{ primary_output }}
- Main tools or systems: {{ tools_summary }}
- Failure tolerance: {{ failure_tolerance }}
## Workflow
### 1. Intake
{% for item in intake_steps %}
- {{ item }}
{% endfor %}
### 2. Choose the path
{% for item in routing_steps %}
- {{ item }}
{% endfor %}
### 3. Execute
{% for item in execute_steps %}
- {{ item }}
{% endfor %}
### 4. Validate
{% for item in validate_steps %}
- {{ item }}
{% endfor %}
## Bundled Resources
- Read `references/` when domain-specific detail or long examples are needed.
- Use `scripts/` when deterministic or repetitive steps should not be re-authored in prose.
- Use `assets/` for templates or output artifacts, not instructions.
## Reference Map
{% for item in reference_map %}
- {{ item }}
{% endfor %}