TokenToSea提示词广场
English 控制台

Skill Creator 技能创建指南

智能体与系统提示·系统提示 / 角色

在聊天中使用

指导创建或更新 Claude 技能,包括技能结构、附带资源、SKILL.md 写法以及初始化与打包脚本。

---
name: skill-creator
description: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
license: Complete terms in LICENSE.txt
---

# Skill Creator

本技能提供创建高效技能的指导。

## 关于技能

技能是模块化、自包含的包,通过提供专门知识、工作流程和工具来扩展 Claude 的能力。可以将它们视为特定领域或任务的“入职指南”——它们将 Claude 从通用代理转变为具备程序性知识的专用代理,而这些知识是任何模型都无法完全拥有的。

### 技能提供的内容

1. 专门的工作流程 - 针对特定领域的多步骤流程
2. 工具集成 - 用于处理特定文件格式或 API 的说明
3. 领域专长 - 公司特定的知识、模式、业务逻辑
4. 捆绑资源 - 用于复杂和重复任务的脚本、参考和资源

## 核心原则

### 简洁为王

上下文窗口是一种公共资源。技能需要与系统提示、对话历史、其他技能的元数据以及实际用户请求共享上下文窗口。

**默认假设:Claude 已经非常聪明。** 仅添加 Claude 尚未掌握的上下文。对每一条信息提出质疑:“Claude 真的需要这个解释吗?”以及“这段文字是否值得其消耗的 token 成本?”

优先使用简洁的示例,而非冗长的解释。

### 设定适当的自由度

根据任务的脆弱性和可变性来匹配具体程度:

**高自由度(基于文本的说明)**:当多种方法都有效、决策依赖于上下文或方法由启发式规则引导时使用。

**中等自由度(带参数的伪代码或脚本)**:当存在首选模式、可接受一定程度的变化或配置影响行为时使用。

**低自由度(具体脚本,少量参数)**:当操作脆弱且容易出错、一致性至关重要或必须遵循特定顺序时使用。

将 Claude 想象为在一条路径上探索:狭窄的桥上有悬崖需要具体的护栏(低自由度),而开阔的田野允许多种路线(高自由度)。

### 技能的构成

每个技能包含一个必需的 SKILL.md 文件和可选的捆绑资源:

```
skill-name/
├── SKILL.md (required)
│   ├── YAML frontmatter metadata (required)
│   │   ├── name: (required)
│   │   └── description: (required)
│   └── Markdown instructions (required)
└── Bundled Resources (optional)
    ├── scripts/          - Executable code (Python/Bash/etc.)
    ├── references/       - Documentation intended to be loaded into context as needed
    └── assets/           - Files used in output (templates, icons, fonts, etc.)
```

#### SKILL.md(必需)

每个 SKILL.md 包含:

- **前置内容**(YAML):包含 `name` 和 `description` 字段。这些是 Claude 用于判断何时使用该技能的唯一字段,因此清晰全面地描述技能内容及其使用场景非常重要。
- **正文**(Markdown):使用该技能的说明和指导。仅在技能触发后(如果有的话)才会加载。

#### 捆绑资源(可选)

##### 脚本(`scripts/`)

用于需要确定性可靠性或反复重写的任务的可执行代码(Python/Bash 等)。

- **何时包含**:当相同代码被反复重写或需要确定性可靠性时
- **示例**:用于 PDF 旋转任务的 `scripts/rotate_pdf.py`
- **优点**:节省 token,具有确定性,可能无需加载到上下文中即可执行
- **注意**:脚本仍可能需要被 Claude 读取以进行修补或环境特定调整
##### 参考资料 (`references/`)

旨在根据需要加载到上下文中的文档和参考资料,用于指导 Claude 的处理和思考过程。

- **何时包含**:当 Claude 在工作过程中需要参考文档时
- **示例**:`references/finance.md` 用于财务模式,`references/mnda.md` 用于公司 NDA 模板,`references/policies.md` 用于公司政策,`references/api_docs.md` 用于 API 规范
- **使用场景**:数据库模式、API 文档、领域知识、公司政策、详细工作流程指南
- **优势**:保持 SKILL.md 简洁,仅在 Claude 判断需要时才加载
- **最佳实践**:如果文件较大(>10k 词),请在 SKILL.md 中包含 grep 搜索模式
- **避免重复**:信息应仅存在于 SKILL.md 或参考资料文件中,不可两者同时存在。

##### 资源文件 (`assets/`)

不打算加载到上下文中的文件,而是用于 Claude 生成的输出内容中。

- **何时包含**:当技能需要在最终输出中使用的文件时
- **示例**:`assets/logo.png` 用于品牌资产,`assets/slides.pptx` 用于 PowerPoint 模板
- **使用场景**:模板、图像、图标、样板代码、字体、示例文档

### 渐进式披露设计原则

技能采用三级加载系统,以高效管理上下文:

