欢迎光临
我们一直在努力

OpenClaw 技能开发教程:从入门到发布

摘要

OpenClaw 的技能(Skills)系统是其生态的核心组成部分,允许开发者扩展 AI 助手的能力边界。本文将详细介绍 Skills 的架构设计、开发流程、测试方法和发布规范。通过完整的实战案例,帮助开发者掌握从零开始创建高质量 Skill 的全过程,并了解如何将其发布到 ClawHub 技能市场供全球用户使用。

关键词:OpenClaw、Skills 开发、插件系统、ClawHub、AI 扩展


目录

  • 一、引言
  • [二、Skills 系统架构](#二 skills 系统架构)
  • [三、Skill 类型与选择](#三 skill 类型与选择)
  • 四、开发环境搭建
  • [五、SKILL.md 规范详解](#五 skillmd 规范详解)
  • [六、第一个 Skill 开发](#六第一个 skill 开发)
  • [七、高级 Skill 开发技巧](#七高级 skill 开发技巧)
  • 八、测试与调试
  • [九、发布到 ClawHub](#九发布到 clawhub)
  • [十、Skill 运营与推广](#十 skill 运营与推广)
  • 总结
  • 参考资料

一、引言

1.1 为什么需要 Skills?

虽然 OpenClaw 内置了丰富的工具,但面对无限的应用场景,我们需要:

  • 领域专业化:医疗、法律、金融等垂直领域需要专门知识
  • 服务集成:对接第三方 API(GitHub、Notion、Slack 等)
  • 工作流自动化:封装复杂的业务流程
  • 社区共建:开发者贡献自己的独特能力

Skills 系统正是为此而生,它让每个开发者都能:

  • ✅ 扩展 AI 的能力边界
  • ✅ 分享自己的专业知识和工具
  • ✅ 构建可复用的功能模块
  • ✅ 甚至创建个人品牌或商业模式
  • 1.2 Skills 生态系统

    #mermaid-svg-Sr9AmWUjwN28G5hZ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Sr9AmWUjwN28G5hZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Sr9AmWUjwN28G5hZ .error-icon{fill:#552222;}#mermaid-svg-Sr9AmWUjwN28G5hZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Sr9AmWUjwN28G5hZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Sr9AmWUjwN28G5hZ .marker.cross{stroke:#333333;}#mermaid-svg-Sr9AmWUjwN28G5hZ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Sr9AmWUjwN28G5hZ p{margin:0;}#mermaid-svg-Sr9AmWUjwN28G5hZ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Sr9AmWUjwN28G5hZ .cluster-label text{fill:#333;}#mermaid-svg-Sr9AmWUjwN28G5hZ .cluster-label span{color:#333;}#mermaid-svg-Sr9AmWUjwN28G5hZ .cluster-label span p{background-color:transparent;}#mermaid-svg-Sr9AmWUjwN28G5hZ .label text,#mermaid-svg-Sr9AmWUjwN28G5hZ span{fill:#333;color:#333;}#mermaid-svg-Sr9AmWUjwN28G5hZ .node rect,#mermaid-svg-Sr9AmWUjwN28G5hZ .node circle,#mermaid-svg-Sr9AmWUjwN28G5hZ .node ellipse,#mermaid-svg-Sr9AmWUjwN28G5hZ .node polygon,#mermaid-svg-Sr9AmWUjwN28G5hZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Sr9AmWUjwN28G5hZ .rough-node .label text,#mermaid-svg-Sr9AmWUjwN28G5hZ .node .label text,#mermaid-svg-Sr9AmWUjwN28G5hZ .image-shape .label,#mermaid-svg-Sr9AmWUjwN28G5hZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-Sr9AmWUjwN28G5hZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Sr9AmWUjwN28G5hZ .rough-node .label,#mermaid-svg-Sr9AmWUjwN28G5hZ .node .label,#mermaid-svg-Sr9AmWUjwN28G5hZ .image-shape .label,#mermaid-svg-Sr9AmWUjwN28G5hZ .icon-shape .label{text-align:center;}#mermaid-svg-Sr9AmWUjwN28G5hZ .node.clickable{cursor:pointer;}#mermaid-svg-Sr9AmWUjwN28G5hZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Sr9AmWUjwN28G5hZ .arrowheadPath{fill:#333333;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Sr9AmWUjwN28G5hZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Sr9AmWUjwN28G5hZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Sr9AmWUjwN28G5hZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Sr9AmWUjwN28G5hZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Sr9AmWUjwN28G5hZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Sr9AmWUjwN28G5hZ .cluster text{fill:#333;}#mermaid-svg-Sr9AmWUjwN28G5hZ .cluster span{color:#333;}#mermaid-svg-Sr9AmWUjwN28G5hZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Sr9AmWUjwN28G5hZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Sr9AmWUjwN28G5hZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-Sr9AmWUjwN28G5hZ .icon-shape,#mermaid-svg-Sr9AmWUjwN28G5hZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Sr9AmWUjwN28G5hZ .icon-shape p,#mermaid-svg-Sr9AmWUjwN28G5hZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Sr9AmWUjwN28G5hZ .icon-shape rect,#mermaid-svg-Sr9AmWUjwN28G5hZ .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Sr9AmWUjwN28G5hZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Sr9AmWUjwN28G5hZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Sr9AmWUjwN28G5hZ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    技能类型

    技能消费者

    技能平台

    技能提供者

    官方团队

    认证开发者

    社区贡献者

    ClawHub 市场

    评论系统

    评分系统

    个人用户

    企业用户

    教育机构

    Bundled Skills

    Managed Skills

    Workspace Skills

    1.3 本文你将学到

    • ✅ Skills 的三种类型及其适用场景
    • ✅ 完整的开发环境和工具链配置
    • ✅ SKILL.md 文档规范和最佳实践
    • ✅ 从零开发一个实用的 Skill
    • ✅ 测试、打包、发布的完整流程
    • ✅ Skill 运营和推广策略

    二、Skills 系统架构

    2.1 Skill 目录结构

    一个标准的 Skill 包含以下文件:

    my-skill/
    ├── SKILL.md # 技能描述文档(必需)
    ├── icon.png # 技能图标(推荐)
    ├── screenshot.png # 截图(推荐)
    ├── manifest.json # 清单文件(可选)
    ├── src/ # 源代码目录
    │ ├── __init__.py
    │ ├── main.py # 主入口
    │ └── utils.py # 工具函数
    ├── tests/ # 测试代码
    │ ├── test_main.py
    │ └── fixtures/ # 测试数据
    ├── requirements.txt # Python 依赖
    ├── package.json # Node.js 依赖(如果有)
    └── README.md # 详细文档

    2.2 Skill 生命周期

    #mermaid-svg-i5ifgv4IdXJBzgIB{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-i5ifgv4IdXJBzgIB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-i5ifgv4IdXJBzgIB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-i5ifgv4IdXJBzgIB .error-icon{fill:#552222;}#mermaid-svg-i5ifgv4IdXJBzgIB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-i5ifgv4IdXJBzgIB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-i5ifgv4IdXJBzgIB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-i5ifgv4IdXJBzgIB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-i5ifgv4IdXJBzgIB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-i5ifgv4IdXJBzgIB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-i5ifgv4IdXJBzgIB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-i5ifgv4IdXJBzgIB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-i5ifgv4IdXJBzgIB .marker.cross{stroke:#333333;}#mermaid-svg-i5ifgv4IdXJBzgIB svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-i5ifgv4IdXJBzgIB p{margin:0;}#mermaid-svg-i5ifgv4IdXJBzgIB .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-i5ifgv4IdXJBzgIB .cluster-label text{fill:#333;}#mermaid-svg-i5ifgv4IdXJBzgIB .cluster-label span{color:#333;}#mermaid-svg-i5ifgv4IdXJBzgIB .cluster-label span p{background-color:transparent;}#mermaid-svg-i5ifgv4IdXJBzgIB .label text,#mermaid-svg-i5ifgv4IdXJBzgIB span{fill:#333;color:#333;}#mermaid-svg-i5ifgv4IdXJBzgIB .node rect,#mermaid-svg-i5ifgv4IdXJBzgIB .node circle,#mermaid-svg-i5ifgv4IdXJBzgIB .node ellipse,#mermaid-svg-i5ifgv4IdXJBzgIB .node polygon,#mermaid-svg-i5ifgv4IdXJBzgIB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-i5ifgv4IdXJBzgIB .rough-node .label text,#mermaid-svg-i5ifgv4IdXJBzgIB .node .label text,#mermaid-svg-i5ifgv4IdXJBzgIB .image-shape .label,#mermaid-svg-i5ifgv4IdXJBzgIB .icon-shape .label{text-anchor:middle;}#mermaid-svg-i5ifgv4IdXJBzgIB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-i5ifgv4IdXJBzgIB .rough-node .label,#mermaid-svg-i5ifgv4IdXJBzgIB .node .label,#mermaid-svg-i5ifgv4IdXJBzgIB .image-shape .label,#mermaid-svg-i5ifgv4IdXJBzgIB .icon-shape .label{text-align:center;}#mermaid-svg-i5ifgv4IdXJBzgIB .node.clickable{cursor:pointer;}#mermaid-svg-i5ifgv4IdXJBzgIB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-i5ifgv4IdXJBzgIB .arrowheadPath{fill:#333333;}#mermaid-svg-i5ifgv4IdXJBzgIB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-i5ifgv4IdXJBzgIB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-i5ifgv4IdXJBzgIB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i5ifgv4IdXJBzgIB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-i5ifgv4IdXJBzgIB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i5ifgv4IdXJBzgIB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-i5ifgv4IdXJBzgIB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-i5ifgv4IdXJBzgIB .cluster text{fill:#333;}#mermaid-svg-i5ifgv4IdXJBzgIB .cluster span{color:#333;}#mermaid-svg-i5ifgv4IdXJBzgIB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-i5ifgv4IdXJBzgIB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-i5ifgv4IdXJBzgIB rect.text{fill:none;stroke-width:0;}#mermaid-svg-i5ifgv4IdXJBzgIB .icon-shape,#mermaid-svg-i5ifgv4IdXJBzgIB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i5ifgv4IdXJBzgIB .icon-shape p,#mermaid-svg-i5ifgv4IdXJBzgIB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-i5ifgv4IdXJBzgIB .icon-shape rect,#mermaid-svg-i5ifgv4IdXJBzgIB .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i5ifgv4IdXJBzgIB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-i5ifgv4IdXJBzgIB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-i5ifgv4IdXJBzgIB :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    官方

    个人

    创建 Skill

    本地开发

    测试验证

    打包构建

    发布到哪里?

    ClawHub 审核

    工作区使用

    审核通过

    上架销售/免费

    自己使用

    用户安装

    手动更新

    自动更新

    2.3 Skill 运行时

    # Python 示例:Skill 运行时容器
    import importlib
    import json
    from pathlib import Path
    from typing import Any, Dict, Optional

    class SkillRuntime:
    def __init__(self, skill_path: str):
    self.skill_path = Path(skill_path)
    self.manifest = None
    self.instance = None
    self.metadata = {}

    def load(self):
    """加载 Skill"""
    print(f"正在加载 Skill: {self.skill_path}")

    # 1. 加载 SKILL.md
    skill_md_path = self.skill_path / "SKILL.md"
    if not skill_md_path.exists():
    raise FileNotFoundError("缺少 SKILL.md 文件")

    with open(skill_md_path, 'r', encoding='utf-8') as f:
    skill_md_content = f.read()

    # 2. 解析元数据(从 SKILL.md 提取)
    self.metadata = self._parse_skill_md(skill_md_content)

    # 3. 加载 manifest.json(如果存在)
    manifest_path = self.skill_path / "manifest.json"
    if manifest_path.exists():
    with open(manifest_path, 'r', encoding='utf-8') as f:
    self.manifest = json.load(f)

    # 4. 导入 Python 模块
    src_path = self.skill_path / "src"
    if src_path.exists():
    self._import_python_module(src_path)

    print(f"Skill 加载完成:{self.metadata.get('name', 'Unknown')}")
    return self

    def _parse_skill_md(self, content: str) > Dict:
    """解析 SKILL.md 提取元数据"""
    metadata = {}

    # 提取标题
    import re
    title_match = re.search(r'^#\\s+(.+)$', content, re.MULTILINE)
    if title_match:
    metadata['name'] = title_match.group(1).strip()

    # 提取描述
    desc_match = re.search(r'##\\s+Description\\s*\\n(.*?)(?=##|\\Z)', content, re.DOTALL)
    if desc_match:
    metadata['description'] = desc_match.group(1).strip()

    # 提取版本
    version_match = re.search(r'\\*\\*Version\\*\\*:\\s*(\\d+\\.\\d+\\.\\d+)', content)
    if version_match:
    metadata['version'] = version_match.group(1)

    # 提取作者
    author_match = re.search(r'\\*\\*Author\\*\\*:\\s*(.+)', content)
    if author_match:
    metadata['author'] = author_match.group(1).strip()

    return metadata

    def _import_python_module(self, src_path: Path):
    """导入 Python 模块"""
    import sys

    # 添加 src 到路径
    sys.path.insert(0, str(src_path))

    try:
    # 导入主模块
    main_module = importlib.import_module('main')

    # 查找主类
    if hasattr(main_module, 'SkillHandler'):
    self.instance = main_module.SkillHandler()
    print("Python SkillHandler 已实例化")
    else:
    print("警告:未找到 SkillHandler 类")

    finally:
    sys.path.remove(str(src_path))

    def execute(self, action: str, **kwargs) > Any:
    """执行 Skill 动作"""
    if not self.instance:
    raise RuntimeError("Skill 未初始化")

    if hasattr(self.instance, action):
    method = getattr(self.instance, action)
    return method(**kwargs)
    else:
    raise AttributeError(f"未知动作:{action}")

    # 使用示例
    runtime = SkillRuntime("./my-skill")
    runtime.load()

    # 执行技能功能
    result = runtime.execute("process_data", input="test")
    print(f"执行结果:{result}")


    三、Skill 类型与选择

    3.1 Bundled Skills(官方捆绑包)

    特点:

    • ✅ OpenClaw 官方开发和维护
    • ✅ 预装在系统中
    • ✅ 最高质量和安全性保证
    • ✅ 随系统更新自动升级

    适用场景:

    • 核心功能(GitHub、邮件处理、文件管理等)
    • 通用需求(天气查询、新闻推送、日历管理等)
    • 官方合作服务集成

    示例:

    bundled-skills/
    ├── github-integration/
    ├── email-handler/
    ├── file-manager/
    └── calendar-sync/

    3.2 Managed Skills(社区管理包)

    特点:

    • ✅ 社区开发者贡献
    • ✅ 通过 ClawHub 分发
    • ✅ 需要审核但有质量差异
    • ✅ 支持付费和免费模式

    适用场景:

    • 垂直领域应用(法律咨询、医疗建议)
    • 特定服务集成(Notion、Airtable)
    • 行业专用工具(电商分析、SEO 优化)

    提交流程:

    #mermaid-svg-CzNrg2hr8sK5kib7{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CzNrg2hr8sK5kib7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CzNrg2hr8sK5kib7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CzNrg2hr8sK5kib7 .error-icon{fill:#552222;}#mermaid-svg-CzNrg2hr8sK5kib7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CzNrg2hr8sK5kib7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CzNrg2hr8sK5kib7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CzNrg2hr8sK5kib7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CzNrg2hr8sK5kib7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CzNrg2hr8sK5kib7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CzNrg2hr8sK5kib7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CzNrg2hr8sK5kib7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CzNrg2hr8sK5kib7 .marker.cross{stroke:#333333;}#mermaid-svg-CzNrg2hr8sK5kib7 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CzNrg2hr8sK5kib7 p{margin:0;}#mermaid-svg-CzNrg2hr8sK5kib7 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-CzNrg2hr8sK5kib7 .cluster-label text{fill:#333;}#mermaid-svg-CzNrg2hr8sK5kib7 .cluster-label span{color:#333;}#mermaid-svg-CzNrg2hr8sK5kib7 .cluster-label span p{background-color:transparent;}#mermaid-svg-CzNrg2hr8sK5kib7 .label text,#mermaid-svg-CzNrg2hr8sK5kib7 span{fill:#333;color:#333;}#mermaid-svg-CzNrg2hr8sK5kib7 .node rect,#mermaid-svg-CzNrg2hr8sK5kib7 .node circle,#mermaid-svg-CzNrg2hr8sK5kib7 .node ellipse,#mermaid-svg-CzNrg2hr8sK5kib7 .node polygon,#mermaid-svg-CzNrg2hr8sK5kib7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CzNrg2hr8sK5kib7 .rough-node .label text,#mermaid-svg-CzNrg2hr8sK5kib7 .node .label text,#mermaid-svg-CzNrg2hr8sK5kib7 .image-shape .label,#mermaid-svg-CzNrg2hr8sK5kib7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-CzNrg2hr8sK5kib7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CzNrg2hr8sK5kib7 .rough-node .label,#mermaid-svg-CzNrg2hr8sK5kib7 .node .label,#mermaid-svg-CzNrg2hr8sK5kib7 .image-shape .label,#mermaid-svg-CzNrg2hr8sK5kib7 .icon-shape .label{text-align:center;}#mermaid-svg-CzNrg2hr8sK5kib7 .node.clickable{cursor:pointer;}#mermaid-svg-CzNrg2hr8sK5kib7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CzNrg2hr8sK5kib7 .arrowheadPath{fill:#333333;}#mermaid-svg-CzNrg2hr8sK5kib7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CzNrg2hr8sK5kib7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CzNrg2hr8sK5kib7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CzNrg2hr8sK5kib7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CzNrg2hr8sK5kib7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CzNrg2hr8sK5kib7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CzNrg2hr8sK5kib7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CzNrg2hr8sK5kib7 .cluster text{fill:#333;}#mermaid-svg-CzNrg2hr8sK5kib7 .cluster span{color:#333;}#mermaid-svg-CzNrg2hr8sK5kib7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CzNrg2hr8sK5kib7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CzNrg2hr8sK5kib7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-CzNrg2hr8sK5kib7 .icon-shape,#mermaid-svg-CzNrg2hr8sK5kib7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CzNrg2hr8sK5kib7 .icon-shape p,#mermaid-svg-CzNrg2hr8sK5kib7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CzNrg2hr8sK5kib7 .icon-shape rect,#mermaid-svg-CzNrg2hr8sK5kib7 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CzNrg2hr8sK5kib7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CzNrg2hr8sK5kib7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CzNrg2hr8sK5kib7 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    失败

    通过

    风险

    安全

    问题

    通过

    开发者提交

    格式检查

    返回修改

    安全扫描

    人工复审

    功能测试

    上架 ClawHub

    用户可见

    3.3 Workspace Skills(工作区自定义包)

    特点:

    • ✅ 用户自行开发或下载
    • ✅ 仅在当前工作区可用
    • ✅ 无需审核,灵活定制
    • ✅ 适合个人和企业内部使用

    适用场景:

    • 企业内部系统集成
    • 个人工作流自动化
    • 实验性功能测试
    • 敏感数据处理

    创建步骤:

    # 1. 创建工作区技能目录
    mkdir -p ~/.openclaw/workspace/skills/my-custom-skill

    # 2. 创建基本文件
    cd ~/.openclaw/workspace/skills/my-custom-skill
    touch SKILL.md
    touch src/main.py
    touch requirements.txt

    # 3. 编辑 SKILL.md
    cat > SKILL.md << 'EOF'
    # My Custom Skill

    ## Description
    个人定制的內部工具

    ## Author
    Your Name

    ## Version
    1.0.0
    EOF

    # 4. 开发实现代码
    # 在 src/main.py 中编写逻辑

    3.4 类型选择指南

    维度BundledManagedWorkspace
    开发难度 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐
    审核要求 N/A 严格
    分发范围 全局 全平台 本地
    更新方式 自动 自动/手动 手动
    商业化
    适合阶段 官方核心功能 成熟产品 原型/内部

    四、开发环境搭建

    4.1 基础工具安装

    # 1. 安装 Python 3.9+
    python –version # 应该 >= 3.9

    # 2. 安装 pnpm(Node.js 包管理器)
    curl -fsSL https://get.pnpm.io/install.sh | sh
    pnpm –version

    # 3. 安装 Git
    git –version

    # 4. 安装 OpenClaw CLI
    npm install -g openclaw@latest
    openclaw –version

    4.2 创建开发工作区

    # 1. 创建工作区目录
    mkdir -p ~/openclaw-dev/skills
    cd ~/openclaw-dev/skills

    # 2. 克隆官方模板仓库
    git clone https://github.com/openclaw/skill-template.git my-first-skill
    cd my-first-skill

    # 3. 安装依赖
    pip install -r requirements.txt

    # 4. 初始化 Git
    git init
    git add .
    git commit -m "Initial commit"

    4.3 开发工具推荐

    VS Code 扩展

    // .vscode/extensions.json
    {
    "recommendations": [
    "ms-python.python",
    "ms-python.vscode-pylance",
    "esbenp.prettier-vscode",
    "redhat.vscode-yaml",
    "docsify.docsify",
    "shd101wyy.markdown-preview-enhanced"
    ]
    }

    项目配置文件

    // .vscode/settings.json
    {
    "python.defaultInterpreterPath": "${workspaceFolder}/venv/bin/python",
    "python.linting.enabled": true,
    "python.linting.pylintEnabled": true,
    "python.formatting.provider": "black",
    "editor.formatOnSave": true,
    "editor.tabSize": 2,
    "files.exclude": {
    "**/__pycache__": true,
    "**/*.pyc": true,
    ".pytest_cache": true
    }
    }

    4.4 虚拟环境管理

    # 创建虚拟环境
    cd ~/openclaw-dev/skills/my-first-skill
    python -m venv venv

    # 激活虚拟环境
    # macOS/Linux
    source venv/bin/activate

    # Windows
    venv\\Scripts\\activate

    # 安装开发依赖
    pip install -r requirements-dev.txt

    # 验证安装
    pip list


    五、SKILL.md 规范详解

    5.1 完整模板

    # Skill 名称

    ## Description

    这里是技能的详细描述,应该包括:
    – 这个技能的主要功能
    – 解决了什么问题
    – 目标用户群体
    – 使用场景说明

    **字数建议**:100-300 字,简洁明了

    ## Features

    – ✨ 特性 1:简要描述
    – 🚀 特性 2:简要描述
    – 🔒 特性 3:简要描述
    – 🎨 特性 4:简要描述

    ## Requirements

    ### 系统要求

    – Python >= 3.9
    – Node.js >= 18 (如果需要)
    – 其他依赖…

    ### API 密钥

    某些功能可能需要:
    – GitHub Token(访问 GitHub API)
    – API Key(第三方服务)

    ## Installation

    ### 方法 1:通过 ClawHub

    ```bash
    openclaw skills install skill-name

    方法 2:手动安装

    git clone https://github.com/your-username/skill-name.git
    cd skill-name
    pip install -r requirements.txt

    Usage

    基本用法

    /user: 使用 skill-name 处理 XXX

    高级功能

    /user: skill-name 高级命令 –option value

    配置示例

    {
    "skills": {
    "skill-name": {
    "apiKey": "your-api-key",
    "enabled": true
    }
    }
    }

    API Reference

    公开方法

    method_name(param1, param2)

    参数:

    • param1 (str): 参数说明
    • param2 (int): 参数说明

    返回值:

    • dict: 返回值说明

    示例:

    result = handler.method_name("value", 123)

    Examples

    示例 1:基本使用场景

    输入:

    请帮我分析这个项目

    输出:

    已分析完成,发现以下问题…

    示例 2:复杂工作流

    输入:

    同步我的 GitHub issues 到 Notion

    输出:

    已同步 15 个 issues 到 Notion workspace

    Troubleshooting

    常见问题

    Q: 安装时出现依赖冲突

    A: 尝试使用虚拟环境:

    python -m venv venv
    source venv/bin/activate
    pip install –upgrade pip
    pip install -r requirements.txt

    Q: API 调用失败

    A: 检查以下几点:

  • API 密钥是否正确配置
  • 网络连接是否正常
  • API 配额是否用完
  • Development

    本地开发

    # 克隆仓库
    git clone https://github.com/your-username/skill-name.git

    # 安装依赖
    pip install -r requirements-dev.txt

    # 运行测试
    pytest tests/

    # 运行示例
    python examples/basic.py

    提交代码

    我们欢迎 PR!请遵循以下步骤:

  • Fork 本仓库
  • 创建特性分支 (git checkout -b feature/amazing-feature)
  • 提交更改 (git commit -m 'Add amazing feature')
  • 推送到分支 (git push origin feature/amazing-feature)
  • 开启 Pull Request
  • Testing

    单元测试

    pytest tests/unit -v

    集成测试

    pytest tests/integration -v

    Contributing

    欢迎贡献代码、报告问题或提出建议!

    License

    本项目采用 MIT 许可证

    Author

    • 姓名: Your Name
    • GitHub: @yourusername
    • 邮箱: your.email@example.com

    Acknowledgments

    感谢以下项目和贡献者:

    • OpenClaw 核心团队
    • 所有贡献者

    Changelog

    Version 1.0.0 (2024-01-01)

    • ✨ 初始版本发布
    • 🐛 修复已知问题
    • 📝 完善文档

    Version 0.1.0 (2023-12-01)

    • 🎉 项目启动

    ### 5.2 元数据提取脚本

    ```python
    # Python 示例:从 SKILL.md 提取元数据
    import re
    from pathlib import Path
    from typing import Dict, Optional

    class SkillMetadataExtractor:
    def __init__(self, skill_md_path: str):
    self.skill_md_path = Path(skill_md_path)
    self.content = ""
    self.metadata = {}

    def load(self):
    """加载 SKILL.md"""
    if not self.skill_md_path.exists():
    raise FileNotFoundError(f"找不到 SKILL.md: {self.skill_md_path}")

    with open(self.skill_md_path, 'r', encoding='utf-8') as f:
    self.content = f.read()

    return self

    def extract_all(self) -> Dict:
    """提取所有元数据"""
    self.metadata = {
    'name': self._extract_name(),
    'description': self._extract_description(),
    'version': self._extract_version(),
    'author': self._extract_author(),
    'features': self._extract_features(),
    'requirements': self._extract_requirements(),
    'examples': self._extract_examples()
    }

    return self.metadata

    def _extract_name(self) -> str:
    """提取名称"""
    match = re.search(r'^#\\s+(.+)$', self.content, re.MULTILINE)
    return match.group(1).strip() if match else "Unknown"

    def _extract_description(self) -> str:
    """提取描述"""
    match = re.search(r'##\\s+Description\\s*\\n(.*?)(?=##|\\Z)', self.content, re.DOTALL)
    return match.group(1).strip() if match else ""

    def _extract_version(self) -> Optional[str]:
    """提取版本"""
    match = re.search(r'\\*\\*Version\\*\\*:\\s*(\\d+\\.\\d+\\.\\d+)', self.content)
    return match.group(1) if match else None

    def _extract_author(self) -> Optional[str]:
    """提取作者"""
    match = re.search(r'\\*\\*Author\\*\\*:\\s*(.+)', self.content)
    return match.group(1).strip() if match else None

    def _extract_features(self) -> list:
    """提取特性列表"""
    features = []
    matches = re.findall(r'^[-*]\\s*[✨🚀🔒🎨]\\s*(.+)$', self.content, re.MULTILINE)
    for match in matches:
    features.append(match.strip())
    return features

    def _extract_requirements(self) -> Dict:
    """提取要求"""
    reqs = {
    'python': None,
    'nodejs': None,
    'api_keys': []
    }

    python_match = re.search(r'Python\\s*>=?\\s*(\\d+\\.\\d+)', self.content, re.IGNORECASE)
    if python_match:
    reqs['python'] = python_match.group(1)

    node_match = re.search(r'Node\\.?js\\s*>=?\\s*(\\d+)', self.content, re.IGNORECASE)
    if node_match:
    reqs['nodejs'] = node_match.group(1)

    return reqs

    def validate(self) -> tuple:
    """验证 SKILL.md"""
    errors = []
    warnings = []

    # 必需字段
    if not self.metadata.get('name') or self.metadata['name'] == "Unknown":
    errors.append("缺少有效的名称")

    if not self.metadata.get('description'):
    errors.append("缺少描述")

    # 可选字段警告
    if not self.metadata.get('version'):
    warnings.append("建议添加版本号")

    if not self.metadata.get('author'):
    warnings.append("建议添加作者信息")

    return errors, warnings

    # 使用示例
    extractor = SkillMetadataExtractor("./my-skill/SKILL.md")
    extractor.load()
    metadata = extractor.extract_all()

    print(f"Skill 名称:{metadata['name']}")
    print(f"描述:{metadata['description'][:100]}…")
    print(f"版本:{metadata['version']}")
    print(f"作者:{metadata['author']}")
    print(f"特性:{metadata['features']}")

    # 验证
    errors, warnings = extractor.validate()
    if errors:
    print("\\n❌ 错误:")
    for error in errors:
    print(f" – {error}")

    if warnings:
    print("\\n⚠️ 警告:")
    for warning in warnings:
    print(f" – {warning}")


    六、第一个 Skill 开发

    6.1 项目初始化

    # 1. 创建项目结构
    mkdir -p github-helper/src/github_helper
    cd github-helper

    # 2. 创建必要文件
    touch SKILL.md
    touch src/github_helper/__init__.py
    touch src/github_helper/main.py
    touch src/github_helper/utils.py
    touch requirements.txt
    touch README.md
    touch .gitignore

    # 3. 初始化 Git
    git init

    6.2 编写 SKILL.md

    # GitHub Helper

    ## Description

    GitHub Helper 是一个强大的 GitHub 集成工具,让你可以通过自然语言与 GitHub 交互。

    **主要功能**:
    – 查询仓库信息和统计数据
    – 管理 Issues 和 Pull Requests
    – 查看 CI/CD 工作流状态
    – 自动生成周报和月报

    **适用场景**:
    – 开发者日常 GitHub 管理
    – 团队项目进度跟踪
    – 开源项目维护

    ## Features

    – ✨ 自然语言查询仓库信息
    – 🚀 一键生成项目报告
    – 🔒 安全的 Token 管理
    – 🎨 美观的统计图表

    ## Requirements

    ### 系统要求

    – Python >= 3.9
    – OpenClaw >= 1.0.0

    ### API 密钥

    需要 GitHub Personal Access Token:
    1. 访问 https://github.com/settings/tokens
    2. 生成新 token(勾选 repo 权限)
    3. 在配置中设置

    ## Installation

    ```bash
    openclaw skills install github-helper

    Usage

    基本命令

    /user: 使用 github-helper 查询 openclaw/openclaw 仓库信息
    /user: github-helper 生成我的本周贡献报告
    /user: 查看 openclaw/openclaw 的 open issues

    配置

    在 ~/.openclaw/openclaw.json 中添加:

    {
    "skills": {
    "github-helper": {
    "token": "ghp_xxxxxxxxxxxx",
    "enabled": true
    }
    }
    }

    Author

    • Name: Your Name
    • GitHub: @yourusername

    Version

    1.0.0

    ### 6.3 实现核心功能

    ```python
    # src/github_helper/main.py
    """GitHub Helper Skill 主模块"""

    import os
    import requests
    from typing import Dict, List, Optional
    from datetime import datetime, timedelta

    from .utils import format_number, parse_repo_url

    class SkillHandler:
    """GitHub Helper 处理器"""

    def __init__(self, config: Optional[Dict] = None):
    """
    初始化处理器

    Args:
    config: 配置字典,包含 token 等信息
    """
    self.config = config or {}
    self.token = self.config.get('token') or os.getenv('GITHUB_TOKEN')

    if not self.token:
    raise ValueError("GitHub Token 未配置")

    self.api_base = "https://api.github.com"
    self.headers = {
    'Authorization': f'token {self.token}',
    'Accept': 'application/vnd.github.v3+json'
    }

    def get_repo_info(self, repo_full_name: str) -> Dict:
    """
    获取仓库信息

    Args:
    repo_full_name: 仓库全名,如 "openclaw/openclaw"

    Returns:
    仓库信息字典
    """
    url = f"{self.api_base}/repos/{repo_full_name}"

    response = requests.get(url, headers=self.headers)
    response.raise_for_status()

    data = response.json()

    return {
    'name': data['name'],
    'full_name': data['full_name'],
    'description': data['description'],
    'stars': data['stargazers_count'],
    'forks': data['forks_count'],
    'watchers': data['watchers_count'],
    'open_issues': data['open_issues_count'],
    'language': data['language'],
    'license': data['license']['name'] if data['license'] else None,
    'created_at': data['created_at'],
    'updated_at': data['updated_at'],
    'url': data['html_url']
    }

    def list_issues(self, repo_full_name: str, state: str = 'open', limit: int = 10) -> List[Dict]:
    """
    列出 Issues

    Args:
    repo_full_name: 仓库全名
    state: 状态(open/closed/all)
    limit: 数量限制

    Returns:
    Issue 列表
    """
    url = f"{self.api_base}/repos/{repo_full_name}/issues"
    params = {
    'state': state,
    'per_page': min(limit, 100)
    }

    response = requests.get(url, headers=self.headers, params=params)
    response.raise_for_status()

    issues = response.json()

    return [
    {
    'number': issue['number'],
    'title': issue['title'],
    'state': issue['state'],
    'user': issue['user']['login'],
    'created_at': issue['created_at'],
    'url': issue['html_url']
    }
    for issue in issues[:limit]
    ]

    def get_contributor_stats(self, repo_full_name: str) -> Dict:
    """
    获取贡献者统计

    Args:
    repo_full_name: 仓库全名

    Returns:
    统计信息字典
    """
    # 获取贡献者列表
    url = f"{self.api_base}/repos/{repo_full_name}/contributors"
    params = {'per_page': 100}

    response = requests.get(url, headers=self.headers, params=params)
    response.raise_for_status()

    contributors = response.json()

    total_commits = sum(c['contributions'] for c in contributors)

    return {
    'total_contributors': len(contributors),
    'total_commits': total_commits,
    'top_contributors': [
    {
    'login': c['login'],
    'contributions': c['contributions'],
    'avatar': c['avatar_url']
    }
    for c in sorted(contributors, key=lambda x: x['contributions'], reverse=True)[:10]
    ]
    }

    def generate_weekly_report(self, repo_full_name: str) -> str:
    """
    生成本周报告

    Args:
    repo_full_name: 仓库全名

    Returns:
    格式化的报告文本
    """
    # 计算本周时间范围
    now = datetime.now()
    monday = now – timedelta(days=now.weekday())

    report_lines = [
    f"# 📊 GitHub 周报 – {repo_full_name}",
    f"\\n**统计周期**: {monday.strftime('%Y-%m-%d')} 至今\\n",
    ]

    # 获取仓库信息
    repo_info = self.get_repo_info(repo_full_name)
    report_lines.extend([
    f"## 仓库概况",
    f"- ⭐ Stars: {format_number(repo_info['stars'])}",
    f"- 🍴 Forks: {format_number(repo_info['forks'])}",
    f"- 📝 Open Issues: {format_number(repo_info['open_issues'])}",
    f"- 💻 语言:{repo_info['language'] or 'N/A'}",
    ""
    ])

    # 获取贡献者统计
    stats = self.get_contributor_stats(repo_full_name)
    report_lines.extend([
    f"## 贡献者统计",
    f"- 👥 总贡献者:{stats['total_contributors']}人",
    f"- 🔢 总提交数:{format_number(stats['total_commits'])}",
    "",
    "### Top 贡献者",
    ])

    for i, contributor in enumerate(stats['top_contributors'][:5], 1):
    report_lines.append(
    f"{i}. **{contributor['login']}**: {contributor['contributions']} 次提交"
    )

    # 获取最新 Issues
    issues = self.list_issues(repo_full_name, limit=5)
    if issues:
    report_lines.extend(["", "## 最新 Issues"])
    for issue in issues:
    report_lines.append(
    f"- [{issue['title']}]({issue['url']}) #{issue['number']}"
    )

    return "\\n".join(report_lines)

    def process_command(self, command: str) -> str:
    """
    处理用户命令

    Args:
    command: 用户命令

    Returns:
    响应文本
    """
    command = command.lower().strip()

    # 解析命令
    if "查询" in command and "仓库" in command:
    # 提取仓库名
    repo = parse_repo_url(command)
    if repo:
    info = self.get_repo_info(repo)
    return (
    f"📦 **{info['full_name']}**\\n\\n"
    f"{info['description']}\\n\\n"
    f"⭐ {format_number(info['stars'])} | "
    f"🍴 {format_number(info['forks'])} | "
    f"📝 {format_number(info['open_issues'])}\\n\\n"
    f"[查看仓库]({info['url']})"
    )

    elif "报告" in command or "周报" in command:
    repo = parse_repo_url(command)
    if repo:
    return self.generate_weekly_report(repo)

    elif "issue" in command or "问题" in command:
    repo = parse_repo_url(command)
    if repo:
    issues = self.list_issues(repo)
    lines = [f"## 最新 Issues in {repo}"]
    for issue in issues:
    lines.append(f"- #{issue['number']} {issue['title']}")
    return "\\n".join(lines)

    return "抱歉,我无法理解该命令。请尝试:\\n- 查询 XXX 仓库信息\\n- 生成 XXX 周报\\n- 查看 XXX 的 issues"

    # 使用示例
    if __name__ == "__main__":
    handler = SkillHandler(config={'token': 'ghp_your_token_here'})

    # 查询仓库信息
    info = handler.get_repo_info("openclaw/openclaw")
    print(f"仓库:{info['full_name']}")
    print(f"Stars: {info['stars']}")

    # 生成周报
    report = handler.generate_weekly_report("openclaw/openclaw")
    print(f"\\n{report}")

    6.4 工具函数

    # src/github_helper/utils.py
    """工具函数模块"""

    import re
    from typing import Optional

    def format_number(num: int) > str:
    """格式化数字(如 1.2k)"""
    if num >= 1000000:
    return f"{num / 1000000:.1f}M"
    elif num >= 1000:
    return f"{num / 1000:.1f}k"
    else:
    return str(num)

    def parse_repo_url(text: str) > Optional[str]:
    """
    从文本中提取仓库全名

    Args:
    text: 输入文本

    Returns:
    仓库全名,如 "owner/repo"
    """
    # 匹配 GitHub URL
    url_pattern = r'github\\.com/([^/\\s]+)/([^/\\s]+)'
    match = re.search(url_pattern, text)
    if match:
    return f"{match.group(1)}/{match.group(2)}"

    # 匹配 owner/repo 格式
    repo_pattern = r'([a-zA-Z0-9_-]+)/([a-zA-Z0-9_.-]+)'
    match = re.search(repo_pattern, text)
    if match:
    return f"{match.group(1)}/{match.group(2)}"

    return None

    6.5 依赖配置

    # requirements.txt
    requests>=2.28.0
    python-dotenv>=1.0.0

    # requirements-dev.txt
    -r requirements.txt
    pytest>=7.0.0
    black>=23.0.0
    flake8>=6.0.0
    mypy>=1.0.0


    七、高级 Skill 开发技巧

    7.1 异步处理

    # src/async_helper.py
    import asyncio
    import aiohttp
    from typing import List, Dict

    class AsyncSkillHandler:
    """异步 Skill 处理器"""

    def __init__(self, token: str):
    self.token = token
    self.session = None

    async def __aenter__(self):
    self.session = aiohttp.ClientSession(
    headers={'Authorization': f'token {self.token}'}
    )
    return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
    if self.session:
    await self.session.close()

    async def fetch_multiple_repos(self, repo_names: List[str]) > List[Dict]:
    """
    并发获取多个仓库信息

    Args:
    repo_names: 仓库名称列表

    Returns:
    仓库信息列表
    """
    async def fetch_repo(name: str):
    url = f"https://api.github.com/repos/{name}"
    async with self.session.get(url) as response:
    if response.status == 200:
    return await response.json()
    return None

    tasks = [fetch_repo(name) for name in repo_names]
    results = await asyncio.gather(*tasks, return_exceptions=True)

    return [r for r in results if isinstance(r, dict)]

    async def batch_process(self, items: List[str], batch_size: int = 10):
    """批量处理"""
    for i in range(0, len(items), batch_size):
    batch = items[i:i + batch_size]
    print(f"处理批次 {i // batch_size + 1}")
    await self.process_batch(batch)

    async def process_batch(self, batch: List[str]):
    """处理单个批次"""
    # 实现具体处理逻辑
    pass

    # 使用示例
    async def main():
    repos = ["openclaw/openclaw", "microsoft/vscode", "python/cpython"]

    async with AsyncSkillHandler(token="ghp_xxx") as handler:
    results = await handler.fetch_multiple_repos(repos)

    for repo in results:
    print(f"{repo['full_name']}: ⭐ {repo['stargazers_count']}")

    asyncio.run(main())

    7.2 缓存机制

    # src/cache_manager.py
    import json
    import hashlib
    from pathlib import Path
    from datetime import datetime, timedelta
    from typing import Any, Optional

    class CacheManager:
    """缓存管理器"""

    def __init__(self, cache_dir: str = "~/.openclaw/cache"):
    self.cache_dir = Path(cache_dir).expanduser()
    self.cache_dir.mkdir(parents=True, exist_ok=True)

    def _generate_key(self, *args, **kwargs) > str:
    """生成缓存键"""
    key_str = f"{args}:{kwargs}"
    return hashlib.md5(key_str.encode()).hexdigest()

    def get(self, key: str, ttl_minutes: int = 30) > Optional[Any]:
    """
    获取缓存

    Args:
    key: 缓存键
    ttl_minutes: 有效期(分钟)

    Returns:
    缓存的数据,过期或不存在返回 None
    """
    cache_file = self.cache_dir / f"{key}.json"

    if not cache_file.exists():
    return None

    try:
    with open(cache_file, 'r', encoding='utf-8') as f:
    data = json.load(f)

    # 检查是否过期
    cached_at = datetime.fromisoformat(data['_cached_at'])
    if datetime.now() cached_at > timedelta(minutes=ttl_minutes):
    return None

    return data['value']

    except Exception:
    return None

    def set(self, key: str, value: Any):
    """设置缓存"""
    cache_file = self.cache_dir / f"{key}.json"

    data = {
    'value': value,
    '_cached_at': datetime.now().isoformat()
    }

    with open(cache_file, 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

    def delete(self, key: str):
    """删除缓存"""
    cache_file = self.cache_dir / f"{key}.json"
    if cache_file.exists():
    cache_file.unlink()

    def clear(self):
    """清空缓存"""
    for cache_file in self.cache_dir.glob("*.json"):
    cache_file.unlink()

    # 使用示例
    cache = CacheManager()

    # 设置缓存
    cache.set("user_123", {"name": "Alice", "age": 30})

    # 获取缓存
    user_data = cache.get("user_123")
    print(user_data) # {'name': 'Alice', 'age': 30}

    # 带缓存的函数调用示例
    def get_expensive_data(param: str):
    cache_key = f"data_{param}"

    # 先尝试从缓存获取
    cached = cache.get(cache_key, ttl_minutes=60)
    if cached:
    print("缓存命中")
    return cached

    # 缓存未命中,执行实际计算
    print("缓存未命中,计算中…")
    result = {"param": param, "timestamp": datetime.now().isoformat()}

    # 保存到缓存
    cache.set(cache_key, result)
    return result

    7.3 错误处理与重试

    # src/error_handler.py
    import time
    import random
    from functools import wraps
    from typing import Callable, Any

    class RetryError(Exception):
    """重试失败异常"""
    pass

    def retry(max_attempts: int = 3, delay: float = 1.0, backoff: float = 2.0):
    """
    重试装饰器

    Args:
    max_attempts: 最大重试次数
    delay: 初始延迟(秒)
    backoff: 延迟倍数
    """
    def decorator(func: Callable) > Callable:
    @wraps(func)
    def wrapper(*args, **kwargs) > Any:
    current_delay = delay
    last_exception = None

    for attempt in range(max_attempts):
    try:
    return func(*args, **kwargs)

    except Exception as e:
    last_exception = e

    if attempt == max_attempts 1:
    # 最后一次尝试失败
    break

    # 等待后重试(添加随机抖动)
    jitter = random.uniform(0.1, 0.3)
    wait_time = current_delay + jitter
    print(f"尝试 {attempt + 1} 失败:{e}")
    print(f"等待 {wait_time:.2f}秒后重试…")
    time.sleep(wait_time)

    current_delay *= backoff

    raise RetryError(f"重试{max_attempts}次后仍然失败") from last_exception

    return wrapper
    return decorator

    # 使用示例
    @retry(max_attempts=3, delay=1.0, backoff=2.0)
    def unstable_api_call():
    """不稳定的 API 调用"""
    import random

    if random.random() < 0.7: # 70% 概率失败
    raise ConnectionError("网络连接失败")

    return "成功!"

    try:
    result = unstable_api_call()
    print(result)
    except RetryError as e:
    print(f"最终失败:{e}")


    八、测试与调试

    8.1 单元测试

    # tests/test_github_helper.py
    import pytest
    import responses
    from src.github_helper.main import SkillHandler

    class TestSkillHandler:
    """SkillHandler 测试类"""

    @pytest.fixture
    def handler(self):
    """测试夹具"""
    return SkillHandler(config={'token': 'test_token'})

    @responses.activate
    def test_get_repo_info(self, handler):
    """测试获取仓库信息"""
    # Mock API 响应
    responses.add(
    responses.GET,
    "https://api.github.com/repos/test/repo",
    json={
    'name': 'repo',
    'full_name': 'test/repo',
    'stargazers_count': 100,
    'forks_count': 20,
    # … 其他字段
    },
    status=200
    )

    # 调用方法
    info = handler.get_repo_info("test/repo")

    # 断言
    assert info['name'] == 'repo'
    assert info['stars'] == 100

    def test_format_number(self):
    """测试数字格式化"""
    from src.github_helper.utils import format_number

    assert format_number(500) == "500"
    assert format_number(1500) == "1.5k"
    assert format_number(1500000) == "1.5M"

    def test_parse_repo_url(self):
    """测试仓库 URL 解析"""
    from src.github_helper.utils import parse_repo_url

    # URL 格式
    assert parse_repo_url("https://github.com/owner/repo") == "owner/repo"

    # 纯文本格式
    assert parse_repo_url("查看 owner/repo 仓库") == "owner/repo"

    # 无效格式
    assert parse_repo_url("无效输入") is None

    8.2 集成测试

    # tests/test_integration.py
    import os
    import pytest
    from src.github_helper.main import SkillHandler

    @pytest.mark.skipif(not os.getenv('GITHUB_TOKEN'), reason="需要 GITHUB_TOKEN")
    class TestIntegration:
    """集成测试"""

    @pytest.fixture
    def real_handler(self):
    """使用真实 Token 的处理器"""
    return SkillHandler(config={'token': os.getenv('GITHUB_TOKEN')})

    def test_real_repo_info(self, real_handler):
    """测试真实的 API 调用"""
    info = real_handler.get_repo_info("openclaw/openclaw")

    assert info['name'] == 'openclaw'
    assert info['stars'] > 0
    assert 'url' in info

    def test_real_issues(self, real_handler):
    """测试获取真实 Issues"""
    issues = real_handler.list_issues("openclaw/openclaw", limit=5)

    assert len(issues) <= 5
    for issue in issues:
    assert 'number' in issue
    assert 'title' in issue

    8.3 运行测试

    # 运行所有测试
    pytest tests/ -v

    # 只运行单元测试
    pytest tests/unit -v

    # 只运行集成测试(需要配置)
    pytest tests/integration -v –integration

    # 生成覆盖率报告
    pytest –cov=src tests/ –cov-report=html

    # 查看 HTML 报告
    open htmlcov/index.html


    九、发布到 ClawHub

    9.1 发布前检查清单

    ## 发布前检查清单

    ### 文档
    – [ ] SKILL.md 完整且准确
    – [ ] README.md 详细说明使用方法
    – [ ] 包含足够的示例
    – [ ] 更新了 Changelog

    ### 代码
    – [ ] 所有测试通过
    – [ ] 代码格式化(black, flake8)
    – [ ] 类型注解完整(mypy)
    – [ ] 无敏感信息(Token、密码等)

    ### 安全
    – [ ] 依赖无已知漏洞
    – [ ] 无恶意代码
    – [ ] 权限最小化

    ### 性能
    – [ ] 响应时间 < 2 秒
    – [ ] 内存使用合理
    – [ ] 有适当的缓存机制

    9.2 打包 Skill

    # 1. 清理不必要的文件
    find . -type d -name "__pycache__" -exec rm -rf {} +
    find . -type f -name "*.pyc" -delete
    find . -type f -name "*.pyo" -delete
    rm -rf .pytest_cache .coverage htmlcov/

    # 2. 创建发布包
    cd ~/openclaw-dev/skills/github-helper

    # 3. 验证包结构
    tree -L 2

    # 预期结构:
    # .
    # ├── SKILL.md
    # ├── README.md
    # ├── requirements.txt
    # ├── src
    # │ └── github_helper
    # │ ├── __init__.py
    # │ ├── main.py
    # │ └── utils.py
    # └── tests
    # └── test_*.py

    9.3 提交到 ClawHub

    # 1. 登录 ClawHub
    openclaw clawhub login

    # 2. 验证 Skill
    openclaw skills validate ./github-helper

    # 3. 发布
    openclaw skills publish ./github-helper \\
    –category "Development Tools" \\
    –tags "github,automation,productivity" \\
    –license "MIT" \\
    –price free # 或 –price 9.99

    # 4. 查看发布状态
    openclaw skills status github-helper

    9.4 审核流程

    #mermaid-svg-sk8JcjtYf5obE9ne{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sk8JcjtYf5obE9ne .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sk8JcjtYf5obE9ne .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sk8JcjtYf5obE9ne .error-icon{fill:#552222;}#mermaid-svg-sk8JcjtYf5obE9ne .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sk8JcjtYf5obE9ne .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sk8JcjtYf5obE9ne .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sk8JcjtYf5obE9ne .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sk8JcjtYf5obE9ne .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sk8JcjtYf5obE9ne .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sk8JcjtYf5obE9ne .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sk8JcjtYf5obE9ne .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sk8JcjtYf5obE9ne .marker.cross{stroke:#333333;}#mermaid-svg-sk8JcjtYf5obE9ne svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sk8JcjtYf5obE9ne p{margin:0;}#mermaid-svg-sk8JcjtYf5obE9ne .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-sk8JcjtYf5obE9ne .cluster-label text{fill:#333;}#mermaid-svg-sk8JcjtYf5obE9ne .cluster-label span{color:#333;}#mermaid-svg-sk8JcjtYf5obE9ne .cluster-label span p{background-color:transparent;}#mermaid-svg-sk8JcjtYf5obE9ne .label text,#mermaid-svg-sk8JcjtYf5obE9ne span{fill:#333;color:#333;}#mermaid-svg-sk8JcjtYf5obE9ne .node rect,#mermaid-svg-sk8JcjtYf5obE9ne .node circle,#mermaid-svg-sk8JcjtYf5obE9ne .node ellipse,#mermaid-svg-sk8JcjtYf5obE9ne .node polygon,#mermaid-svg-sk8JcjtYf5obE9ne .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sk8JcjtYf5obE9ne .rough-node .label text,#mermaid-svg-sk8JcjtYf5obE9ne .node .label text,#mermaid-svg-sk8JcjtYf5obE9ne .image-shape .label,#mermaid-svg-sk8JcjtYf5obE9ne .icon-shape .label{text-anchor:middle;}#mermaid-svg-sk8JcjtYf5obE9ne .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sk8JcjtYf5obE9ne .rough-node .label,#mermaid-svg-sk8JcjtYf5obE9ne .node .label,#mermaid-svg-sk8JcjtYf5obE9ne .image-shape .label,#mermaid-svg-sk8JcjtYf5obE9ne .icon-shape .label{text-align:center;}#mermaid-svg-sk8JcjtYf5obE9ne .node.clickable{cursor:pointer;}#mermaid-svg-sk8JcjtYf5obE9ne .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sk8JcjtYf5obE9ne .arrowheadPath{fill:#333333;}#mermaid-svg-sk8JcjtYf5obE9ne .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sk8JcjtYf5obE9ne .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sk8JcjtYf5obE9ne .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sk8JcjtYf5obE9ne .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sk8JcjtYf5obE9ne .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sk8JcjtYf5obE9ne .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sk8JcjtYf5obE9ne .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sk8JcjtYf5obE9ne .cluster text{fill:#333;}#mermaid-svg-sk8JcjtYf5obE9ne .cluster span{color:#333;}#mermaid-svg-sk8JcjtYf5obE9ne div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sk8JcjtYf5obE9ne .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sk8JcjtYf5obE9ne rect.text{fill:none;stroke-width:0;}#mermaid-svg-sk8JcjtYf5obE9ne .icon-shape,#mermaid-svg-sk8JcjtYf5obE9ne .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sk8JcjtYf5obE9ne .icon-shape p,#mermaid-svg-sk8JcjtYf5obE9ne .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sk8JcjtYf5obE9ne .icon-shape rect,#mermaid-svg-sk8JcjtYf5obE9ne .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sk8JcjtYf5obE9ne .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sk8JcjtYf5obE9ne .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sk8JcjtYf5obE9ne :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    格式错误

    通过

    发现风险

    安全

    发现问题

    通过

    确认安全

    确认风险

    提交发布

    自动检查

    返回修改

    安全扫描

    人工复审

    功能测试

    审核通过

    上架 ClawHub

    用户可见

    拒绝发布


    十、Skill 运营与推广

    10.1 定价策略

    类型价格区间适用场景建议
    免费 $0 引流、建立影响力 提供基础功能,高级功能收费
    低价 $1-9 个人开发者工具 快速获客
    中价 $10-49 专业工具 主流选择
    高价 $50+ 企业级解决方案 提供技术支持

    10.2 营销渠道

  • ClawHub 市场优化

    • 精准的标签和分类
    • 吸引人的图标和截图
    • 详细的文档和示例
  • 社交媒体

    • Twitter/X 发布更新
    • LinkedIn 专业网络
    • 微信公众号(中文用户)
  • 技术社区

    • GitHub Trending
    • Hacker News
    • V2EX
    • 知乎
  • 内容营销

    • 撰写教程博客
    • 制作视频教程
    • 直播演示
  • 10.3 用户反馈循环

    #mermaid-svg-tMS2PnFwKAaJ7Beh{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tMS2PnFwKAaJ7Beh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tMS2PnFwKAaJ7Beh .error-icon{fill:#552222;}#mermaid-svg-tMS2PnFwKAaJ7Beh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tMS2PnFwKAaJ7Beh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tMS2PnFwKAaJ7Beh .marker.cross{stroke:#333333;}#mermaid-svg-tMS2PnFwKAaJ7Beh svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tMS2PnFwKAaJ7Beh p{margin:0;}#mermaid-svg-tMS2PnFwKAaJ7Beh .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-tMS2PnFwKAaJ7Beh .cluster-label text{fill:#333;}#mermaid-svg-tMS2PnFwKAaJ7Beh .cluster-label span{color:#333;}#mermaid-svg-tMS2PnFwKAaJ7Beh .cluster-label span p{background-color:transparent;}#mermaid-svg-tMS2PnFwKAaJ7Beh .label text,#mermaid-svg-tMS2PnFwKAaJ7Beh span{fill:#333;color:#333;}#mermaid-svg-tMS2PnFwKAaJ7Beh .node rect,#mermaid-svg-tMS2PnFwKAaJ7Beh .node circle,#mermaid-svg-tMS2PnFwKAaJ7Beh .node ellipse,#mermaid-svg-tMS2PnFwKAaJ7Beh .node polygon,#mermaid-svg-tMS2PnFwKAaJ7Beh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tMS2PnFwKAaJ7Beh .rough-node .label text,#mermaid-svg-tMS2PnFwKAaJ7Beh .node .label text,#mermaid-svg-tMS2PnFwKAaJ7Beh .image-shape .label,#mermaid-svg-tMS2PnFwKAaJ7Beh .icon-shape .label{text-anchor:middle;}#mermaid-svg-tMS2PnFwKAaJ7Beh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tMS2PnFwKAaJ7Beh .rough-node .label,#mermaid-svg-tMS2PnFwKAaJ7Beh .node .label,#mermaid-svg-tMS2PnFwKAaJ7Beh .image-shape .label,#mermaid-svg-tMS2PnFwKAaJ7Beh .icon-shape .label{text-align:center;}#mermaid-svg-tMS2PnFwKAaJ7Beh .node.clickable{cursor:pointer;}#mermaid-svg-tMS2PnFwKAaJ7Beh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tMS2PnFwKAaJ7Beh .arrowheadPath{fill:#333333;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tMS2PnFwKAaJ7Beh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tMS2PnFwKAaJ7Beh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tMS2PnFwKAaJ7Beh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tMS2PnFwKAaJ7Beh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tMS2PnFwKAaJ7Beh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tMS2PnFwKAaJ7Beh .cluster text{fill:#333;}#mermaid-svg-tMS2PnFwKAaJ7Beh .cluster span{color:#333;}#mermaid-svg-tMS2PnFwKAaJ7Beh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tMS2PnFwKAaJ7Beh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tMS2PnFwKAaJ7Beh rect.text{fill:none;stroke-width:0;}#mermaid-svg-tMS2PnFwKAaJ7Beh .icon-shape,#mermaid-svg-tMS2PnFwKAaJ7Beh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tMS2PnFwKAaJ7Beh .icon-shape p,#mermaid-svg-tMS2PnFwKAaJ7Beh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tMS2PnFwKAaJ7Beh .icon-shape rect,#mermaid-svg-tMS2PnFwKAaJ7Beh .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tMS2PnFwKAaJ7Beh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tMS2PnFwKAaJ7Beh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tMS2PnFwKAaJ7Beh :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    发布 Skill

    用户使用

    收集反馈

    分析问题

    迭代改进

    发布更新

    好评如潮

    更多用户

    10.4 成功案例

    案例 1:GitHub Helper
    • 开发者:@devmaster
    • 上线时间:2024 年 1 月
    • 定价:免费 + 高级版 $9.99/月
    • 成果:
      • 首月下载量:500+
      • 3 个月用户:2000+
      • 月收入:$3000+

    成功因素:

  • 解决了开发者的实际需求
  • 优秀的文档和示例
  • 快速响应用户反馈
  • 持续的更新和改进

  • 总结

    本文全面介绍了 OpenClaw Skills 开发的完整流程:

    核心要点

  • 理解三种 Skill 类型:Bundled、Managed、Workspace
  • 遵循 SKILL.md 规范:文档质量决定用户体验
  • 掌握开发技巧:异步、缓存、错误处理
  • 重视测试:单元测试 + 集成测试
  • 了解发布流程:从验证到上架
  • 学会运营推广:定价、营销、用户反馈
  • 最佳实践

    • ✅ 从简单的 Workspace Skill 开始练习
    • ✅ 参考官方模板和优秀案例
    • ✅ 编写全面的测试用例
    • ✅ 保持文档与代码同步更新
    • ✅ 积极响应用户反馈
    • ✅ 持续改进和优化

    下一步学习

    • 研究 ClawHub 上的热门 Skills
    • 参与开源项目积累经验
    • 学习更多设计模式和架构知识
    • 探索商业化可能性

    参考资料

  • OpenClaw Skills 文档. https://docs.openclaw.ai/skills
  • ClawHub 技能市场. https://clawhub.ai
  • Python 官方文档. https://docs.python.org/3
  • pytest 测试框架. https://docs.pytest.org
  • GitHub API 文档. https://docs.github.com/en/rest
  • Python 异步编程. https://docs.python.org/3/library/asyncio.html
  • 软件架构设计模式. https://refactoring.guru
  • Python 代码规范 PEP 8. https://peps.python.org/pep-0008/
  • 开源许可证指南. https://choosealicense.com
  • 技术写作最佳实践. https://documentation.divio.com
  • 赞(0)
    未经允许不得转载:171主机测评 » OpenClaw 技能开发教程:从入门到发布
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址