agentleFS
nihao555-hubnihao555-hub/claude-code-agent-skills/skills/skill-developer/SKILL.md

skill-developer

Skill4 starsChanged 8 months agoMITView on GitHub

AI Agent 技能开发专家 - Bundled Skill注册、文件提取机制、参数处理、钩子系统、技能搜索和动态加载

  • Reads credentials

24 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use error-tracking, ast-grep-find and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • weirdgmeSkill

    error-tracking

    Add Sentry v8 error tracking and performance monitoring to your project services. Use this skill when adding error handling, creating new controllers, instrumenting cron jobs, or tracking database performance. ALL ERRORS MUST BE CAPTURED TO SENTRY - no exceptions.

    Also in 5 projects that use this

  • parcadeiSkill

    ast-grep-find

    AST-based code search and refactoring via ast-grep MCP

    Also in 4 projects that use this

  • parcadeiSkill

    debug-hooks

    Systematic hook debugging workflow. Use when hooks aren't firing, producing wrong output, or behaving unexpectedly.

    Also in 4 projects that use this

  • weirdgmeSkill

    route-tester

    Test authenticated routes in the your project using cookie-based authentication. Use this skill when testing API endpoints, validating route functionality, or debugging authentication issues. Includes patterns for using test-auth-route.js and mock authentication.

    Also in 4 projects that use this

  • +7 more from parcadei
  • +1 more from weirdgme

The file

Files
SKILL.md

Skill Developer

使用此技能当你需要进行 Bundled Skill开发、技能文件提取系统设计、参数验证逻辑实现、或技能钩子机制开发。

目标

产出完整的技能开发方案,包括 Bundled Skill 注册系统、文件提取机制、参数处理与验证、钩子系统和技能搜索发现机制。

核心能力

1. Bundled Skill 注册系统 (src/skills/bundledSkills.ts)

Claude Code的 Bundled Skill 注册模式:

import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
import { constants as fsConstants } from 'fs'
import { mkdir, open } from 'fs/promises'
import { dirname, isAbsolute, join, normalize, sep as pathSep } from 'path'
import type { ToolUseContext } from '../Tool.js'

// Skill 文件定义(用于提取到磁盘)
const SKILL_FILES: Record<string, string> = {
  'examples/cli.md': `
# CLI Usage Examples

\`\`\`bash
/example-command arg1 arg2
\`\`\`
`,
  'examples/server.md': `
# Server Usage Examples

\`\`\`typescript
await server.start();
\`\`\`
`
}

// Skill 主体内容(markdown 格式)
const SKILL_MD = `
---
name: verify
description: Verify a code change does what it should by running the app.
argumentHint: <change-description>
---

# Verification Skill

This skill helps you verify that a code change works correctly.

## Process

1. **Understand the Change**
   - What was modified?
   - What behavior should change?
   - What should remain unchanged?

2. **Run the Application**
   - Start the development server
   - Navigate to affected areas
   - Test the specific change

3. **Verify Behavior**
   - Does it work as expected?
   - Are there any regressions?
   - Edge cases covered?

4. **Report Results**
   - Summary of findings
   - Screenshots if applicable
   - Recommendations
`

// 解析 frontmatter
import { parseFrontmatter } from '../../utils/frontmatterParser.js'

const { frontmatter, content: SKILL_BODY } = parseFrontmatter(SKILL_MD)

const DESCRIPTION = typeof frontmatter.description === 'string'
  ? frontmatter.description
  : 'Verify a code change does what it should.'

// 注册技能
export function registerVerifySkill(): void {
  if (process.env.USER_TYPE !== 'ant') {
    return  // 仅 ant 用户可用
  }

  registerBundledSkill({
    name: 'verify',
    description: DESCRIPTION,
    userInvocable: true,
    files: SKILL_FILES,  // 要提取的文件
    async getPromptForCommand(args) {
      const parts: string[] = [SKILL_BODY.trimStart()]
      if (args) {
        parts.push(`## User Request\n\n${args}`)
      }
      return [{ type: 'text', text: parts.join('\n\n') }]
    },
  })
}