1. **元数据(名称 + 描述)** - 始终在上下文中(约 100 词)
2. **SKILL.md 正文** - 技能触发时加载(<5k 词)
3. **捆绑资源** - 由 Claude 按需加载

请将 SKILL.md 正文控制在核心内容范围内,并少于 500 行,以尽量减少上下文膨胀。

## 技能创建流程

技能创建包含以下步骤:

1. 使用具体示例理解技能
2. 规划可复用的技能内容(脚本、参考资料、资源文件)
3. 初始化技能(运行 init_skill.py)
4. 编辑技能(实现资源并编写 SKILL.md)
5. 打包技能(运行 package_skill.py)
6. 根据实际使用情况迭代优化

### 第 3 步:初始化技能

从零开始创建新技能时,始终运行 `init_skill.py` 脚本:

```bash
scripts/init_skill.py <skill-name> --path <output-directory>
```

### 第 4 步:编辑技能

根据您的技能需求,参考以下有用指南:

- **多步骤流程**:参见 references/workflows.md 了解顺序工作流和条件逻辑
- **特定输出格式或质量标准**:参见 references/output-patterns.md 了解模板和示例模式

### 第 5 步:打包技能

```bash
scripts/package_skill.py <path/to/skill-folder>
```

打包脚本将验证并生成用于分发的 .skill 文件。
FILE:references/workflows.md
# 工作流模式

## 顺序工作流

对于复杂任务,将操作分解为清晰的顺序步骤。通常在 SKILL.md 开头部分向 Claude 提供流程概览会很有帮助:

```markdown
Filling a PDF form involves these steps:

1. Analyze the form (run analyze_form.py)
2. Create field mapping (edit fields.json)
3. Validate mapping (run validate_fields.py)
4. Fill the form (run fill_form.py)
5. Verify output (run verify_output.py)
```

## 条件工作流

对于具有分支逻辑的任务,请引导 Claude 经历各个决策点:

```markdown
1. Determine the modification type:
   **Creating new content?** → Follow "Creation workflow" below
   **Editing existing content?** → Follow "Editing workflow" below

2. Creation workflow: [steps]
3. Editing workflow: [steps]
```
FILE:references/output-patterns.md
# 输出模式

当技能需要生成一致且高质量的输出时,请使用以下模式。

## 模板模式

为输出格式提供模板。根据您的需求匹配严格的程度。

**对于严格要求(如 API 响应或数据格式):**

```markdown
## Report structure

ALWAYS use this exact template structure:

# [Analysis Title]

## Executive summary
[One-paragraph overview of key findings]

## Key findings
- Finding 1 with supporting data
- Finding 2 with supporting data
- Finding 3 with supporting data

## Recommendations
1. Specific actionable recommendation
2. Specific actionable recommendation
```

**对于灵活指导(当需要适应性时):**

```markdown
## Report structure

Here is a sensible default format, but use your best judgment:

# [Analysis Title]

## Executive summary
[Overview]

## Key findings
[Adapt sections based on what you discover]

## Recommendations
[Tailor to the specific context]

Adjust sections as needed for the specific analysis type.
```

## 示例模式

对于输出质量依赖于示例的技能,请提供输入/输出配对示例:

```markdown
## Commit message format

Generate commit messages following these examples:

**Example 1:**
Input: Added user authentication with JWT tokens
Output:
```
添加登录端点和令牌验证中间件
```

**Example 2:**
Input: Fixed bug where dates displayed incorrectly in reports
Output:
```
fix(reports): 修正时区转换中的日期格式

在报告生成过程中始终使用 UTC 时间戳
```

Follow this style: type(scope): brief description, then detailed explanation.
```

示例比单纯的描述更能帮助 Claude 清晰理解所需的风格和细节程度。
FILE:scripts/quick_validate.py
#!/usr/bin/env python3
"""
Quick validation script for skills - minimal version
"""

import sys
import os
import re
import yaml
from pathlib import Path

