Install
$ agentstack add skill-agentworkforce-relay-creating-claude-hooks-skill ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Creating Claude Code Hooks
Use this skill when creating, improving, or publishing Claude Code hooks. Provides essential guidance on hook format, event handling, I/O conventions, and package structure.
When to Use This Skill
Activate this skill when:
- User asks to create a new Claude Code hook
- User wants to publish a hook as a PRPM package
- User needs to understand hook format or events
- User is troubleshooting hook execution
- User asks about hook vs skill vs command differences
Quick Reference
Hook File Format
| Aspect | Requirement | | --------------- | ------------------------------------------------- | | Location | .claude/hooks/ | | Format | Executable file (shell, TypeScript, Python, etc.) | | Permissions | Must be executable (chmod +x) | | Shebang | Required (#!/bin/bash or #!/usr/bin/env node) | | Input | JSON via stdin | | Output | Text via stdout (shown to user) | | Exit Codes | 0 = success, 2 = block, other = error |
Available Events
| Event | When It Fires | Common Use Cases | | -------------------- | --------------------------- | ---------------------------------------- | | session-start | New session begins | Environment setup, logging, checks | | user-prompt-submit | Before user input processes | Validation, enhancement, filtering | | tool-call | Before tool execution | Permission checks, logging, modification | | assistant-response | After assistant responds | Formatting, logging, cleanup |
Hook Format Requirements
File Location
Project hooks:
.claude/hooks/session-start
.claude/hooks/user-prompt-submit
User-global hooks:
~/.claude/hooks/session-start
~/.claude/hooks/tool-call
Executable Requirements
Every hook MUST:
- Have a shebang line:
#!/bin/bash
# or
#!/usr/bin/env node
# or
#!/usr/bin/env python3
- Be executable:
chmod +x .claude/hooks/session-start
- Handle JSON input from stdin:
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
- Exit with appropriate code:
exit 0 # Success
exit 2 # Block operation
exit 1 # Error (logs but continues)
Input/Output Format
JSON Input Structure
Hooks receive JSON via stdin with event-specific data:
{
"event": "tool-call",
"timestamp": "2025-01-15T10:30:00Z",
"session_id": "abc123",
"current_dir": "/path/to/project",
"input": {
"file_path": "/path/to/file.ts",
"command": "npm test",
"old_string": "...",
"new_string": "..."
}
}
Stdout Output
- Normal output shows in transcript
- Empty output runs silently
- Use stderr (
>&2) for errors
Exit Codes
| Code | Meaning | Behavior | | ------------ | ------- | -------------------------- | | 0 | Success | Continue normally | | 2 | Block | Stop operation, show error | | 1 or other | Error | Log error, continue |
Schema Validation
Hooks should validate against the JSON schema:
Schema URL: https://github.com/pr-pm/prpm/blob/main/packages/converters/schemas/claude-hook.schema.json
Required frontmatter fields:
name- Hook identifier (lowercase, hyphens only)description- What the hook doesevent- Event type (optional, inferred from filename)language- bash, typescript, javascript, python, binary (optional)hookType: "hook"- For round-trip conversion
Common Mistakes
| Mistake | Problem | Solution | | ---------------------- | ------------------------- | ------------------------------------ | | Not quoting variables | Breaks on spaces | Always use "$VAR" | | Missing shebang | Won't execute | Add #!/bin/bash | | Not executable | Permission denied | Run chmod +x hook-file | | Logging to stdout | Clutters transcript | Use stderr: echo "log" >&2 | | Wrong exit code | Doesn't block when needed | Use exit 2 to block | | No input validation | Security risk | Always validate JSON fields | | Slow operations | Blocks Claude | Run in background or use PostToolUse | | Absolute paths missing | Can't find scripts | Use $CLAUDE_PLUGIN_ROOT |
Basic Hook Examples
Shell Script Hook
#!/bin/bash
# .claude/hooks/session-start
# Log session start
echo "Session started at $(date)" >> ~/.claude/session.log
# Check environment
if ! command -v node &> /dev/null; then
echo "Warning: Node.js not installed" >&2
fi
# Output to user
echo "Development environment ready"
exit 0
TypeScript Hook
#!/usr/bin/env node
// .claude/hooks/user-prompt-submit
import { readFileSync } from 'fs';
// Read JSON from stdin
const input = readFileSync(0, 'utf-8');
const data = JSON.parse(input);
// Validate prompt
if (data.prompt.includes('API_KEY')) {
console.error('Warning: Prompt may contain secrets');
process.exit(2); // Block
}
console.log('Prompt validated');
process.exit(0);
Best Practices
1. Keep Hooks Fast
Target /dev/null; then echo "jq not installed, skipping" >&2 exit 0 fi
Validate input
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty') if [[ -z "$FILE" ]]; then echo "No file path provided" >&2 exit 1 fi
### 3. Use Shebangs
Always start with shebang:
```bash
#!/bin/bash
#!/usr/bin/env node
#!/usr/bin/env python3
4. Secure Sensitive Files
BLOCKED=(".env" ".env.*" "*.pem" "*.key")
for pattern in "${BLOCKED[@]}"; do
case "$FILE" in
$pattern)
echo "Blocked: $FILE is sensitive" >&2
exit 2
;;
esac
done
5. Quote All Variables
# WRONG - breaks on spaces
prettier --write $FILE
# RIGHT - handles spaces
prettier --write "$FILE"
6. Log for Debugging
LOG_FILE=~/.claude-hooks/debug.log
# Log to file
echo "[$(date)] Processing $FILE" >> "$LOG_FILE"
# Log to stderr (shows in transcript)
echo "Hook running..." >&2
Publishing as PRPM Package
Package Structure
my-hook/
├── prpm.json # Package manifest
├── HOOK.md # Hook documentation
└── hook-script.sh # Hook executable
prpm.json
{
"name": "@username/hook-name",
"version": "1.0.0",
"description": "Brief description shown in search",
"author": "Your Name",
"format": "claude",
"subtype": "hook",
"tags": ["automation", "security", "formatting"],
"main": "HOOK.md"
}
HOOK.md Format
---
name: session-logger
description: Logs session start/end times for tracking
event: SessionStart
language: bash
hookType: hook
---
# Session Logger Hook
Logs Claude Code session activity for tracking and debugging.
## Installation
This hook will be installed to `.claude/hooks/session-start`.
## Behavior
- Logs session start time to `~/.claude/session.log`
- Displays environment status
- Runs silent dependency checks
## Requirements
- bash 4.0+
- write access to `~/.claude/`
## Source Code
\`\`\`bash
#!/bin/bash
echo "Session started at $(date)" >> ~/.claude/session.log
echo "Environment ready"
exit 0
\`\`\`
Publishing Process
# Test locally first
prpm test
# Publish to registry
prpm publish
# Version bumps
prpm publish patch # 1.0.0 -> 1.0.1
prpm publish minor # 1.0.0 -> 1.1.0
prpm publish major # 1.0.0 -> 2.0.0
Security Requirements
Input Validation
# Parse JSON safely
INPUT=$(cat)
if ! FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty' 2>&1); then
echo "JSON parse failed" >&2
exit 1
fi
# Validate field exists
[[ -n "$FILE" ]] || exit 1
Path Sanitization
# Prevent directory traversal
if [[ "$FILE" == *".."* ]]; then
echo "Path traversal detected" >&2
exit 2
fi
# Keep in project directory
if [[ "$FILE" != "$CLAUDE_PROJECT_DIR"* ]]; then
echo "File outside project" >&2
exit 2
fi
User Confirmation
Claude Code automatically:
- Requires confirmation before installing hooks
- Shows hook source code to user
- Warns about hook execution
- Displays hook output in transcript
Hooks vs Skills vs Commands
| Feature | Hooks | Skills | Commands | | ------------ | ---------------------- | ---------------------- | --------------------- | | Format | Executable code | Markdown | Markdown | | Trigger | Automatic (events) | Automatic (context) | Manual (/command) | | Language | Any executable | N/A | N/A | | Use Case | Automation, validation | Reference, patterns | Quick tasks | | Security | Requires confirmation | No special permissions | Inherits from session |
Examples:
- Hook: Auto-format files on save
- Skill: Reference guide for testing patterns
- Command:
/review-prquick code review
Related Resources
- claude-hook-writer skill - Detailed hook development guidance
- typescript-hook-writer skill - TypeScript-specific hook development
- Claude Code Docs
- Schema
Checklist for New Hooks
Before publishing:
- [ ] Shebang line included
- [ ] File is executable (
chmod +x) - [ ] Validates all stdin input
- [ ] Quotes all variables
- [ ] Handles missing dependencies gracefully
- [ ] Uses appropriate exit codes
- [ ] Logs errors to stderr or file
- [ ] Tests with edge cases (spaces, Unicode, missing fields)
- [ ] Documents dependencies in HOOK.md
- [ ] Includes installation instructions
- [ ] Source code included in documentation
- [ ] Clear description and tags in prpm.json
- [ ] Version number is semantic
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: AgentWorkforce
- Source: AgentWorkforce/relay
- License: Apache-2.0
- Homepage: https://agentrelay.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.