mirror of
https://github.com/anthropics/claude-code.git
synced 2025-11-28 16:50:27 +08:00
Adds the hookify plugin to public marketplace. Enables users to create custom hooks using simple markdown configuration files instead of editing JSON. Key features: - Define rules with regex patterns to warn/block operations - Create rules from explicit instructions or conversation analysis - Pattern-based matching for bash commands, file edits, prompts, stop events - Enable/disable rules dynamically without editing code - Conversation analyzer agent finds problematic behaviors Changes from internal version: - Removed non-functional SessionStart hook (not registered in hooks.json) - Removed all sessionstart documentation and examples - Fixed restart documentation to consistently state "no restart needed" - Changed license from "Internal Anthropic use only" to "MIT License" - Kept test blocks in core modules (useful for developers) Plugin provides: - 4 commands: /hookify, /hookify:list, /hookify:configure, /hookify:help - 1 agent: conversation-analyzer - 1 skill: writing-rules - 4 hook types: PreToolUse, PostToolUse, Stop, UserPromptSubmit - 4 example rules ready to use All features functional and suitable for public use. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
374 lines
8.2 KiB
Markdown
374 lines
8.2 KiB
Markdown
---
|
|
name: Writing Hookify Rules
|
|
description: This skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
|
|
version: 0.1.0
|
|
---
|
|
|
|
# Writing Hookify Rules
|
|
|
|
## Overview
|
|
|
|
Hookify rules are markdown files with YAML frontmatter that define patterns to watch for and messages to show when those patterns match. Rules are stored in `.claude/hookify.{rule-name}.local.md` files.
|
|
|
|
## Rule File Format
|
|
|
|
### Basic Structure
|
|
|
|
```markdown
|
|
---
|
|
name: rule-identifier
|
|
enabled: true
|
|
event: bash|file|stop|prompt|all
|
|
pattern: regex-pattern-here
|
|
---
|
|
|
|
Message to show Claude when this rule triggers.
|
|
Can include markdown formatting, warnings, suggestions, etc.
|
|
```
|
|
|
|
### Frontmatter Fields
|
|
|
|
**name** (required): Unique identifier for the rule
|
|
- Use kebab-case: `warn-dangerous-rm`, `block-console-log`
|
|
- Be descriptive and action-oriented
|
|
- Start with verb: warn, prevent, block, require, check
|
|
|
|
**enabled** (required): Boolean to activate/deactivate
|
|
- `true`: Rule is active
|
|
- `false`: Rule is disabled (won't trigger)
|
|
- Can toggle without deleting rule
|
|
|
|
**event** (required): Which hook event to trigger on
|
|
- `bash`: Bash tool commands
|
|
- `file`: Edit, Write, MultiEdit tools
|
|
- `stop`: When agent wants to stop
|
|
- `prompt`: When user submits a prompt
|
|
- `all`: All events
|
|
|
|
**action** (optional): What to do when rule matches
|
|
- `warn`: Show message but allow operation (default)
|
|
- `block`: Prevent operation (PreToolUse) or stop session (Stop events)
|
|
- If omitted, defaults to `warn`
|
|
|
|
**pattern** (simple format): Regex pattern to match
|
|
- Used for simple single-condition rules
|
|
- Matches against command (bash) or new_text (file)
|
|
- Python regex syntax
|
|
|
|
**Example:**
|
|
```yaml
|
|
event: bash
|
|
pattern: rm\s+-rf
|
|
```
|
|
|
|
### Advanced Format (Multiple Conditions)
|
|
|
|
For complex rules with multiple conditions:
|
|
|
|
```markdown
|
|
---
|
|
name: warn-env-file-edits
|
|
enabled: true
|
|
event: file
|
|
conditions:
|
|
- field: file_path
|
|
operator: regex_match
|
|
pattern: \.env$
|
|
- field: new_text
|
|
operator: contains
|
|
pattern: API_KEY
|
|
---
|
|
|
|
You're adding an API key to a .env file. Ensure this file is in .gitignore!
|
|
```
|
|
|
|
**Condition fields:**
|
|
- `field`: Which field to check
|
|
- For bash: `command`
|
|
- For file: `file_path`, `new_text`, `old_text`, `content`
|
|
- `operator`: How to match
|
|
- `regex_match`: Regex pattern matching
|
|
- `contains`: Substring check
|
|
- `equals`: Exact match
|
|
- `not_contains`: Substring must NOT be present
|
|
- `starts_with`: Prefix check
|
|
- `ends_with`: Suffix check
|
|
- `pattern`: Pattern or string to match
|
|
|
|
**All conditions must match for rule to trigger.**
|
|
|
|
## Message Body
|
|
|
|
The markdown content after frontmatter is shown to Claude when the rule triggers.
|
|
|
|
**Good messages:**
|
|
- Explain what was detected
|
|
- Explain why it's problematic
|
|
- Suggest alternatives or best practices
|
|
- Use formatting for clarity (bold, lists, etc.)
|
|
|
|
**Example:**
|
|
```markdown
|
|
⚠️ **Console.log detected!**
|
|
|
|
You're adding console.log to production code.
|
|
|
|
**Why this matters:**
|
|
- Debug logs shouldn't ship to production
|
|
- Console.log can expose sensitive data
|
|
- Impacts browser performance
|
|
|
|
**Alternatives:**
|
|
- Use a proper logging library
|
|
- Remove before committing
|
|
- Use conditional debug builds
|
|
```
|
|
|
|
## Event Type Guide
|
|
|
|
### bash Events
|
|
|
|
Match Bash command patterns:
|
|
|
|
```markdown
|
|
---
|
|
event: bash
|
|
pattern: sudo\s+|rm\s+-rf|chmod\s+777
|
|
---
|
|
|
|
Dangerous command detected!
|
|
```
|
|
|
|
**Common patterns:**
|
|
- Dangerous commands: `rm\s+-rf`, `dd\s+if=`, `mkfs`
|
|
- Privilege escalation: `sudo\s+`, `su\s+`
|
|
- Permission issues: `chmod\s+777`, `chown\s+root`
|
|
|
|
### file Events
|
|
|
|
Match Edit/Write/MultiEdit operations:
|
|
|
|
```markdown
|
|
---
|
|
event: file
|
|
pattern: console\.log\(|eval\(|innerHTML\s*=
|
|
---
|
|
|
|
Potentially problematic code pattern detected!
|
|
```
|
|
|
|
**Match on different fields:**
|
|
```markdown
|
|
---
|
|
event: file
|
|
conditions:
|
|
- field: file_path
|
|
operator: regex_match
|
|
pattern: \.tsx?$
|
|
- field: new_text
|
|
operator: regex_match
|
|
pattern: console\.log\(
|
|
---
|
|
|
|
Console.log in TypeScript file!
|
|
```
|
|
|
|
**Common patterns:**
|
|
- Debug code: `console\.log\(`, `debugger`, `print\(`
|
|
- Security risks: `eval\(`, `innerHTML\s*=`, `dangerouslySetInnerHTML`
|
|
- Sensitive files: `\.env$`, `credentials`, `\.pem$`
|
|
- Generated files: `node_modules/`, `dist/`, `build/`
|
|
|
|
### stop Events
|
|
|
|
Match when agent wants to stop (completion checks):
|
|
|
|
```markdown
|
|
---
|
|
event: stop
|
|
pattern: .*
|
|
---
|
|
|
|
Before stopping, verify:
|
|
- [ ] Tests were run
|
|
- [ ] Build succeeded
|
|
- [ ] Documentation updated
|
|
```
|
|
|
|
**Use for:**
|
|
- Reminders about required steps
|
|
- Completion checklists
|
|
- Process enforcement
|
|
|
|
### prompt Events
|
|
|
|
Match user prompt content (advanced):
|
|
|
|
```markdown
|
|
---
|
|
event: prompt
|
|
conditions:
|
|
- field: user_prompt
|
|
operator: contains
|
|
pattern: deploy to production
|
|
---
|
|
|
|
Production deployment checklist:
|
|
- [ ] Tests passing?
|
|
- [ ] Reviewed by team?
|
|
- [ ] Monitoring ready?
|
|
```
|
|
|
|
## Pattern Writing Tips
|
|
|
|
### Regex Basics
|
|
|
|
**Literal characters:** Most characters match themselves
|
|
- `rm` matches "rm"
|
|
- `console.log` matches "console.log"
|
|
|
|
**Special characters need escaping:**
|
|
- `.` (any char) → `\.` (literal dot)
|
|
- `(` `)` → `\(` `\)` (literal parens)
|
|
- `[` `]` → `\[` `\]` (literal brackets)
|
|
|
|
**Common metacharacters:**
|
|
- `\s` - whitespace (space, tab, newline)
|
|
- `\d` - digit (0-9)
|
|
- `\w` - word character (a-z, A-Z, 0-9, _)
|
|
- `.` - any character
|
|
- `+` - one or more
|
|
- `*` - zero or more
|
|
- `?` - zero or one
|
|
- `|` - OR
|
|
|
|
**Examples:**
|
|
```
|
|
rm\s+-rf Matches: rm -rf, rm -rf
|
|
console\.log\( Matches: console.log(
|
|
(eval|exec)\( Matches: eval( or exec(
|
|
chmod\s+777 Matches: chmod 777, chmod 777
|
|
API_KEY\s*= Matches: API_KEY=, API_KEY =
|
|
```
|
|
|
|
### Testing Patterns
|
|
|
|
Test regex patterns before using:
|
|
|
|
```bash
|
|
python3 -c "import re; print(re.search(r'your_pattern', 'test text'))"
|
|
```
|
|
|
|
Or use online regex testers (regex101.com with Python flavor).
|
|
|
|
### Common Pitfalls
|
|
|
|
**Too broad:**
|
|
```yaml
|
|
pattern: log # Matches "log", "login", "dialog", "catalog"
|
|
```
|
|
Better: `console\.log\(|logger\.`
|
|
|
|
**Too specific:**
|
|
```yaml
|
|
pattern: rm -rf /tmp # Only matches exact path
|
|
```
|
|
Better: `rm\s+-rf`
|
|
|
|
**Escaping issues:**
|
|
- YAML quoted strings: `"pattern"` requires double backslashes `\\s`
|
|
- YAML unquoted: `pattern: \s` works as-is
|
|
- **Recommendation**: Use unquoted patterns in YAML
|
|
|
|
## File Organization
|
|
|
|
**Location:** All rules in `.claude/` directory
|
|
**Naming:** `.claude/hookify.{descriptive-name}.local.md`
|
|
**Gitignore:** Add `.claude/*.local.md` to `.gitignore`
|
|
|
|
**Good names:**
|
|
- `hookify.dangerous-rm.local.md`
|
|
- `hookify.console-log.local.md`
|
|
- `hookify.require-tests.local.md`
|
|
- `hookify.sensitive-files.local.md`
|
|
|
|
**Bad names:**
|
|
- `hookify.rule1.local.md` (not descriptive)
|
|
- `hookify.md` (missing .local)
|
|
- `danger.local.md` (missing hookify prefix)
|
|
|
|
## Workflow
|
|
|
|
### Creating a Rule
|
|
|
|
1. Identify unwanted behavior
|
|
2. Determine which tool is involved (Bash, Edit, etc.)
|
|
3. Choose event type (bash, file, stop, etc.)
|
|
4. Write regex pattern
|
|
5. Create `.claude/hookify.{name}.local.md` file in project root
|
|
6. Test immediately - rules are read dynamically on next tool use
|
|
|
|
### Refining a Rule
|
|
|
|
1. Edit the `.local.md` file
|
|
2. Adjust pattern or message
|
|
3. Test immediately - changes take effect on next tool use
|
|
|
|
### Disabling a Rule
|
|
|
|
**Temporary:** Set `enabled: false` in frontmatter
|
|
**Permanent:** Delete the `.local.md` file
|
|
|
|
## Examples
|
|
|
|
See `${CLAUDE_PLUGIN_ROOT}/examples/` for complete examples:
|
|
- `dangerous-rm.local.md` - Block dangerous rm commands
|
|
- `console-log-warning.local.md` - Warn about console.log
|
|
- `sensitive-files-warning.local.md` - Warn about editing .env files
|
|
|
|
## Quick Reference
|
|
|
|
**Minimum viable rule:**
|
|
```markdown
|
|
---
|
|
name: my-rule
|
|
enabled: true
|
|
event: bash
|
|
pattern: dangerous_command
|
|
---
|
|
|
|
Warning message here
|
|
```
|
|
|
|
**Rule with conditions:**
|
|
```markdown
|
|
---
|
|
name: my-rule
|
|
enabled: true
|
|
event: file
|
|
conditions:
|
|
- field: file_path
|
|
operator: regex_match
|
|
pattern: \.ts$
|
|
- field: new_text
|
|
operator: contains
|
|
pattern: any
|
|
---
|
|
|
|
Warning message
|
|
```
|
|
|
|
**Event types:**
|
|
- `bash` - Bash commands
|
|
- `file` - File edits
|
|
- `stop` - Completion checks
|
|
- `prompt` - User input
|
|
- `all` - All events
|
|
|
|
**Field options:**
|
|
- Bash: `command`
|
|
- File: `file_path`, `new_text`, `old_text`, `content`
|
|
- Prompt: `user_prompt`
|
|
|
|
**Operators:**
|
|
- `regex_match`, `contains`, `equals`, `not_contains`, `starts_with`, `ends_with`
|