hook-creator

安装量: 58
排名: #12929

安装

npx skills add https://github.com/oimiragieo/agent-studio --skill hook-creator

Hook Creator Skill

Creates, validates, and registers hooks for the multi-agent orchestration framework.

ROUTER UPDATE REQUIRED (CRITICAL - DO NOT SKIP)

After creating ANY hook, you MUST update documentation:

  1. Add to .claude/hooks/README.md under appropriate category
  2. Register in config.yaml or settings.json if required
  3. Update learnings.md with hook summary

Verification:

grep "" .claude/hooks/README.md || echo "ERROR: hooks/README.md NOT UPDATED!"

WHY: Hooks not documented are invisible and unmaintainable.

Overview

This skill creates hooks for the Claude Code framework:

Pre-tool execution - Safety validation before commands run Post-tool execution - Logging, memory updates, telemetry Session lifecycle - Initialize context, cleanup on exit Memory management - Auto-extract learnings, format memory files Routing enforcement - Ensure Router-First protocol compliance Hook Types Type Location Purpose When Triggered Safety .claude/hooks/safety/ Validate commands, block dangerous ops Before Bash/Write/Edit Memory .claude/hooks/memory/ Auto-update learnings, extract insights After task completion Routing .claude/hooks/routing/ Enforce router-first protocol On UserPromptSubmit Session .claude/hooks/session/ Initialize/cleanup sessions Session start/end Claude Code Hook Types Hook Event When Triggered Use Case PreToolUse Before tool executes Validation, blocking, permission checks PostToolUse After tool completes Logging, cleanup, notifications UserPromptSubmit Before model sees message Routing, intent analysis, filtering Workflow Steps Reference Hook

Use .claude/hooks/routing/router-enforcer.cjs as the canonical reference hook.

Before finalizing any hook, compare against router-enforcer structure:

Has proper CommonJS exports (module.exports) Exports required functions for hook type (validate, main, etc.) Has comprehensive test file (.test.cjs) Has proper error handling (try/catch, graceful fallbacks) Returns correct response format for hook type Step 1: Gather Hook Requirements

Before creating a hook, gather:

Purpose: What should this hook do? Trigger: When should it run? (pre-tool, post-tool, session event) Target tools: Which tools does it apply to? (Bash, Write, Edit, Read) Behavior: Block operation or warn only? Exit codes: What indicates success/failure? // Example requirements gathering { purpose: "Validate git push commands to prevent force push", trigger: "pre-tool (Bash)", target_tools: ["Bash"], behavior: "block if force push detected", exit_codes: { 0: "allow", 1: "block" } }

Step 2: Determine Hook Type and Location If hook does... Type Location Validates commands Safety .claude/hooks/safety/ Modifies routing Routing .claude/hooks/routing/ Updates memory Memory .claude/hooks/memory/ Session init/cleanup Session .claude/hooks/session/

Naming Convention: -.cjs

Examples:

validate-git-force-push.cjs enforce-tdd-workflow.cjs extract-workflow-learnings.cjs memory-reminder.cjs Step 3: Generate Hook Code (CJS Format)

All hooks use CommonJS format and follow this template:

'use strict';

