Skip to content
Back to skills

Ac Meta Hook Writer

ASecurity

Expert assistant for authoring hook scripts. Creates Python hooks with correct JSON output schema, validates against PreToolUse/PostToolUse/UserPromptSubmit formats, and applies fail-open principles. Triggers on keywords: writing hooks, creating hooks, hook authoring, pretooluse hook, posttooluse hook, new hook, hook template, hook validation, hook schema

  • 30 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 6, 2026
ai-agentspythonbashgit

Security analysis

A100/100

Scanned September 6, 2026

npx -y skills add MatiasComercio/agentic-config --skill ac-meta-hook-writer --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ac Meta Hook Writer?

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

Security grade badge for Ac Meta Hook Writer
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/matiascomercio-ac-meta-hook-writer/badge)](https://www.skillsdirectory.com/skills/matiascomercio-ac-meta-hook-writer)

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

Download with Pro
SKILL.md
---
name: ac-meta-hook-writer
description: "Expert assistant for authoring hook scripts. Creates Python hooks with correct JSON output schema, validates against PreToolUse/PostToolUse/UserPromptSubmit formats, and applies fail-open principles. Triggers on keywords: writing hooks, creating hooks, hook authoring, pretooluse hook, posttooluse hook, new hook, hook template, hook validation, hook schema"
project-agnostic: true
allowed-tools:
  - Read
  - Write
  - Edit
  - Glob
  - Grep
  - Bash
---

# Hook Writer

Creates Python hooks with correct JSON output schemas and fail-open patterns.

## Compatibility Note

This pi wrapper preserves the original hook authoring target. The wrapper only adapts invocation to pi; it does not retarget the generated hook format.

## Hook Types

| Event | Trigger | Use Case |
|-------|---------|----------|
| PreToolUse | Before tool execution | Block dangerous commands, validate inputs |
| PostToolUse | After tool execution | Log results, trigger follow-up actions |
| UserPromptSubmit | Before prompt processing | Validate/transform user input |
| Stop | Session ends | Cleanup, summary generation |
| SubagentStop | Subagent completes | Aggregate results, status reporting |

## JSON Output Schema

### PreToolUse/PostToolUse (Permission Decisions)

```json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "Optional explanation"
  }
}
```

| Field | Values | Required |
|-------|--------|----------|
| `hookEventName` | `"PreToolUse"` or `"PostToolUse"` | Yes |
| `permissionDecision` | `"allow"`, `"deny"`, `"ask"` | Yes |
| `permissionDecisionReason` | String explanation | No (recommended for deny) |

**DEPRECATED FORMAT (DO NOT USE):**
```json
{"decision": "allow", "message": null}
```

### UserPromptSubmit

```json
{
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "modifiedPrompt": "Transformed user prompt"
  }
}
```

### Stop/SubagentStop

```json
{
  "hookSpecificOutput": {
    "hookEventName": "Stop"
  }
}
```

## Python TypedDict Templates

### PreToolUse/PostToolUse

```python
from typing import TypedDict


class HookSpecificOutput(TypedDict, total=False):
    """Inner hook output structure."""
    hookEventName: str
    permissionDecision: str  # "allow" | "deny" | "ask"
    permissionDecisionReason: str


class HookOutput(TypedDict):
    """JSON output returned via stdout."""
    hookSpecificOutput: HookSpecificOutput
```

### UserPromptSubmit

```python
from typing import TypedDict


class HookSpecificOutput(TypedDict, total=False):
    """Inner hook output structure."""
    hookEventName: str
    modifiedPrompt: str


class HookOutput(TypedDict):
    """JSON output returned via stdout."""
    hookSpecificOutput: HookSpecificOutput
```

## Hook Input Schema

Hooks receive JSON via stdin:

```python
class ToolInput(TypedDict, total=False):
    """Tool parameters from the hook host."""
    command: str      # Bash commands
    file_path: str    # Write/Edit/Read targets
    content: str      # Write content
    old_string: str   # Edit source
    new_string: str   # Edit replacement


class HookInput(TypedDict):
    """JSON input received via stdin."""
    tool_name: str    # "Bash", "Write", "Edit", "Read", etc.
    tool_input: ToolInput
```

## Complete Hook Template

```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""
Pretooluse hook for the target host that [PURPOSE].

[DETAILED DESCRIPTION]
Fail-open principle: allow operations if hook encounters errors.
"""

import json
import sys
from typing import TypedDict


class ToolInput(TypedDict, total=False):
    """Tool parameters from the hook host."""
    command: str


class HookInput(TypedDict):
    """JSON input received via stdin."""
    tool_name: str
    tool_input: ToolInput


class HookSpecificOutput(TypedDict, total=False):
    """Inner hook output structure."""
    hookEventName: str
    permissionDecision: str  # "allow" | "deny"
    permissionDecisionReason: str


class HookOutput(TypedDict):
    """JSON output returned via stdout."""
    hookSpecificOutput: HookSpecificOutput


def should_block_tool(tool_name: str, tool_input: ToolInput) -> tuple[bool, str | None]:
    """
    Determine if tool should be blocked.

    Returns:
        (should_block, message): Tuple of block decision and optional message
    """
    # Only inspect specific tools
    if tool_name != "Bash":
        return False, None

    command = tool_input.get("command", "")

    # Add detection logic here
    if "dangerous_pattern" in command:
        return True, "Blocked: explanation of why this is blocked."

    return False, None


def main() -> None:
    """Main hook execution."""
    try:
        # Read input from stdin
        input_data: HookInput = json.load(sys.stdin)
        tool_name = input_data.get("tool_name", "")
        tool_input = input_data.get("tool_input", {})

        # Determine if should block
        should_block, message = should_block_tool(tool_name, tool_input)

        # Return decision in hook format
        hook_output: HookSpecificOutput = {
            "hookEventName": "PreToolUse",
            "permissionDecision": "deny" if should_block else "allow",
        }
        if message:
            hook_output["permissionDecisionReason"] = message

        output: HookOutput = {"hookSpecificOutput": hook_output}
        print(json.dumps(output))

    except Exception as e:
        # Fail-open: if hook crashes, allow the operation
        output: HookOutput = {
            "hookSpecificOutput": {
                "hookEventName": "PreToolUse",
                "permissionDecision": "allow",
            }
        }
        print(json.dumps(output))
        print(f"Hook error: {e}", file=sys.stderr)
        sys.exit(0)


if __name__ == "__main__":
    main()
```

## settings.json Configuration

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "uv run --no-project --script /path/to/hook.py"
      }
    ]
  }
}
```

### Matcher Options

| Matcher | Matches |
|---------|---------|
| `"Bash"` | Bash tool only |
| `"Write"` | Write tool only |
| `"*"` | All tools |
| `["Bash", "Write"]` | Multiple specific tools |

## Fail-Open Principle

Hooks MUST fail-open to prevent blocking legitimate operations due to hook errors:

1. **Wrap main logic in try/except**
2. **Exception handler outputs `"permissionDecision": "allow"`**
3. **Log error to stderr (optional)**
4. **Exit with 0 (not error code)**

```python
except Exception as e:
    # Fail-open: if hook crashes, allow the operation
    output: HookOutput = {
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": "allow",
        }
    }
    print(json.dumps(output))
    print(f"Hook error: {e}", file=sys.stderr)
    sys.exit(0)  # Exit cleanly even on error
```

## Reference Implementations

| Hook | Purpose | Bundled In |
|------|---------|------------|
| dry-run-guard.py | Block file-writing in dry-run mode | `dry-run` skill |
| git-commit-guard.py | Block --no-verify flag | project `.claude/hooks/` |
| gsuite-public-asset-guard.py | Block public asset creation | `gsuite` skill |
| mux-orchestrator-guard.py | Block forbidden tools in MUX orchestrator | `mux` skill |
| mux-subagent-guard.py | Block TaskOutput for MUX subagents | `mux-subagent` skill |

Hooks are bundled within their respective skill directories under `hooks/` subdirectory.
For standalone hooks not tied to a skill, see the project's `.claude/hooks/` directory.

## Workflow

1. **Identify** the tool(s) to monitor
2. **Define** blocking conditions (patterns, state checks)
3. **Create** hook using template above
4. **Test** manually: `echo '{"tool_name":"Bash","tool_input":{"command":"test"}}' | python hook.py`
5. **Configure** in settings.json
6. **Verify** hook triggers on actual tool use

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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.