Writing hookify rules skill

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.

by davila7·MIT license·★ 32,299 Stars on the repo·GitHub ↗

Use now

Files of Writing hookify rules

davila7/main1 file shown
SKILL.md
Show the full text375 lines

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
---
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:

event: bash
pattern: rm\s+-rf
Advanced Format (Multiple Conditions)

For complex rules with multiple conditions:

---
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:

⚠️ **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:

---
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:

---
event: file
pattern: console\.log\(|eval\(|innerHTML\s*=
---

Potentially problematic code pattern detected!

Match on different fields:

---
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):

---
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):

---
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:

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:

pattern: log    # Matches "log", "login", "dialog", "catalog"

Better: console\.log\(|logger\.

Too specific:

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:

---
name: my-rule
enabled: true
event: bash
pattern: dangerous_command
---

Warning message here

Rule with conditions:

---
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
1---
2name: Writing Hookify Rules
3description: 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.
4version: 0.1.0
5---
6 
7# Writing Hookify Rules
8 
9## Overview
10 
11Hookify 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.
12 
13## Rule File Format
14 
15### Basic Structure
16 
17```markdown
18---
19name: rule-identifier
20enabled: true
21event: bash|file|stop|prompt|all
22pattern: regex-pattern-here
23---
24 
25Message to show Claude when this rule triggers.
26Can include markdown formatting, warnings, suggestions, etc.
27```
28 
29### Frontmatter Fields
30 
31**name** (required): Unique identifier for the rule
32- Use kebab-case: `warn-dangerous-rm`, `block-console-log`
33- Be descriptive and action-oriented
34- Start with verb: warn, prevent, block, require, check
35 
36**enabled** (required): Boolean to activate/deactivate
37- `true`: Rule is active
38- `false`: Rule is disabled (won't trigger)
39- Can toggle without deleting rule
40 
41**event** (required): Which hook event to trigger on
42- `bash`: Bash tool commands
43- `file`: Edit, Write, MultiEdit tools
44- `stop`: When agent wants to stop
45- `prompt`: When user submits a prompt
46- `all`: All events
47 
48**action** (optional): What to do when rule matches
49- `warn`: Show message but allow operation (default)
50- `block`: Prevent operation (PreToolUse) or stop session (Stop events)
51- If omitted, defaults to `warn`
52 
53**pattern** (simple format): Regex pattern to match
54- Used for simple single-condition rules
55- Matches against command (bash) or new_text (file)
56- Python regex syntax
57 
58**Example:**
59```yaml
60event: bash
61pattern: rm\s+-rf
62```
63 
64### Advanced Format (Multiple Conditions)
65 
66For complex rules with multiple conditions:
67 
68```markdown
69---
70name: warn-env-file-edits
71enabled: true
72event: file
73conditions:
74 - field: file_path
75 operator: regex_match
76 pattern: \.env$
77 - field: new_text
78 operator: contains
79 pattern: API_KEY
80---
81 
82You're adding an API key to a .env file. Ensure this file is in .gitignore!
83```
84 
85**Condition fields:**
86- `field`: Which field to check
87 - For bash: `command`
88 - For file: `file_path`, `new_text`, `old_text`, `content`
89- `operator`: How to match
90 - `regex_match`: Regex pattern matching
91 - `contains`: Substring check
92 - `equals`: Exact match
93 - `not_contains`: Substring must NOT be present
94 - `starts_with`: Prefix check
95 - `ends_with`: Suffix check
96- `pattern`: Pattern or string to match
97 
98**All conditions must match for rule to trigger.**
99 
100## Message Body
101 
102The markdown content after frontmatter is shown to Claude when the rule triggers.
103 
104**Good messages:**
105- Explain what was detected
106- Explain why it's problematic
107- Suggest alternatives or best practices
108- Use formatting for clarity (bold, lists, etc.)
109 
110**Example:**
111```markdown
112⚠️ **Console.log detected!**
113 
114You're adding console.log to production code.
115 
116**Why this matters:**
117- Debug logs shouldn't ship to production
118- Console.log can expose sensitive data
119- Impacts browser performance
120 
121**Alternatives:**
122- Use a proper logging library
123- Remove before committing
124- Use conditional debug builds
125```
126 
127## Event Type Guide
128 
129### bash Events
130 
131Match Bash command patterns:
132 
133```markdown
134---
135event: bash
136pattern: sudo\s+|rm\s+-rf|chmod\s+777
137---
138 
139Dangerous command detected!
140```
141 
142**Common patterns:**
143- Dangerous commands: `rm\s+-rf`, `dd\s+if=`, `mkfs`
144- Privilege escalation: `sudo\s+`, `su\s+`
145- Permission issues: `chmod\s+777`, `chown\s+root`
146 
147### file Events
148 
149Match Edit/Write/MultiEdit operations:
150 
151```markdown
152---
153event: file
154pattern: console\.log\(|eval\(|innerHTML\s*=
155---
156 
157Potentially problematic code pattern detected!
158```
159 
160**Match on different fields:**
161```markdown
162---
163event: file
164conditions:
165 - field: file_path
166 operator: regex_match
167 pattern: \.tsx?$
168 - field: new_text
169 operator: regex_match
170 pattern: console\.log\(
171---
172 
173Console.log in TypeScript file!
174```
175 
176**Common patterns:**
177- Debug code: `console\.log\(`, `debugger`, `print\(`
178- Security risks: `eval\(`, `innerHTML\s*=`, `dangerouslySetInnerHTML`
179- Sensitive files: `\.env$`, `credentials`, `\.pem$`
180- Generated files: `node_modules/`, `dist/`, `build/`
181 
182### stop Events
183 
184Match when agent wants to stop (completion checks):
185 
186```markdown
187---
188event: stop
189pattern: .*
190---
191 
192Before stopping, verify:
193- [ ] Tests were run
194- [ ] Build succeeded
195- [ ] Documentation updated
196```
197 
198**Use for:**
199- Reminders about required steps
200- Completion checklists
201- Process enforcement
202 
203### prompt Events
204 
205Match user prompt content (advanced):
206 
207```markdown
208---
209event: prompt
210conditions:
211 - field: user_prompt
212 operator: contains
213 pattern: deploy to production
214---
215 
216Production deployment checklist:
217- [ ] Tests passing?
218- [ ] Reviewed by team?
219- [ ] Monitoring ready?
220```
221 
222## Pattern Writing Tips
223 
224### Regex Basics
225 
226**Literal characters:** Most characters match themselves
227- `rm` matches "rm"
228- `console.log` matches "console.log"
229 
230**Special characters need escaping:**
231- `.` (any char) → `\.` (literal dot)
232- `(` `)` → `\(` `\)` (literal parens)
233- `[` `]` → `\[` `\]` (literal brackets)
234 
235**Common metacharacters:**
236- `\s` - whitespace (space, tab, newline)
237- `\d` - digit (0-9)
238- `\w` - word character (a-z, A-Z, 0-9, _)
239- `.` - any character
240- `+` - one or more
241- `*` - zero or more
242- `?` - zero or one
243- `|` - OR
244 
245**Examples:**
246```
247rm\s+-rf Matches: rm -rf, rm -rf
248console\.log\( Matches: console.log(
249(eval|exec)\( Matches: eval( or exec(
250chmod\s+777 Matches: chmod 777, chmod 777
251API_KEY\s*= Matches: API_KEY=, API_KEY =
252```
253 
254### Testing Patterns
255 
256Test regex patterns before using:
257 
258```bash
259python3 -c "import re; print(re.search(r'your_pattern', 'test text'))"
260```
261 
262Or use online regex testers (regex101.com with Python flavor).
263 
264### Common Pitfalls
265 
266**Too broad:**
267```yaml
268pattern: log # Matches "log", "login", "dialog", "catalog"
269```
270Better: `console\.log\(|logger\.`
271 
272**Too specific:**
273```yaml
274pattern: rm -rf /tmp # Only matches exact path
275```
276Better: `rm\s+-rf`
277 
278**Escaping issues:**
279- YAML quoted strings: `"pattern"` requires double backslashes `\\s`
280- YAML unquoted: `pattern: \s` works as-is
281- **Recommendation**: Use unquoted patterns in YAML
282 
283## File Organization
284 
285**Location:** All rules in `.claude/` directory
286**Naming:** `.claude/hookify.{descriptive-name}.local.md`
287**Gitignore:** Add `.claude/*.local.md` to `.gitignore`
288 
289**Good names:**
290- `hookify.dangerous-rm.local.md`
291- `hookify.console-log.local.md`
292- `hookify.require-tests.local.md`
293- `hookify.sensitive-files.local.md`
294 
295**Bad names:**
296- `hookify.rule1.local.md` (not descriptive)
297- `hookify.md` (missing .local)
298- `danger.local.md` (missing hookify prefix)
299 
300## Workflow
301 
302### Creating a Rule
303 
3041. Identify unwanted behavior
3052. Determine which tool is involved (Bash, Edit, etc.)
3063. Choose event type (bash, file, stop, etc.)
3074. Write regex pattern
3085. Create `.claude/hookify.{name}.local.md` file in project root
3096. Test immediately - rules are read dynamically on next tool use
310 
311### Refining a Rule
312 
3131. Edit the `.local.md` file
3142. Adjust pattern or message
3153. Test immediately - changes take effect on next tool use
316 
317### Disabling a Rule
318 
319**Temporary:** Set `enabled: false` in frontmatter
320**Permanent:** Delete the `.local.md` file
321 
322## Examples
323 
324See `${CLAUDE_PLUGIN_ROOT}/examples/` for complete examples:
325- `dangerous-rm.local.md` - Block dangerous rm commands
326- `console-log-warning.local.md` - Warn about console.log
327- `sensitive-files-warning.local.md` - Warn about editing .env files
328 
329## Quick Reference
330 
331**Minimum viable rule:**
332```markdown
333---
334name: my-rule
335enabled: true
336event: bash
337pattern: dangerous_command
338---
339 
340Warning message here
341```
342 
343**Rule with conditions:**
344```markdown
345---
346name: my-rule
347enabled: true
348event: file
349conditions:
350 - field: file_path
351 operator: regex_match
352 pattern: \.ts$
353 - field: new_text
354 operator: contains
355 pattern: any
356---
357 
358Warning message
359```
360 
361**Event types:**
362- `bash` - Bash commands
363- `file` - File edits
364- `stop` - Completion checks
365- `prompt` - User input
366- `all` - All events
367 
368**Field options:**
369- Bash: `command`
370- File: `file_path`, `new_text`, `old_text`, `content`
371- Prompt: `user_prompt`
372 
373**Operators:**
374- `regex_match`, `contains`, `equals`, `not_contains`, `starts_with`, `ends_with`
375 

Discussion