Skip to content
Back to skills

140 Claude A7982489

ASecurity

Python scripts that respond to Claude Code lifecycle events.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
ai-agentspython

Works with

  • claude code

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 140-claude_a7982489 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 140 Claude A7982489?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 140 Claude A7982489
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-140-claude-a7982489/badge)](https://www.skillsdirectory.com/skills/tools-only-140-claude-a7982489)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# 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

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…