2. 技能文件提取机制

/**
 * Extract bundled skill files to disk on first use
 */
async function extractBundledSkillFiles(
  skillName: string,
  files: Record<string, string>
): Promise<string | null> {
  try {
    const extractDir = getBundledSkillExtractDir(skillName)
    
    // Create directory
    await mkdir(extractDir, { recursive: true })
    
    // Write each file
    for (const [relativePath, content] of Object.entries(files)) {
      const fullPath = join(extractDir, relativePath)
      const dir = dirname(fullPath)
      
      // Ensure parent directory exists
      await mkdir(dir, { recursive: true })
      
      // Write file
      const fd = await open(fullPath, 'w')
      try {
        await fd.write(content)
      } finally {
        await fd.close()
      }
    }
    
    return extractDir
  } catch (error) {
    console.error(`Failed to extract skill files for ${skillName}:`, error)
    return null
  }
}

/**
 * Get extraction directory path
 */
function getBundledSkillExtractDir(skillName: string): string {
  // In production: returns path within bun cache
  // In development: returns src/skills/bundled/{skillName}
  if (process.env.NODE_ENV === 'development') {
    return join(process.cwd(), 'src', 'skills', 'bundled', skillName)
  } else {
    return join(getCacheDir(), 'bundled-skills', skillName)
  }
}

3. 参数处理与验证

import { z } from 'zod/v4'

// 定义参数 schema
const skillInputSchema = z.object({
  target: z.string().describe('The file or directory to verify'),
  changes: z.array(z.string()).optional().describe('List of specific changes made'),
  testCommand: z.string().optional().describe('Custom test command to run')
})

type SkillInput = z.infer<typeof skillInputSchema>

/**
 * Parse and validate skill arguments
 */
function parseSkillArgs(args: string): SkillInput {
  try {
    // Try parsing as JSON first
    return skillInputSchema.parse(JSON.parse(args))
  } catch {
    // Fall back to simple string parsing
    const parts = args.trim().split(/\s+/)
    return {
      target: parts[0] || '.',
      changes: parts.slice(1),
      testCommand: undefined
    }
  }
}

/**
 * Generate helpful error message for invalid input
 */
function getInvalidInputErrorMessage(error: z.ZodError): string {
  const issues = error.errors.map(issue => {
    const path = issue.path.join('.')
    return `${path || 'root'}: ${issue.message}`
  })
  
  return `Invalid skill input:\n- ${issues.join('\n- ')}`
}

4. 钩子系统 (HooksSettings)

export interface HooksSettings {
  onStop?: {
    command: string
    description?: string
  }
  onTurnComplete?: {
    command: string
    description?: string
  }
}

/**
 * Register session hooks for a skill
 */
function registerSkillHooks(hooks: HooksSettings): void {
  const { onStop, onTurnComplete } = hooks
  
  if (onStop) {
    registerStopHook({
      command: onStop.command,
      description: onStop.description || 'Skill completion hook'
    })
  }
  
  if (onTurnComplete) {
    registerTurnCompleteHook({
      command: onTurnComplete.command,
      description: onTurnComplete.description || 'Turn complete hook'
    })
  }
}

/**
 * Example: Notify user when skill completes
 */
const notifyOnComplete: HooksSettings = {
  onStop: {
    command: 'osascript -e \'display notification "Skill completed!" with title "Claude Code"\'',
    description: 'Desktop notification on completion'
  }
}

/**
 * Example: Log metrics when turn completes
 */
const logMetrics: HooksSettings = {
  onTurnComplete: {
    command: 'echo "Turn completed at $(date)" >> /tmp/claude-metrics.log',
    description: 'Log turn completion time'
  }
}

5. 技能搜索与发现

/**
 * Search for skills by name or description
 */
