Skip to content
Development
Hook

Hooks

What skill-semver runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
skill-semver
171 skill1 hook

Claude Code

> /plugin marketplace add cathy-kim/skill-semver
> /plugin install skill-semver@skill-semver-marketplace

What fires, and when

PostToolUse

  • MatchesWrite|Editnpx tsx hooks/skill-version-hook.ts
Read hooks/hooks.json

Where it lives

  • hooks/skill-version-hook.tsRunsGitHub
    Read the script
    #!/usr/bin/env npx tsx
    
    /**
     * Skill Version Hook v1.1.0
     *
     * SKILL.md 파일이 수정될 때 자동으로 버전 백업을 생성합니다.
     *
     * Hook Event: PostToolUse (Write, Edit tools)
     *
     * 동작:
     * 1. Write/Edit 도구가 SKILL.md를 수정했는지 확인
     * 2. SKILL.md에서 버전 정보 추출 (pre-release 지원: 1.0.0-alpha, 1.0.0-beta.1)
     * 3. releases/ 폴더에 버전별 백업 생성
     * 4. CHANGELOG.md 업데이트
     * 5. Last Updated 날짜 자동 업데이트
     * 6. 로그 출력
     *
     * 파일 명명 규칙: v{VERSION}_{YYYY-MM-DD}_SKILL.md
     *
     * Changelog:
     * - v1.1.0: Pre-release 지원, Last Updated 자동화, 경로 버그 수정, 성능 최적화
     * - v1.0.0: 초기 버전
     */
    
    import * as fs from "fs";
    import * as path from "path";
    
    // ============================================================================
    // Types
    // ============================================================================
    
    interface PostToolUseInput {
      session_id: string;
      tool_name: string;
      tool_input: {
        file_path?: string;
        content?: string;
        old_string?: string;
        new_string?: string;
      };
      tool_output?: {
        success?: boolean;
        error?: string;
      };
      transcript_path?: string;
    }
    
    interface HookResult {
      continue: boolean;
      message?: string;
    }
    
    // ============================================================================
    // Constants
    // ============================================================================
    
    const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
    const LOG_DIR = path.join(PROJECT_DIR, ".claude", "hooks", "logs");
    
    // ============================================================================
    // Main Hook
    // ============================================================================
    
    async function main(): Promise<void> {
      try {
        // Read input from stdin
        const inputData = fs.readFileSync(0, "utf-8");
        const input: PostToolUseInput = JSON.parse(inputData);
    
        const result = await processHook(input);
    
        // Output result
        console.log(JSON.stringify(result));
      } catch (error: any) {
        // Graceful degradation - don't block the session
        console.log(
          JSON.stringify({
            continue: true,
            message: `[skill-version-hook] Error: ${error.message}`,
          })
        );
      }
    }
    
    async function processHook(input: PostToolUseInput): Promise<HookResult> {
      const { tool_name, tool_input, tool_output } = input;
    
      // 1. Check if this is a Write or Edit tool
      if (tool_name !== "Write" && tool_name !== "Edit") {
        return { continue: true };
      }
    
      // 2. Check if the tool succeeded
      if (tool_output?.success === false) {
        return { continue: true };
      }
    
      // 3. Check if the file is a SKILL.md
      const filePath = tool_input?.file_path;
      if (!filePath || !isSkillMdFile(filePath)) {
        return { continue: true };
      }
    
      // 4. Extract skill name from path
      const skillName = extractSkillName(filePath);
      if (!skillName) {
        return { continue: true };
      }
    
      // 5. Read the SKILL.md content once (optimization: single read)
      let content: string;
      try {
        content = fs.readFileSync(filePath, "utf-8");
      } catch (error: any) {
        log(`[skill-version-hook] Failed to read ${filePath}: ${error.message}`);
        return { continue: true };
      }
    
      // 6. Extract version from content (supports pre-release: 1.0.0-alpha, 1.0.0-beta.1)
      const version = extractVersionFromContent(content);
      if (!version) {
        log(`[skill-version-hook] No version found in ${filePath}, skipping backup`);
        return {
          continue: true,
          message: `[skill-version-hook] No version header found in ${skillName}/SKILL.md`,
        };
      }
    
      // 7. Create releases directory if needed
      const releasesDir = path.join(path.dirname(filePath), "releases");
      if (!fs.existsSync(releasesDir)) {
        fs.mkdirSync(releasesDir, { recursive: true });
      }
    
      // 8. Generate backup filename (sanitize pre-release for filename)
      const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
      const safeVersion = version.replace(/[^a-zA-Z0-9.-]/g, "-");
      const backupFilename = `v${safeVersion}_${today}_SKILL.md`;
      const backupPath = path.join(releasesDir, backupFilename);
    
      // 9. Check if backup already exists for this version
      if (fs.existsSync(backupPath)) {
        log(`[skill-version-hook] Backup already exists: ${backupFilename}`);
        return {
          continue: true,
          message: `[skill-version-hook] Backup already exists for ${skillName} v${version}`,
        };
      }
    
      // 10. Update Last Updated date in SKILL.md
      const updatedContent = updateLastUpdated(content, today);
      if (updatedContent !== content) {
        try {
          fs.writeFileSync(filePath, updatedContent, "utf-8");
          content = updatedContent;
          log(`[skill-version-hook] Updated Last Updated to ${today}`);
        } catch (error: any) {
          log(`[skill-version-hook] Failed to update Last Updated: ${error.message}`);
        }
      }
    
      // 11. Create backup
      try {
        fs.writeFileSync(backupPath, content, "utf-8");
        log(`[skill-version-hook] Created backup: ${backupFilename}`);
    
        // 12. Update CHANGELOG.md
        const changelogPath = path.join(path.dirname(filePath), "CHANGELOG.md");
        updateChangelog(changelogPath, skillName, version, today);
    
        // 13. Add initial development notice for 0.x.x versions
        const versionNote = version.startsWith("0.")
          ? " (Initial Development)"
          : "";
    
        return {
          continue: true,
          message: `[skill-version-hook] Backed up ${skillName}/SKILL.md to releases/${backupFilename}${versionNote}`,
        };
      } catch (error: any) {
        log(`[skill-version-hook] Failed to create backup: ${error.message}`);
        return {
          continue: true,
          message: `[skill-version-hook] Failed to backup: ${error.message}`,
        };
      }
    }
    
    // ============================================================================
    // Helper Functions
    // ============================================================================
    
    /**
     * Check if the file path is a SKILL.md file
     * Fixed: Use regex for cross-platform path separator compatibility
     */
    function isSkillMdFile(filePath: string): boolean {
      // Normalize path and convert to forward slashes for co

Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.

@cathy-kim
Ships withskill-semver

Automatic version control for Claude Code Skills with semantic versioning, auto-backup, and changelog generation.

Stars on GitHub

Momentum

stars in total
17
Star history of cathy-kim/skill-semver on GitHub, a chart by star-history.com

More plugins that ship hooks.

superpowers

superpowers

A development methodology for coding agents that makes the agent brainstorm before building, follow plans, run parallel work and finish branches in a disciplined way. You get fewer skipped steps and more consistent results from your coding assistant.

15 skills1 hook311k
@obra@obra
Install Plugin
ponytail

ponytail

A Claude Code plugin with skills for auditing a whole repo, reviewing a change, listing deferred shortcut comments, and showing measured savings and a quick command reference.

6 skills10 hooks188k
@dietrichgebert@dietrichgebert
Install Plugin
agent-skills

agent-skills

Walks a software change from a written spec through design, testing, code review, CI/CD, and release, applying the matching engineering skill at each stage. Useful for developers using Claude Code on full development workflows.

25 skills+3112k
@addyosmani@addyosmani
Install Plugin
planning-with-files

planning-with-files

Persistent file-based planning for AI coding agents on long-running, multi-step tasks. It keeps task_plan.md, findings.md and progress.md on disk, so work can resume after /clear or context compaction.

6 skills+228k
@othmanadi@othmanadi
Install Plugin
gsd-core

gsd-core

A spec-driven development workflow for Claude Code that guides a project through planning, phases, milestone audits and fixes. Includes skills to generate tests from UAT criteria and to audit completed work.

72 skills+311k
@open-gsd@open-gsd
Install Plugin
superpowers-zh

superpowers-zh

Chinese-language skill pack for Claude Code that adds workflow guidance for brainstorming, TDD, debugging, and code review, plus Chinese conventions for commits, documentation, and domestic Git platforms like Gitee and Coding.net.

21 skills1 hook8.5k
@jnmetacode@jnmetacode
Install Plugin
socraticode

socraticode

Gives Claude Code semantic search, dependency graph and architecture context over a codebase, so an AI assistant can explore and understand a project's code. Includes skills for indexing a project and managing its file watching.

2 skills+33.4k
@giancarloerra@giancarloerra
Install Plugin
cocoindex-code

cocoindex-code

A lightweight code search engine that uses AST-based semantic search with local embeddings and incremental indexing. It helps Claude Code users find code faster and more efficiently.

1 skill1 MCP+13k
@cocoindex-io@cocoindex-io
Install Plugin

Questions about the hooks in skill-semver.

Which coding agents can use the hooks in skill-semver?
The hooks in skill-semver install in Claude Code and Cursor: each runs Claude Code hooks from .claude/settings.json, so copy the hooks there.