spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

claude-code / plugins / hookify / skills / writing-rules / SKILL.md
374 lines · 8.2 KBPreviewCodeRaw
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`