async function searchSkills(query: string): Promise<Array<{
  name: string
  description: string
  matchScore: number
}>> {
  const queryLower = query.toLowerCase()
  const allSkills = getBundledSkills()
  
  return allSkills
    .map(skill => {
      const nameMatch = skill.name.toLowerCase().includes(queryLower)
      const descMatch = skill.description.toLowerCase().includes(queryLower)
      
      let matchScore = 0
      if (nameMatch) matchScore += 10
      if (descMatch) matchScore += 5
      
      // Fuzzy matching bonus
      const fuzzyScore = calculateFuzzyMatch(queryLower, skill.name)
      matchScore += fuzzyScore
      
      return {
        name: skill.name,
        description: skill.description,
        matchScore
      }
    })
    .filter(skill => skill.matchScore > 0)
    .sort((a, b) => b.matchScore - a.matchScore)
}

/**
 * Calculate fuzzy match score (simple implementation)
 */
function calculateFuzzyMatch(query: string, target: string): number {
  const distance = levenshteinDistance(query, target)
  const maxLength = Math.max(query.length, target.length)
  return Math.max(0, 10 - (distance / maxLength) * 10)
}

6. 技能执行生成器

/**
 * Run skill generator to produce prompt blocks
 */
async function runSkillGenerator(
  skillName: string,
  args: string,
  context: ToolUseContext
): Promise<ContentBlockParam[]> {
  const skill = findSkillByName(skillName)
  
  if (!skill) {
    throw new Error(`Skill "${skillName}" not found`)
  }
  
  try {
    // Execute skill's getPromptForCommand
    const promptBlocks = await skill.getPromptForCommand(args, context)
    
    // Validate output
    if (!Array.isArray(promptBlocks)) {
      throw new Error('getPromptForCommand must return an array')
    }
    
    for (const block of promptBlocks) {
      if (!block.type || !['text', 'image', 'tool_use'].includes(block.type)) {
        throw new Error(`Invalid block type: ${(block as any).type}`)
      }
    }
    
    return promptBlocks
  } catch (error) {
    console.error(`Skill execution failed: ${skillName}`, error)
    
    // Return error as text block
    return [{
      type: 'text',
      text: `Skill "${skillName}" failed: ${error instanceof Error ? error.message : String(error)}`
    }]
  }
}

7. 完整 Skill 示例

/**
 * Complete example: Code Review Skill
 */

import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
import type { ToolUseContext } from '../index.js'
import { registerBundledSkill } from '../index.js'

const REVIEW_SKILL_FILES = {
  'checklist.md': `
# Code Review Checklist

## Correctness
- [ ] Logic is sound
- [ ] Edge cases handled
- [ ] No off-by-one errors
- [ ] Null/undefined checks

## Security
- [ ] No SQL injection risks
- [ ] Input validation present
- [ ] Authentication checks
- [ ] No hardcoded secrets

## Performance
- [ ] No unnecessary loops
- [ ] Efficient data structures
- [ ] Caching where appropriate
- [ ] No memory leaks

## Maintainability
- [ ] Clear variable names
- [ ] Comments explain "why"
- [ ] Functions are small
- [ ] DRY principles followed
`
}

const REVIEW_SKILL_MD = `
---
name: code-review
description: Expert code review with focus on bugs, security, and best practices
aliases: ['review', 'pr-review']
argumentHint: '<file-path> [focus-areas]'
allowedTools: ['FileReadTool', 'GrepTool', 'GlobTool']
model: 'claude-sonnet-4-5-20260101'
---

# Code Review Skill

You are an expert code reviewer with deep knowledge of:
- Security vulnerabilities (OWASP Top 10)
- Performance optimization patterns
- Language-specific best practices
- Maintainability and code smells

## Review Process

1. **First Pass**: Read entire file for understanding
2. **Second Pass**: Deep analysis of each concern area
3. **Third Pass**: Prioritize and format findings

## Output Format

Structure your review as:

### Summary
Brief overview (2-3 sentences)

### Critical Issues 🔴
Must fix before merge

### High Priority 🟡
Important but not blocking

### Medium Priority 🟢
Suggestions for improvement

### Low Priority ⚪
Nice-to-have enhancements

### Positive Notes 👍
What was done well
`