/* * {Hook Name} * * Type: {pre|post}-{tool} | session-{start|end} | user-prompt * Purpose: {One line description} * Trigger: {When this hook runs} * * Exit codes: * - 0: Allow operation (with optional warning) * - 1: Block operation (when in blocking mode) * * Environment: * {HOOK_NAME}_MODE=block|warn|off (default: warn) /

const fs = require('fs'); const path = require('path');

// Find project root by looking for .claude directory function findProjectRoot() { let dir = __dirname; while (dir !== path.parse(dir).root) { if (fs.existsSync(path.join(dir, '.claude'))) { return dir; } dir = path.dirname(dir); } return process.cwd(); }

const PROJECT_ROOT = findProjectRoot(); const ENFORCEMENT_MODE = process.env.HOOK_NAME_MODE || 'warn';

/* * Parse hook input from Claude Code * Claude Code passes JSON via process.argv[2] for hooks * @returns {Object|null} Parsed hook input or null / function parseHookInput() { try { if (process.argv[2]) { return JSON.parse(process.argv[2]); } } catch (e) { // Fallback for testing or invalid input } return null; }

/* * Validate hook - called by Claude Code or programmatically * @param {Object} context - Hook context with tool info * @param {string} context.tool - Tool name (Bash, Write, Edit, Read) * @param {Object} context.parameters - Tool parameters * @returns {{ valid: boolean, error: string, warning?: string }} / function validate(context) { const { tool, parameters } = context;

// YOUR VALIDATION LOGIC HERE

// Return validation result return { valid: true, error: '' }; }

/* * Main execution for CLI hook usage / function main() { // Skip if enforcement is off if (ENFORCEMENT_MODE === 'off') { process.exit(0); }

const hookInput = parseHookInput(); if (!hookInput) { process.exit(0); }

// Get tool name and input const toolName = hookInput.tool_name || hookInput.tool; const toolInput = hookInput.tool_input || hookInput.input || {};

// Run validation const result = validate({ tool: toolName, parameters: toolInput });

if (!result.valid) { if (ENFORCEMENT_MODE === 'block') { console.error(BLOCKED: ${result.error}); process.exit(1); } else { console.warn(WARNING: ${result.error}); process.exit(0); } }

if (result.warning) { console.warn(WARNING: ${result.warning}); }

process.exit(0); }

// Run main if executed directly if (require.main === module) { main(); }

// Export for programmatic use and testing module.exports = { validate, findProjectRoot, PROJECT_ROOT, };

Step 4: Create Test File

Every hook MUST have a corresponding test file:

'use strict';

const { validate } = require('./hook-name.cjs');

describe('Hook Name', () => { test('allows valid operations', () => { const result = validate({ tool: 'Bash', parameters: { command: 'git status' }, }); expect(result.valid).toBe(true); expect(result.error).toBe(''); });

test('blocks dangerous operations', () => { const result = validate({ tool: 'Bash', parameters: { command: 'git push --force' }, }); expect(result.valid).toBe(false); expect(result.error).toContain('force push'); });

test('handles missing parameters gracefully', () => { const result = validate({ tool: 'Bash', parameters: {}, }); expect(result.valid).toBe(true); }); });

Step 5: Register Hook (If Needed)

Some hooks require registration in config files:

For pre/post-tool hooks (settings.json):

{ "hooks": { "pre-tool": [".claude/hooks/safety/hook-name.cjs"], "post-tool": [".claude/hooks/memory/hook-name.cjs"] } }

For event hooks (config.yaml):

hooks: UserPromptSubmit: - path: .claude/hooks/routing/hook-name.cjs type: command SessionStart: - path: .claude/hooks/session/hook-name.cjs type: command

Step 6: Update Documentation (MANDATORY - BLOCKING)

After creating a hook, update .claude/hooks/README.md:

{Hook Name} (hook-name.cjs)

{Description of what the hook does}

When it runs: {Trigger condition} What it checks/does: {Detailed behavior}

Verify with:

grep "hook-name" .claude/hooks/README.md || echo "ERROR: Not documented!"

Step 7: System Impact Analysis (MANDATORY)

This analysis is MANDATORY. Hook creation is INCOMPLETE without it.

After creating a hook:

Settings Registration (BLOCKING)

Add to .claude/settings.json PreToolUse/PostToolUse/etc. Verify with: grep "hook-name" .claude/settings.json

Test Coverage (BLOCKING)

Create .test.cjs file with minimum 10 test cases Run tests: node .claude/hooks//.test.cjs

Documentation

Update .claude/docs/ if hook adds new capability Add usage examples

Related Hooks

Check if hook affects other hooks in same trigger category Document interaction patterns

Full Checklist:

[HOOK-CREATOR] System Impact Analysis for:

  1. HOOK FILE CREATED [ ] Created at .claude/hooks//.cjs [ ] Follows CJS format with validate() export [ ] Has main() function for CLI execution [ ] Handles graceful degradation (warn by default)

  2. TEST FILE CREATED (minimum 10 test cases) [ ] Created at .claude/hooks//.test.cjs [ ] Tests valid operations (3+ cases) [ ] Tests blocked operations (3+ cases) [ ] Tests edge cases (3+ cases) [ ] Tests error handling (1+ cases)

  3. DOCUMENTATION UPDATED [ ] Added to .claude/hooks/README.md [ ] Documented trigger conditions [ ] Documented exit codes

  4. REGISTRATION (BLOCKING) [ ] Added to settings.json (pre/post-tool hooks) [ ] Added to config.yaml (event hooks) [ ] Verified: grep "" .claude/settings.json

  5. MEMORY UPDATED [ ] Added to learnings.md with hook summary

BLOCKING: If ANY item above is missing, hook creation is INCOMPLETE.

CLI Reference

Create hook using CLI tool

node .claude/tools/hook-creator/create-hook.mjs \ --name "hook-name" \ --type "PreToolUse|PostToolUse|UserPromptSubmit" \ --purpose "Description of what the hook does" \ --category "safety|routing|memory|audit|security|validation|custom" \ --matcher "Edit|Write|Bash" # Optional: tool matcher regex

List all hooks

node .claude/tools/hook-creator/create-hook.mjs --list

Validate hook structure

node .claude/tools/hook-creator/create-hook.mjs --validate ""

Assign to agents

node .claude/tools/hook-creator/create-hook.mjs --assign "name" --agents "agent1,agent2"

Unregister hook

node .claude/tools/hook-creator/create-hook.mjs --unregister ""

Test with sample input

node .claude/hooks//.cjs '{"tool_name":"Edit","tool_input":{"file_path":"test.js"}}'

Hook Patterns Reference Pattern 1: Safety Validator (Pre-Tool)

For validating commands before execution:

'use strict';

/* * Validate Git Force Push * Prevents accidental force pushes to protected branches /

const PROTECTED_BRANCHES = ['main', 'master', 'production'];

function validate(context) { const { tool, parameters } = context;

if (tool !== 'Bash') { return { valid: true, error: '' }; }

const command = parameters?.command || '';

// Check for force push if (command.includes('git push') && (command.includes('--force') || command.includes('-f'))) { // Check if pushing to protected branch for (const branch of PROTECTED_BRANCHES) { if (command.includes(branch)) { return { valid: false, error: Force push to ${branch} blocked. Use --force-with-lease instead., }; } }

return {
  valid: true,
  error: '',
  warning: 'Force push detected. Ensure you know what you are doing.',
};

}

return { valid: true, error: '' }; }

module.exports = { validate };

Pattern 2: Memory Extractor (Post-Tool)

For extracting learnings after task completion:

'use strict';

/* * Extract Workflow Learnings * Automatically captures patterns from completed workflows /

const fs = require('fs'); const path = require('path');

function findProjectRoot() { let dir = __dirname; while (dir !== path.parse(dir).root) { if (fs.existsSync(path.join(dir, '.claude'))) return dir; dir = path.dirname(dir); } return process.cwd(); }

const LEARNINGS_PATH = path.join(findProjectRoot(), '.claude/context/memory/learnings.md');

function extractLearnings(context) { const { tool, parameters, result } = context;

// Only process completed tasks if (!result || result.status !== 'completed') { return { extracted: false }; }

// Extract patterns from result const learnings = [];

if (result.patterns) { learnings.push(...result.patterns); }

if (result.decisions) { learnings.push(...result.decisions); }

if (learnings.length === 0) { return { extracted: false }; }

// Append to learnings file const entry = \n## [${new Date().toISOString().split('T')[0]}] ${context.taskName || 'Task'}\n\n; const content = learnings.map(l => - ${l}).join('\n');

fs.appendFileSync(LEARNINGS_PATH, entry + content + '\n');

return { extracted: true, count: learnings.length }; }

module.exports = { extractLearnings };

Pattern 3: Routing Enforcer (User Prompt)

For enforcing routing protocols:

'use strict';

/* * Router First Enforcer * Ensures all requests go through the Router agent /

function validate(context) { const { prompt, currentAgent } = context;

// Skip if already routed if (currentAgent === 'router') { return { valid: true, error: '' }; }

// Skip slash commands (handled by skill system) if (prompt && prompt.trim().startsWith('/')) { return { valid: true, error: '' }; }

// Suggest routing return { valid: true, error: '', warning: 'Consider using Router to spawn appropriate agent via Task tool.', }; }

module.exports = { validate };

Pattern 4: Session Initializer

For session lifecycle management:

'use strict';

/* * Session Memory Initializer * Reminds agents to read memory files at session start /

const fs = require('fs'); const path = require('path');

function findProjectRoot() { let dir = __dirname; while (dir !== path.parse(dir).root) { if (fs.existsSync(path.join(dir, '.claude'))) return dir; dir = path.dirname(dir); } return process.cwd(); }

const MEMORY_FILES = [ '.claude/context/memory/learnings.md', '.claude/context/memory/issues.md', '.claude/context/memory/decisions.md', ];

function initialize() { const root = findProjectRoot();

console.log('\n' + '='.repeat(50)); console.log(' SESSION MEMORY REMINDER'); console.log('='.repeat(50)); console.log('\n Before starting work, read these memory files:');

for (const file of MEMORY_FILES) { const fullPath = path.join(root, file); if (fs.existsSync(fullPath)) { const stats = fs.statSync(fullPath); const modified = stats.mtime.toISOString().split('T')[0]; console.log(- ${file} (updated: ${modified})); } }

console.log('\n' + '='.repeat(50) + '\n');

return { initialized: true }; }

// Run on direct execution if (require.main === module) { initialize(); }

module.exports = { initialize };

Examples Security Validation Hook node .claude/tools/hook-creator/create-hook.mjs \ --name "secret-detector" \ --type "PreToolUse" \ --purpose "Blocks commits containing secrets or credentials" \ --category "security" \ --matcher "Bash"

Audit Logging Hook node .claude/tools/hook-creator/create-hook.mjs \ --name "operation-logger" \ --type "PostToolUse" \ --purpose "Logs all file modifications to audit trail" \ --category "audit"

Intent Analysis Hook node .claude/tools/hook-creator/create-hook.mjs \ --name "intent-classifier" \ --type "UserPromptSubmit" \ --purpose "Classifies user intent for intelligent routing" \ --category "routing"

Workflow Integration

This skill is part of the unified artifact lifecycle. For complete multi-agent orchestration:

Router Decision: .claude/workflows/core/router-decision.md

How the Router discovers and invokes this skill's artifacts

Artifact Lifecycle: .claude/workflows/core/skill-lifecycle.md

Discovery, creation, update, deprecation phases Version management and registry updates CLAUDE.md integration requirements

External Integration: .claude/workflows/core/external-integration.md

Safe integration of external artifacts Security review and validation phases Cross-Reference: Creator Ecosystem

This skill is part of the Creator Ecosystem. After creating a hook, consider if companion artifacts are needed:

Need Creator to Invoke Command Dedicated skill for hook logic skill-creator Skill({ skill: 'skill-creator' }) Agent that uses this hook agent-creator Skill({ skill: 'agent-creator' }) Workflow for hook testing workflow-creator Create in .claude/workflows/ Schema for hook config schema-creator Create in .claude/schemas/ Template for hook scaffold template-creator Create in .claude/templates/ Integration Workflow

After creating a hook that needs additional capabilities:

// 1. Hook created but needs dedicated skill Skill({ skill: 'skill-creator' }); // Create skill that encapsulates hook logic

// 2. Hook needs to be assigned to agent // Update agent's workflow to include hook awareness

// 3. Hook needs workflow for testing // Create workflow in .claude/workflows/-test-workflow.md

Post-Creation Checklist for Ecosystem Integration

After hook is fully created and validated:

[ ] Does hook need a skill wrapper? -> Use skill-creator [ ] Does hook need dedicated agent? -> Use agent-creator [ ] Does hook need testing workflow? -> Create workflow [ ] Should hook be enabled by default? -> Update config.yaml [ ] Does hook interact with other hooks? -> Document in README.md

Iron Laws of Hook Creation

These rules are INVIOLABLE. Breaking them causes silent failures.

  1. NO HOOK WITHOUT validate() EXPORT
  2. Every hook MUST export validate() function
  3. Hooks without validate() cannot be called programmatically

  4. NO HOOK WITHOUT main() FOR CLI

  5. Every hook MUST have main() for CLI execution
  6. Run only when require.main === module

  7. NO HOOK WITHOUT GRACEFUL DEGRADATION

  8. Default to 'warn' mode, not 'block'
  9. Use environment variables for enforcement mode
  10. Never crash on malformed input

  11. NO HOOK WITHOUT ERROR HANDLING

  12. Wrap JSON.parse in try/catch
  13. Handle missing parameters gracefully
  14. Return valid: true when unsure (fail open, not closed)

  15. NO HOOK WITHOUT TEST FILE

  16. Every hook needs .test.cjs
  17. Test valid, invalid, and edge cases

  18. NO HOOK WITHOUT DOCUMENTATION

  19. Add to .claude/hooks/README.md
  20. Document trigger, behavior, exit codes

  21. CROSS-PLATFORM PATHS

  22. Use path.join() not string concatenation
  23. Handle both / and \ path separators
  24. Use path.normalize() for comparison

  25. NO CREATION WITHOUT SYSTEM IMPACT ANALYSIS

  26. Check if hook requires settings.json registration
  27. Check if hook requires config.yaml registration
  28. Check if related hooks need updating
  29. Document all system changes made

Integration Points Ecosystem Assessor: Hook creator integrates with ecosystem assessment for reverse lookups Agent Creator: Agents can reference hooks in their frontmatter Skill Creator: Skills can define hooks in their hooks/ directory Settings.json: Hooks are auto-registered with proper triggers and matchers Config.yaml: Event hooks registered for UserPromptSubmit, SessionStart, etc. File Placement & Standards Output Location Rules

This skill outputs to: .claude/hooks//

Categories:

safety/ - Safety validators (command validation, security checks) routing/ - Router enforcement hooks memory/ - Memory management hooks session/ - Session lifecycle hooks validation/ - Input/output validation hooks Mandatory References File Placement: See .claude/docs/FILE_PLACEMENT_RULES.md Developer Workflow: See .claude/docs/DEVELOPER_WORKFLOW.md Artifact Naming: See .claude/docs/ARTIFACT_NAMING.md Enforcement

File placement is enforced by file-placement-guard.cjs hook. Invalid placements will be blocked in production mode.

Memory Protocol (MANDATORY)

Before creating a hook:

cat .claude/context/memory/learnings.md

Check for:

Previously created hooks Known hook patterns User preferences for hook behavior

After completing:

New hook created -> Append to .claude/context/memory/learnings.md Issue with hook -> Append to .claude/context/memory/issues.md Hook design decision -> Append to .claude/context/memory/decisions.md

ASSUME INTERRUPTION: Your context may reset. If it's not in memory, it didn't happen.

返回排行榜