def validate_skill(skill_path):
    """Basic validation of a skill"""
    skill_path = Path(skill_path)

    # Check SKILL.md exists
    skill_md = skill_path / 'SKILL.md'
    if not skill_md.exists():
        return False, "SKILL.md not found"

    # Read and validate frontmatter
    content = skill_md.read_text()
    if not content.startswith('---'):
        return False, "No YAML frontmatter found"

    # Extract frontmatter
    match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
    if not match:
        return False, "Invalid frontmatter format"

    frontmatter_text = match.group(1)

    # Parse YAML frontmatter
    try:
        frontmatter = yaml.safe_load(frontmatter_text)
        if not isinstance(frontmatter, dict):
            return False, "Frontmatter must be a YAML dictionary"
    except yaml.YAMLError as e:
        return False, f"Invalid YAML in frontmatter: {e}"

    # Define allowed properties
    ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata'}

    # Check for unexpected properties (excluding nested keys under metadata)
    unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
    if unexpected_keys:
        return False, (
            f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. "
            f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}"
        )

    # Check required fields
    if 'name' not in frontmatter:
        return False, "Missing 'name' in frontmatter"
    if 'description' not in frontmatter:
        return False, "Missing 'description' in frontmatter"

    # Extract name for validation
    name = frontmatter.get('name', '')
    if not isinstance(name, str):
        return False, f"Name must be a string, got {type(name).__name__}"
    name = name.strip()
    if name:
        # Check naming convention (hyphen-case: lowercase with hyphens)
        if not re.match(r'^[a-z0-9-]+$', name):
            return False, f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)"
        if name.startswith('-') or name.endswith('-') or '--' in name:
            return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens"
        # Check name length (max 64 characters per spec)
        if len(name) > 64:
            return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters."

    # Extract and validate description
    description = frontmatter.get('description', '')
    if not isinstance(description, str):
        return False, f"Description must be a string, got {type(description).__name__}"
    description = description.strip()
    if description:
        # Check for angle brackets
        if '<' in description or '>' in description:
            return False, "Description cannot contain angle brackets (< or >)"
        # Check description length (max 1024 characters per spec)
        if len(description) > 1024

    try:
        scripts_dir = skill_dir / 'scripts'
        scripts_dir.mkdir(exist_ok=True)
        example_script = scripts_dir / 'example.py'
        example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name))
        example_script.chmod(0o755)
        print("✅ Created scripts/example.py")

        references_dir = skill_dir / 'references'
        references_dir.mkdir(exist_ok=True)
        example_reference = references_dir / 'api_reference.md'
        example_reference.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title))
        print("✅ Created references/api_reference.md")

        assets_dir = skill_dir / 'assets'
        assets_dir.mkdir(exist_ok=True)
        example_asset = assets_dir / 'example_asset.txt'
        example_asset.write_text(EXAMPLE_ASSET)
        print("✅ Created assets/example_asset.txt")
    except Exception as e:
        print(f"❌ Error creating resource directories: {e}")
        return None

    print(f"\n✅ Skill '{skill_name}' initialized successfully at {skill_dir}")
    return skill_dir


def main():
    if len(sys.argv) < 4 or sys.argv[2] != '--path':
        print("Usage: init_skill.py <skill-name> --path <path>")
        sys.exit(1)

    skill_name = sys.argv[1]
    path = sys.argv[3]

    print(f"🚀 Initializing skill: {skill_name}")
    print(f"   Location: {path}")
    print()

    result = init_skill(skill_name, path)
    sys.exit(0 if result else 1)


if __name__ == "__main__":
    main()
FILE:scripts/package_skill.py
#!/usr/bin/env python3
"""
Skill Packager - Creates a distributable .skill file of a skill folder

Usage:
    python utils/package_skill.py <path/to/skill-folder> [output-directory]

Example:
    python utils/package_skill.py skills/public/my-skill
    python utils/package_skill.py skills/public/my-skill ./dist
"""

import sys
import zipfile
from pathlib import Path
from quick_validate import validate_skill


def package_skill(skill_path, output_dir=None):
    """Package a skill folder into a .skill file."""
    skill_path = Path(skill_path).resolve()

    if not skill_path.exists():
        print(f"❌ Error: Skill folder not found: {skill_path}")
        return None

    if not skill_path.is_dir():
        print(f"❌ Error: Path is not a directory: {skill_path}")
        return None

    skill_md = skill_path / "SKILL.md"
    if not skill_md.exists():
        print(f"❌ Error: SKILL.md not found in {skill_path}")
        return None

    print("🔍 Validating skill...")
    valid, message = validate_skill(skill_path)
    if not valid:
        print(f"❌ Validation failed: {message}")
        print("   Please fix the validation errors before packaging.")
        return None
    print(f"✅ {message}\n")

    skill_name = skill_path.name
    if output_dir:
        output_path = Path(output_dir).resolve()
        output_path.mkdir(parents=True, exist_ok=True)
    else:
        output_path = Path.cwd()

    skill_filename = output_path / f"{skill_name}.skill"

    try:
        with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
            for file_path in skill_path.rglob('*'):
                if file_path.is_file():
                    arcname = file_path.relative_to(skill_path.parent)
                    zipf.write(file_path, arcname)
                    print(f"  Added: {arcname}")

        print(f"\n✅ Successfully packaged skill to: {skill_filename}")
        return skill_filename

    except Exception as e:
        print(f"❌ 创建 .skill 文件时出错:{e}")
        return None


def main():
    if len(sys.argv) < 2:
        print("用法: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
        sys.exit(1)

    skill_path = sys.argv[1]
    output_dir = sys.argv[2] if len(sys.argv) > 2 else None

    print(f"📦 正在打包技能:{skill_path}")
    if output_dir:
        print(f"   输出目录:{output_dir}")
    print()

    result = package_skill(skill_path, output_dir)
    sys.exit(0 if result else 1)


if __name__ == "__main__":
    main()