export function registerCodeReviewSkill(): void {
  const { frontmatter, content: SKILL_BODY } = parseFrontmatter(REVIEW_SKILL_MD)
  
  registerBundledSkill({
    name: frontmatter.name as string,
    description: frontmatter.description as string,
    aliases: frontmatter.aliases as string[],
    argumentHint: frontmatter.argumentHint as string,
    allowedTools: frontmatter.allowedTools as string[],
    model: frontmatter.model as string,
    userInvocable: true,
    files: REVIEW_SKILL_FILES,
    
    async getPromptForCommand(args: string, context: ToolUseContext) {
      const parts: string[] = [SKILL_BODY.trimStart()]
      
      if (args) {
        parts.push(`## Review Request\n\nTarget: ${args}`)
      }
      
      return [{ type: 'text', text: parts.join('\n\n') }]
    },
    
    hooks: {
      onStop: {
        command: 'echo "✓ Code review complete!"',
        description: 'Show completion marker'
      }
    }
  })
}

工作流程

第一步:技能需求分析 (10 分钟)

  1. 明确技能目标
    - 这个技能解决什么问题?
    - 目标用户是谁?
    - 需要什么工具权限?
    - 是否需要提取文件到磁盘?
  2. 定义输入输出
    // 输入参数 schema
    const inputSchema = z.object({
      // 定义你的参数
    })
    
    // 输出格式
    type Output = {
      // 定义你的输出
    }

第二步:技能实现 (20 分钟)

基于 Claude Code最佳实践实现你的技能,包括 frontmatter定义、skill body markdown、文件提取、参数验证和钩子注册。

第三步:测试与优化 (15 分钟)

测试检查清单

  • 基本功能测试
    • 空参数处理
    • 有效参数处理
    • 无效参数错误提示
    • 文件提取成功验证
  • 集成测试
    • 技能注册成功
    • 技能搜索找到
    • 技能执行正常
    • 钩子触发正确
  • 边界测试
    • 大参数处理
    • 特殊字符处理
    • 并发执行测试
    • 内存泄漏检查

规则

  • ✅ 使用 frontmatter定义技能元数据
  • ✅ 为复杂技能提供文件提取支持
  • ✅ 实现健壮的参数验证和错误提示
  • ✅ 使用 HooksSettings 注册生命周期钩子
  • ✅ 提供清晰的技能描述和使用说明
  • ❌ 不要在技能名称中使用空格或非 kebab-case
  • ❌ 不要忘记处理参数为空的情况
  • ❌ 不要假设文件提取总是成功
  • ❌ 不要忽略技能的错误处理和降级策略

输出格式

📋 技能定义

name: skill-name
description: 清晰的技能描述
aliases: [alias1, alias2]
argumentHint: '<required> [optional]'
allowedTools: [Tool1, Tool2]
model: claude-sonnet-4-5-20260101
userInvocable: true

🏗️ 架构设计

使用流程图展示技能执行流程。

📝 实现代码

提供完整的 TypeScript 实现代码,包括 frontmatter、skill body、文件提取、参数验证和钩子。

🔍 测试用例

详细的单元测试、集成测试、边界测试计划。

📚 使用文档

技能的使用说明、示例调用、常见问题解答。

⚠️ 注意事项

已知的限制、使用场景的边界条件、性能考虑。

交付物清单

最终报告应包含:

  • 技能定义和元数据
  • 完整的 TypeScript 实现代码
  • 文件提取机制(如果需要)
  • 参数验证逻辑
  • 钩子系统实现
  • 测试计划和测试用例
  • 使用文档和示例
  • 性能基准和优化建议

🤖 AI IDE 开发指南

本部分指导 AI IDE 按照 Claude Code的最佳实践开发 Bundled Skill系统。

AI IDE 开发前检查

Frontmatter 验证

必须字段:
  - name: kebab-case命名
  - description: 清晰的技能描述
  - argumentHint: '<required> [optional]'格式
  
