Back to skills
SKILL.md
140 Claude A7982489
ASecurityPython scripts that respond to Claude Code lifecycle events.
- 9 stars
- 0 votes
- 0 copies
- 0 views
- Added October 11, 2026
Works with
Security analysis
100/100npx -y skills add tools-only/X-Skills --skill 140-claude_a7982489 --agent claude-codeAre you the author of 140 Claude A7982489?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-140-claude-a7982489)# Hooks
Python scripts that respond to Claude Code lifecycle events.
## Structure
```
hooks/
hooks.json # Auto-discovered config (events → scripts)
hook_utils.py # Shared utilities (ALWAYS import)
{hook_name}.py # Individual hook implementations
```
## Template
Every hook follows this structure:
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""
hook_name.py - Brief description.
Hook type: {PreToolUse|PostToolUse|SessionStart|UserPromptSubmit|etc.}
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from hook_utils import (
hook_main,
log_debug,
output_empty,
parse_hook_input,
read_stdin_safe,
)
@hook_main("HookEventName")
def main() -> None:
raw = read_stdin_safe()
data = parse_hook_input(raw)
if not data:
output_empty()
return
# Hook logic here
if __name__ == "__main__":
main()
```
## Input/Output
| Direction | Format | Access |
|-----------|--------|--------|
| Input | JSON from stdin | `read_stdin_safe()` → `parse_hook_input()` |
| Output | JSON to stdout | `output_empty()`, `output_context()`, `output_block()` |
| Debug | stderr | `log_debug()` (only when `HOOK_DEBUG=1`) |
### Available Input Fields
Hook input JSON includes (varies by hook type):
| Field | Description |
|-------|-------------|
| `prompt` | User's message (UserPromptSubmit) |
| `cwd` | Current working directory |
| `permission_mode` | "plan" when in plan mode, empty otherwise |
| `tool_name` | Tool being used (PreToolUse, PostToolUse) |
| `tool_input` | Tool parameters (PreToolUse, PostToolUse) |
Example: Detecting plan mode
```python
permission_mode = data.get("permission_mode", "")
if permission_mode == "plan":
# Handle plan mode differently
```
## Output Functions
| Function | When | Effect |
|----------|------|--------|
| `output_empty()` | Pass through | No modification |
| `output_context(event, ctx)` | Add context | Injects into conversation |
| `output_block(event, reason)` | Block action | Prevents tool execution |
| `output_permission(decision)` | Permission hooks | `allow`, `deny`, or `ask` |
## Configuration
Environment variables for user customization:
```python
def get_threshold() -> int:
return int(os.environ.get("OMC_THRESHOLD", "100"))
def is_enabled() -> bool:
return os.environ.get("OMC_FEATURE", "1").lower() not in ("0", "false", "no")
```
## Anti-Patterns
- Don't skip `@hook_main` decorator - handles all error recovery
- Don't print to stdout except via output functions
- Don't block stdin indefinitely - use `read_stdin_safe()`
- Don't import external packages without adding to `dependencies`
- Don't modify hook_utils.py without updating all dependents
Attribution
Comments
Loading comments…