可选字段:
  - aliases: 别名列表
  - allowedTools: 允许的工具列表
  - model: 目标模型
  - whenToUse: 使用时机说明

警告信号:
  - name 包含空格或大写字母
  - description 过于模糊
  - argumentHint 格式不正确

文件提取准备

必须检查:
  - SKILL_FILES 对象定义
  - 相对路径格式正确
  - 文件内容无 PII 泄露
  
目录结构:
  - examples/*.md - 使用示例
  - templates/*.md - 模板文件
  - rules/*.md - 规则文档

AI IDE 开发中指导

实时技能开发监控

当创建新技能时,AI IDE应该:

  1. 命名规范检查
    // ✅ 正确的命名
    const skill = { name: 'code-review' }  // kebab-case
    const skill = { name: 'debug' }
    
    // ❌ 错误的命名
    const skill = { name: 'codeReview' }  // camelCase
    const skill = { name: 'Code Review' }  // 含空格
    // AI IDE 应该:立即警告并建议修正
  2. Frontmatter解析验证
    // AI IDE 应该验证 frontmatter 解析
    const { frontmatter, content } = parseFrontmatter(SKILL_MD)
    
    // 必需字段检查
    if (!frontmatter.name || !frontmatter.description) {
      throw new Error('Missing required frontmatter fields')
    }
    
    // 类型安全转换
    const name = String(frontmatter.name)
    const description = String(frontmatter.description)
  3. 参数处理优化
    // AI IDE 应该推荐健壮的参数解析
    function parseSkillArgs(args: string): ParsedArgs {
      try {
        // 尝试 JSON 解析(结构化输入)
        return JSON.parse(args)
      } catch {
        // 降级为空格分隔的简单解析
        const parts = args.trim().split(/\s+/)
        return { target: parts[0] || '.', rest: parts.slice(1) }
      }
    }

钩子系统管理

AI IDE应该提供:

  • onStop 钩子: 技能完成时的清理操作
  • onTurnComplete 钩子: 每轮结束后的处理
  • 错误隔离: 钩子错误不影响主流程
  • 命令注入防护: 验证 shell 命令安全性

AI IDE 完成后验证

技能开发健康度评分卡

Frontmatter (0-10分):
  - 字段完整性
  - 格式正确性
  - 描述清晰度

文件提取 (0-10分):
  - 路径正确性
  - 内容安全性
  - 目录创建可靠性

参数处理 (0-10分):
  - JSON 解析健壮性
  - 降级策略合理性
  - 错误提示友好性

钩子系统 (0-10分):
  - 生命周期覆盖
  - 错误隔离
  - 资源清理

搜索发现 (0-10分):
  - 名称匹配准确度
  - 描述匹配相关度
  - 模糊搜索智能性

总分评级:
  - 90-100: Excellent (生产就绪)
  - 75-89: Good (少量优化)
  - 60-74: Fair (需要改进)
  - <60: Poor (建议重构)

自动化测试清单

AI IDE应该运行:

# 1. Frontmatter 测试
test('parses name correctly', () => {...})
test('validates required fields', () => {...})

# 2. 文件提取测试
test('creates directory structure', () => {...})
test('writes files atomically', () => {...})

# 3. 参数处理测试
test('handles JSON input', () => {...})
test('handles string input', () => {...})
test('shows helpful errors', () => {...})

# 4. 钩子测试
test('onStop fires on completion', () => {...})
test('errors dont break main flow', () => {...})

# 5. 搜索测试
test('finds by name', () => {...})
test('finds by description', () => {...})
test('ranks by relevance', () => {...})

AI IDE 常见陷阱检测

🔴 高危问题(必须修复)

// ❌ Frontmatter 缺少必需字段
const skill = {
  name: 'my-skill'
  // missing description!
}
// AI IDE 应该:立即警告 + 阻止注册

// ❌ 文件提取不安全
const path = userInput  // 未验证的用户输入!
await writeFile(path, content)  // 路径遍历攻击风险
// AI IDE 应该:建议使用 join(extractDir, relativePath)

// ❌ 参数无验证
async getPromptForCommand(args: string) {
  return [{ type: 'text', text: args }]  // 直接使用未验证的参数!
}
// AI IDE 应该:建议添加参数解析和验证

🟡 中等风险(建议优化)

// ⚠️ 错误提示不友好
throw new Error('Invalid args')
// AI IDE 应该:建议提供详细的错误信息和修复建议

// ⚠️ 缺少超时
await longRunningOperation()  // 可能永远等待
// AI IDE 应该:建议添加 AbortSignal.timeout()

🟢 低风险(可选改进)

// 💡 可以优化的模式
const skills = allSkills.filter(s => s.name.includes(query))
// AI IDE 可以建议:使用 fuzzy search 提升匹配质量

AI IDE 代码审查检查清单

在 PR/MR阶段,AI IDE应该自动检查:

Frontmatter

  • name 使用 kebab-case
  • description 清晰具体
  • argumentHint 格式正确
  • aliases 有助于发现
  • allowedTools 合理限制

文件提取

  • 路径使用相对路径
  • 目录自动创建
  • 原子写入(flush:true)
  • 无 PII 泄露

参数处理

  • JSON 解析有 try-catch
  • 降级策略合理
  • 错误信息有帮助
  • Zod 验证 schema

钩子系统

  • onStop 清理资源
  • onTurnComplete 记录日志
  • 错误不中断主流程
  • 命令注入防护

搜索发现

  • 名称匹配准确
  • 描述匹配相关
  • 模糊搜索智能
  • 排序合理

AI IDE 集成实现示例

interface SkillRule {
  id: string
  description: string
  severity: 'error' | 'warning' | 'info'
  check: (skill: BundledSkill, files: SkillFiles) => Violation[]
  fix?: (violation: Violation) => Fix
}

const rules: SkillRule[] = [
  {
    id: 'SKILL-001',
    description: 'Skill name must be kebab-case',
    severity: 'error',
    check: (skill) => {
      if (!/^[a-z][a-z0-9-]*$/.test(skill.name)) {
        return [{
          message: `Invalid skill name format: ${skill.name}`,
          location: skill.nameDefinition
        }]
      }
      return []
    },
    fix: () => ({ type: 'convert', format: 'kebab-case' })
  },
  {
    id: 'SKILL-002',
    description: 'Must have description in frontmatter',
    severity: 'error',
    check: (skill) => {
      if (!skill.frontmatter.description) {
        return [{
          message: 'Missing description field',
          location: skill.frontmatterLocation
        }]
      }
      return []
    }
  },
  {
    id: 'SKILL-003',
    description: 'File paths must be relative',
    severity: 'error',
    check: (skill, files) => {
      for (const path of Object.keys(files)) {
        if (path.startsWith('/') || path.includes('..')) {
          return [{
            message: `Absolute or unsafe path: ${path}`,
            location: path
          }]
        }
      }
      return []
    },
    fix: () => ({ type: 'sanitize_paths' })
  },
  {
    id: 'SKILL-004',
    description: 'Should handle parse errors gracefully',
    severity: 'warning',
    check: (skill) => {
      const source = skill.getPromptForCommand.toString()
      if (!source.includes('try') && !source.includes('catch')) {
        return [{
          message: 'No error handling for argument parsing',
          location: skill.getPromptForCommand
        }]
      }
      return []
    }
  }
  // ... 更多规则
]

AI IDE 学习路径

为了让 AI IDE更好地理解技能开发规范:

  1. 第一阶段: 学习 frontmatter 语法和必需字段
  2. 第二阶段: 理解文件提取机制和安全考虑
  3. 第三阶段: 掌握参数解析和验证模式
  4. 第四阶段: 实现钩子系统和生命周期管理
  5. 第五阶段: 提供智能搜索发现和排序优化

通过学习路径,AI IDE可以成长为能够独立设计和审查技能开发系统的专家。

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.