# Claude Code Community Plugins & Examples — Administrator & Developer Guide

## 1. Architecture Overview

The `anthropics/claude-code` repository is the official community collection of plugins, examples, and tooling for extending Claude Code. It is not the Claude Code application itself — it is a **plugin and example ecosystem** that Claude Code discovers and loads at runtime.

### System Architecture

```text
Claude Code Runtime
├── Plugin Discovery
│   └── Scans plugin directories for standard structure
│       ├── commands/     → Registers slash commands
│       ├── agents/       → Registers spawnable agents
│       ├── skills/       → Registers knowledge packs (SKILL.md)
│       ├── hooks/        → Registers event hooks (hooks.json)
│       └── scripts/      → Utility scripts (not auto-discovered)
│
├── Hook Event Pipeline
│   ├── SessionStart      → Fires on session init
│   ├── UserPromptSubmit  → Fires on user input
│   ├── PreToolUse        → Fires before tool execution
│   ├── PostToolUse       → Fires after tool execution
│   └── Stop              → Fires when Claude stops
│
├── Settings Layer
│   ├── Managed settings (MDM / settings.json)
│   ├── Permission rules (ask/deny/allow)
│   └── Sandbox configuration
│
└── MCP Server Integration
    ├── stdio  (local process)
    ├── SSE    (hosted cloud)
    └── HTTP   (REST API)
```

> [!NOTE]
> The plugin discovery mechanism uses convention-over-configuration. Plugins need no registration file beyond the standard directory structure — Claude Code auto-discovers components by scanning known subdirectory names.

### Component Inventory

| Component | Path | Role |
|---|---|---|
| Hookify core | `plugins/hookify/core/` | Rule engine + config loader (Python) |
| Security guidance | `plugins/security-guidance/hooks/` | Security pattern detection hook (Python) |
| Code review | `plugins/code-review/commands/` | Code review slash command |
| PR review toolkit | `plugins/pr-review-toolkit/` | 6 specialized review agents + orchestrator command |
| Commit commands | `plugins/commit-commands/commands/` | Git commit/push/PR workflow commands |
| Feature dev | `plugins/feature-dev/` | 3 agents + feature development command |
| Plugin dev | `plugins/plugin-dev/` | Meta-plugin: 7 skills, 3 agents, 1 command |
| Agent SDK dev | `plugins/agent-sdk-dev/` | Agent SDK scaffolding command + verifier agents |
| Ralph Wiggum | `plugins/ralph-wiggum/` | Looping task automation |
| Explanatory style | `plugins/explanatory-output-style/` | SessionStart hook for explanatory output |
| Learning style | `plugins/learning-output-style/` | SessionStart hook for teaching output |
| Claude Opus 4.5 migration | `plugins/claude-opus-4-5-migration/` | Model migration skill pack |
| Frontend design | `plugins/frontend-design/` | Frontend design skill |
| Settings examples | `examples/settings/` | 3 settings presets (strict, lax, sandbox) |
| Hook examples | `examples/hooks/` | Bash command validator example |
| MDM examples | `examples/mdm/` | Managed device templates (macOS + Windows) |
| DevContainer script | `Script/` | PowerShell DevContainer automation |
| Issue scripts | `scripts/` | TypeScript/bash issue management scripts |

### Technology Stack

| Layer | Technology |
|---|---|
| Hook scripts | Python 3, Bash |
| Rule engine | Python 3 (dataclasses, regex, glob) |
| Commands / Agents / Skills | Markdown with YAML frontmatter |
| Hook configuration | JSON (`hooks.json`) |
| Settings | JSON |
| MCP configuration | JSON (stdio/SSE/HTTP) |
| DevContainer script | PowerShell |
| Issue management scripts | TypeScript, Bash |
| MDM templates | Apple plist/mobileconfig, Windows ADMX/ADML, PowerShell |

### Data Flow: Hook Execution

```text
1. User or Claude triggers a tool call (e.g., Bash "rm -rf /tmp")
2. Claude Code fires PreToolUse event
3. Event pipeline checks hooks.json for matching hooks
   └── matcher: "Bash" matches tool_name "Bash"
4. Hook script receives JSON on stdin:
   {"tool_name": "Bash", "tool_input": {"command": "rm -rf /tmp"}, "session_id": "..."}
5. Hook evaluates input:
   ├── Exit 0 → Allow (operation proceeds)
   ├── Exit 1 → Error (stderr to user, operation proceeds)
   └── Exit 2 → Block (stderr JSON with systemMessage to Claude)
6. If blocked: Claude sees the systemMessage and adjusts behavior
```

### Data Flow: Hookify Rule Evaluation

```text
1. PreToolUse/PostToolUse/Stop/UserPromptSubmit event fires
2. Hookify hook script runs (e.g., pretooluse.py)
3. config_loader.py scans .claude/hookify.*.local.md files
4. Each file's YAML frontmatter is parsed into a Rule object
5. rule_engine.py evaluates all enabled rules against input_data
   ├── Tool matcher check (e.g., "Bash", "Edit|Write", "*")
   ├── All conditions must match (AND logic)
   │   └── Each condition: extract field → apply operator → match pattern
   └── Results accumulated: blocking rules take priority over warnings
6. Combined response:
   ├── Block → {"hookSpecificOutput": {"permissionDecision": "deny"}, "systemMessage": "..."}
   ├── Warn  → {"systemMessage": "..."}
   └── None  → {} (allow)
```

## 2. System Requirements

| Requirement | Version | Notes |
|---|---|---|
| Claude Code | Latest with plugin support | Core runtime — this repo extends it |
| Python | 3.8+ | Required by hookify core and security-guidance hooks |
| jq | Any | Recommended for bash hook scripts that parse JSON |
| Git | Any | For cloning and contributing |
| Docker | 20.10+ | Only for DevContainer script |
| Podman | 4.0+ | Alternative to Docker for DevContainer script |
| devcontainer CLI | Any | Required by DevContainer script |
| Node.js / npm | 18+ | Only for issue management scripts (TypeScript) |
| PowerShell | 5.1+ / 7+ | Only for DevContainer script (Windows) |

## 3. Configuration Reference

### Settings JSON Schema

Settings are configured via JSON files. The repository provides three example presets demonstrating the available fields.

#### Permission Settings

| Key | Type | Default | Description | Required |
|---|---|---|---|---|
| `permissions.disableBypassPermissionsMode` | `string` | (unset) | Set to `"disable"` to prevent users from bypassing permission checks | No |
| `permissions.ask` | `string[]` | `[]` | Tool names that require explicit user approval before each use | No |
| `permissions.deny` | `string[]` | `[]` | Tool names that are completely blocked | No |

#### Sandbox Settings

| Key | Type | Default | Description | Required |
|---|---|---|---|---|
| `sandbox.enabled` | `boolean` | `false` | Enable command sandboxing | No |
| `sandbox.autoAllowBashIfSandboxed` | `boolean` | `false` | Auto-approve Bash commands when sandbox is active | No |
| `sandbox.allowUnsandboxedCommands` | `boolean` | `true` | Allow commands to run outside the sandbox | No |
| `sandbox.excludedCommands` | `string[]` | `[]` | Commands excluded from sandboxing | No |
| `sandbox.enableWeakerNestedSandbox` | `boolean` | `false` | Allow a weaker sandbox for nested operations | No |

#### Sandbox Network Settings

| Key | Type | Default | Description | Required |
|---|---|---|---|---|
| `sandbox.network.allowUnixSockets` | `string[]` | `[]` | Specific Unix socket paths to allow | No |
| `sandbox.network.allowAllUnixSockets` | `boolean` | `false` | Allow all Unix socket connections | No |
| `sandbox.network.allowLocalBinding` | `boolean` | `false` | Allow binding to local ports | No |
| `sandbox.network.allowedDomains` | `string[]` | `[]` | Domains allowed for outbound connections | No |
| `sandbox.network.httpProxyPort` | `integer\|null` | `null` | HTTP proxy port for sandboxed traffic | No |
| `sandbox.network.socksProxyPort` | `integer\|null` | `null` | SOCKS proxy port for sandboxed traffic | No |

#### Management Settings

| Key | Type | Default | Description | Required |
|---|---|---|---|---|
| `allowManagedPermissionRulesOnly` | `boolean` | `false` | Only allow permission rules set by managed configuration (MDM) | No |
| `allowManagedHooksOnly` | `boolean` | `false` | Only allow hooks set by managed configuration | No |
| `strictKnownMarketplaces` | `string[]` | (unset) | Restrict plugin sources to listed marketplaces | No |

> [!IMPORTANT]
> When `allowManagedPermissionRulesOnly` is `true`, users cannot add their own permission rules — only centrally managed rules apply. This is the primary enterprise control lever for locking down Claude Code.

### Environment Variables

| Variable | Type | Default | Description | Required |
|---|---|---|---|---|
| `ENABLE_SECURITY_REMINDER` | `string` | `"1"` | Set to `"0"` to disable the security-guidance hook entirely | No |
| `CLAUDE_PLUGIN_ROOT` | `string` | (set by runtime) | Absolute path to the plugin's root directory; use in hooks.json paths | No (auto) |
| `CLAUDE_PROJECT_DIR` | `string` | (set by runtime) | Absolute path to the current project directory | No (auto) |
| `CLAUDE_ENV_FILE` | `string` | (set by runtime) | Path to environment file for persisting variables across hooks | No (auto) |

### Hook Configuration (hooks.json)

Each plugin's `hooks/hooks.json` defines event subscriptions:

```json
{
  "description": "Optional description of this hook set",
  "hooks": {
    "<EventName>": [
      {
        "matcher": "<ToolName|ToolName2>",
        "hooks": [
          {
            "type": "command",
            "command": "<executable> ${CLAUDE_PLUGIN_ROOT}/path/to/script"
          }
        ]
      }
    ]
  }
}
```

**Event types and their input data:**

| Event | Input Fields | Matcher Applies To |
|---|---|---|
| `PreToolUse` | `tool_name`, `tool_input`, `session_id`, `hook_event_name` | `tool_name` |
| `PostToolUse` | `tool_name`, `tool_input`, `tool_output`, `session_id` | `tool_name` |
| `Stop` | `reason`, `transcript_path`, `session_id` | N/A |
| `SessionStart` | `session_id` | N/A |
| `UserPromptSubmit` | `user_prompt`, `session_id` | N/A |

**Hook output JSON schema (exit code 2):**

```json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny|ask|allow"
  },
  "systemMessage": "Message visible to Claude explaining why the operation was blocked",
  "decision": "block",
  "reason": "For Stop events — reason for blocking"
}
```

### Hookify Rule File Format

Rule files are markdown with YAML frontmatter, stored as `.claude/hookify.{name}.local.md`:

| Frontmatter Key | Type | Default | Description |
|---|---|---|---|
| `name` | `string` | `"unnamed"` | Rule identifier |
| `enabled` | `boolean` | `true` | Whether the rule is active |
| `event` | `string` | `"all"` | Event filter: `bash`, `file`, `stop`, `all` |
| `action` | `string` | `"warn"` | `warn` (show message) or `block` (deny operation) |
| `pattern` | `string` | (none) | Legacy simple pattern (auto-converted to condition) |
| `tool_matcher` | `string` | (none) | Tool name filter: `"Bash"`, `"Edit\|Write"`, `"*"` |
| `conditions` | `list` | `[]` | List of condition objects (see below) |

**Condition object:**

| Key | Type | Description |
|---|---|---|
| `field` | `string` | Field to extract from input (`command`, `file_path`, `new_text`, `content`, `reason`, `transcript`, `user_prompt`) |
| `operator` | `string` | Match operator (`regex_match`, `contains`, `equals`, `not_contains`, `starts_with`, `ends_with`) |
| `pattern` | `string` | Value to match against |

### MCP Server Configuration

Three transport types are supported in plugin MCP configurations:

**stdio** — local process:

| Key | Type | Description |
|---|---|---|
| `command` | `string` | Executable to run |
| `args` | `string[]` | Command arguments |
| `env` | `object` | Environment variables |

**SSE** — hosted cloud service:

| Key | Type | Description |
|---|---|---|
| `type` | `"sse"` | Transport type |
| `url` | `string` | SSE endpoint URL |
| `headers` | `object` | Optional HTTP headers |

**HTTP** — REST API:

| Key | Type | Description |
|---|---|---|
| `type` | `"http"` | Transport type |
| `url` | `string` | HTTP endpoint URL |
| `headers` | `object` | HTTP headers (e.g., Authorization) |

### Command Frontmatter Reference

Slash commands are markdown files with optional YAML frontmatter:

| Field | Type | Default | Description |
|---|---|---|---|
| `description` | `string` | (none) | Brief description shown in `/help` |
| `allowed-tools` | `string` | (all) | Comma-separated tool whitelist (e.g., `Read, Bash(git:*)`) |
| `model` | `string` | (default) | Model override: `sonnet`, `opus`, `haiku` |
| `argument-hint` | `string` | (none) | Argument documentation (e.g., `[pr-number] [priority]`) |
| `disable-model-invocation` | `boolean` | `false` | When `true`, command is manual-only (not auto-invoked) |

**Dynamic argument substitution:**

| Syntax | Description |
|---|---|
| `$ARGUMENTS` | All arguments as a single string |
| `$1`, `$2`, `$3` | Positional arguments |
| `@path/to/file` | Include file contents inline |
| `` !`command` `` | Execute bash command and include output |

## 4. Deployment & Scaling

### Enterprise Deployment via MDM

The `examples/mdm/` directory provides templates for managed device management deployment on macOS and Windows.

#### macOS Deployment

| File | Format | Purpose |
|---|---|---|
| `com.anthropic.claudecode.mobileconfig` | Apple Configuration Profile | Full MDM profile for deployment via MDM solutions (Jamf, Mosyle, etc.) |
| `com.anthropic.claudecode.plist` | Property List | Preference domain for `defaults write` or profile manager |

#### Windows Deployment

| File | Format | Purpose |
|---|---|---|
| `ClaudeCode.admx` | Group Policy Administrative Template | Defines Claude Code policy settings for Group Policy Editor |
| `en-US/ClaudeCode.adml` | ADML Language File | English language strings for the ADMX template |
| `Set-ClaudeCodePolicy.ps1` | PowerShell Script | Programmatically set Claude Code policies via registry |

**Minimal managed settings** (prevents permission bypass):

```json
{
  "permissions": {
    "disableBypassPermissionsMode": "disable"
  }
}
```

> [!WARNING]
> MDM-deployed settings take precedence over user-local settings. Test thoroughly in a staging environment before pushing to production devices.

### DevContainer Deployment

The PowerShell script at `Script/run_devcontainer_claude_code.ps1` automates containerized Claude Code environments.

**Parameters:**

| Parameter | Required | Values | Description |
|---|---|---|---|
| `-Backend` | Yes | `docker`, `podman` | Container backend to use |

**Podman flow:**

1. `podman machine init claudeVM` — creates the VM
2. `podman machine start claudeVM -q` — starts the VM
3. `podman system connection default claudeVM` — sets default connection
4. `devcontainer up --workspace-folder . --docker-path podman`
5. Finds container by label `devcontainer.local_folder={cwd}`
6. `podman exec -it {id} zsh -c 'claude; exec zsh'`

**Docker flow:**

1. Verifies Docker Desktop is running via `docker info`
2. `devcontainer up --workspace-folder .`
3. Finds container by label `devcontainer.local_folder={cwd}`
4. `docker exec -it {id} zsh -c 'claude; exec zsh'`

## 5. Operations

### Issue Management Scripts

The `scripts/` directory contains automation for GitHub issue triage:

| Script | Language | Purpose |
|---|---|---|
| `auto-close-duplicates.ts` | TypeScript | Automatically close duplicate issues |
| `backfill-duplicate-comments.ts` | TypeScript | Add duplicate markers to existing issues |
| `comment-on-duplicates.sh` | Bash | Comment on duplicate issues |
| `edit-issue-labels.sh` | Bash | Batch edit issue labels |
| `gh.sh` | Bash | GitHub CLI wrapper |
| `issue-lifecycle.ts` | TypeScript | Manage issue lifecycle transitions |
| `lifecycle-comment.ts` | TypeScript | Add lifecycle comments to issues |
| `sweep.ts` | TypeScript | Sweep stale issues |

> [!TIP]
> These scripts are designed for repository maintainers. They require the `gh` CLI to be authenticated and use the GitHub API for issue management.

### Plugin Maintenance

**Adding a new plugin:**

1. Create the plugin directory under `plugins/`
2. Add a `README.md` describing the plugin
3. Create component subdirectories as needed (`commands/`, `hooks/`, `skills/`, `agents/`)
4. For hooks: create `hooks/hooks.json` with event subscriptions
5. Test with `claude --debug`

**Updating hook scripts:**

1. Edit the script
2. Lint with `hook-linter.sh`
3. Test with `test-hook.sh` using sample input
4. Validate `hooks.json` with `validate-hook-schema.sh`

> [!NOTE]
> The hook development scripts in `plugins/plugin-dev/skills/hook-development/scripts/` are the canonical tools for validating and testing hooks across the entire repository.

### Security State File Cleanup

The security-guidance hook creates session-scoped state files at `~/.claude/security_warnings_state_{session_id}.json`. These are cleaned up automatically:

- 10% chance per hook invocation: scans `~/.claude/` for state files older than 30 days and removes them
- Manual cleanup: `rm ~/.claude/security_warnings_state_*.json`

## 6. Performance

### Hook Execution Performance

Hook scripts run synchronously in the tool execution pipeline. Performance considerations:

- **Hookify regex caching**: The `RuleEngine` uses `functools.lru_cache(maxsize=128)` for compiled regex patterns, avoiding re-compilation on repeated evaluations
- **Rule file scanning**: `config_loader.load_rules()` scans `.claude/hookify.*.local.md` via `glob.glob()` on every hook invocation — keep the number of rule files reasonable (< 50)
- **Security-guidance state I/O**: Each invocation reads/writes a JSON state file; this is fast for typical session sizes but could slow down with thousands of unique file-pattern combinations in a single session

**Hook timeout guidelines:**

- Hooks should complete within 60 seconds (Claude Code enforces timeouts)
- Avoid `sleep`, network calls, or long-running computations in hooks
- The hook-linter checks for `sleep [0-9]{3,}` and `while true` patterns

### Hookify Condition Evaluation

All conditions within a rule use AND logic — every condition must match for the rule to fire. Rules are evaluated sequentially; the first blocking rule short-circuits warning-only rules.

The field extraction path for each tool type:

| Tool | Fields Available |
|---|---|
| `Bash` | `command` |
| `Write` | `file_path`, `content` |
| `Edit` | `file_path`, `new_string`/`new_text`, `old_string`/`old_text`, `content` |
| `MultiEdit` | `file_path`, `new_text`/`content` (concatenated from all edits) |
| Stop event | `reason`, `transcript` (reads from `transcript_path` file) |
| UserPromptSubmit | `user_prompt` |

## 7. Security

### Security-Guidance Hook — Pattern Coverage

The security-guidance plugin implements a `PreToolUse` hook that intercepts `Edit`, `Write`, and `MultiEdit` operations. It checks both file paths and content against 9 built-in patterns:

| # | Rule Name | Detection Method | Vulnerability Class |
|---|---|---|---|
| 1 | `github_actions_workflow` | Path match: `.github/workflows/*.yml\|yaml` | Command injection in CI/CD |
| 2 | `child_process_exec` | Substring: `child_process.exec`, `exec(`, `execSync(` | Shell injection |
| 3 | `new_function_injection` | Substring: `new Function` | Code injection |
| 4 | `eval_injection` | Substring: `eval(` | Arbitrary code execution |
| 5 | `react_dangerously_set_html` | Substring: `dangerouslySetInnerHTML` | XSS |
| 6 | `document_write_xss` | Substring: `document.write` | XSS |
| 7 | `innerHTML_xss` | Substring: `.innerHTML =`, `.innerHTML=` | XSS |
| 8 | `pickle_deserialization` | Substring: `pickle` | Deserialization RCE |
| 9 | `os_system_injection` | Substring: `os.system`, `from os import system` | Command injection |

> [!CAUTION]
> The security-guidance patterns use simple substring matching, not AST analysis. They will produce false positives (e.g., a comment mentioning `eval(`) and may miss obfuscated patterns. They are a first-line warning system, not a security guarantee.

**Session-scoped deduplication:** Each warning fires once per unique `{file_path}-{rule_name}` combination per session. State is stored at `~/.claude/security_warnings_state_{session_id}.json`.

**Disabling:** Set `ENABLE_SECURITY_REMINDER=0` in the environment. The hook checks this variable on every invocation and exits immediately if disabled.

### Hook Script Security Best Practices

The hook-linter (`plugins/plugin-dev/skills/hook-development/scripts/hook-linter.sh`) enforces these security checks:

| Check | Risk | Mitigation |
|---|---|---|
| Unquoted variables | Command/path injection | Always use `"$variable"` |
| Missing `set -euo pipefail` | Silent failures, undefined variables | Add to every bash hook |
| Hardcoded absolute paths | Portability, path traversal | Use `$CLAUDE_PLUGIN_ROOT` or `$CLAUDE_PROJECT_DIR` |
| Missing shebang | Unpredictable interpreter | Always include `#!/bin/bash` or `#!/usr/bin/env python3` |
| Missing input validation | Unexpected null/empty fields | Check for empty values before processing |
| Error output not to stderr | Error messages lost | Use `>&2` for all error output |
| Long-running operations | Hook timeout, UX degradation | Avoid `sleep`, network calls, loops |

### Sandbox Configuration Security Model

The sandbox settings control bash command execution:

- `sandbox.enabled: true` — all Bash tool calls run in a sandboxed environment
- `sandbox.autoAllowBashIfSandboxed: false` — even sandboxed commands require approval (defense in depth)
- `sandbox.allowUnsandboxedCommands: false` — no escape from the sandbox
- `sandbox.network.*` — fine-grained network access controls within the sandbox

> [!WARNING]
> The `enableWeakerNestedSandbox` setting reduces sandbox protections for nested operations. Only enable this if a specific tool requires it and you understand the security implications.

### MDM Security Controls

Managed settings pushed via MDM take precedence over user-local settings:

- `disableBypassPermissionsMode: "disable"` — prevents users from switching to a permissive mode
- `allowManagedPermissionRulesOnly: true` — users cannot add their own permission rules
- `allowManagedHooksOnly: true` — users cannot register their own hooks

These three settings together create a fully centrally-controlled Claude Code environment suitable for enterprise deployment.

## 8. Developer Internals

### Repository Structure

```text
anthropics/claude-code/
├── plugins/                          # Community plugins
│   ├── hookify/                      # Rule engine for markdown-based hooks
│   │   ├── core/                     # Python rule engine
│   │   │   ├── config_loader.py      # Rule file parser (YAML frontmatter + conditions)
│   │   │   └── rule_engine.py        # Condition evaluator (regex, contains, equals, etc.)
│   │   ├── commands/                 # Slash commands (hookify, configure, list, help)
│   │   ├── hooks/                    # Hook entry points (pretooluse.py, posttooluse.py, stop.py, userpromptsubmit.py)
│   │   ├── matchers/                 # Tool matching logic
│   │   ├── agents/                   # Conversation analyzer agent
│   │   ├── skills/                   # Writing rules skill
│   │   ├── utils/                    # Shared utilities
│   │   └── examples/                 # Example rule files
│   ├── security-guidance/            # Security pattern detection
│   │   └── hooks/                    # hooks.json + security_reminder_hook.py
│   ├── code-review/                  # Code review command
│   ├── pr-review-toolkit/            # PR review agents + command
│   ├── commit-commands/              # Git workflow commands
│   ├── feature-dev/                  # Feature development agents + command
│   ├── plugin-dev/                   # Plugin development toolkit
│   │   ├── commands/                 # create-plugin command
│   │   ├── agents/                   # agent-creator, plugin-validator, skill-reviewer
│   │   └── skills/                   # 7 skills covering every plugin component type
│   ├── agent-sdk-dev/                # Agent SDK development
│   ├── ralph-wiggum/                 # Looping task automation
│   ├── explanatory-output-style/     # Explanatory output SessionStart hook
│   ├── learning-output-style/        # Learning output SessionStart hook
│   ├── claude-opus-4-5-migration/    # Model migration skill
│   └── frontend-design/             # Frontend design skill
├── examples/
│   ├── hooks/                        # Example hook scripts
│   ├── settings/                     # Settings presets (strict, lax, sandbox)
│   └── mdm/                         # MDM deployment templates
│       ├── macos/                    # plist + mobileconfig
│       └── windows/                  # ADMX + ADML + PowerShell
├── Script/                           # DevContainer automation (PowerShell)
├── scripts/                          # Issue management automation (TypeScript/Bash)
├── README.md
├── CHANGELOG.md
├── LICENSE.md
└── SECURITY.md
```

### Module Reference

#### `plugins/hookify/core/config_loader.py`

The configuration loader responsible for parsing hookify rule files.

**Classes:**

| Class | Description |
|---|---|
| `Condition` | Dataclass representing a single match condition (field, operator, pattern) |
| `Rule` | Dataclass representing a complete hookify rule (name, enabled, event, conditions, action, message) |

**Key functions:**

| Function | Signature | Description |
|---|---|---|
| `extract_frontmatter` | `(content: str) → tuple[Dict, str]` | Parses YAML frontmatter from markdown content. Handles simple key-value pairs, list items, and multi-line dictionary items within lists. Returns `(frontmatter_dict, message_body)`. |
| `load_rules` | `(event: Optional[str]) → List[Rule]` | Scans `.claude/hookify.*.local.md` files via `glob.glob()`. Filters by event type and enabled status. Returns list of `Rule` objects. |
| `load_rule_file` | `(file_path: str) → Optional[Rule]` | Loads and parses a single rule file. Returns `None` on parse errors (with stderr warning). |

**Frontmatter parsing details:**

The `extract_frontmatter` function implements a custom YAML parser (not a full YAML library) that handles:

- Simple `key: value` pairs (with boolean coercion for `true`/`false`)
- List items (`- item`)
- Inline dict list items (`- field: command, operator: regex_match`)
- Multi-line dict list items (indented continuation lines)
- String unquoting (strips surrounding `"` and `'`)

**Legacy pattern conversion:** When a rule uses the legacy `pattern` field instead of `conditions`, the loader auto-converts it into a `Condition` with `operator: regex_match`. The inferred field depends on the event type: `bash` → `command`, `file` → `new_text`, other → `content`.

#### `plugins/hookify/core/rule_engine.py`

The evaluation engine that matches rules against hook input data.

**Class: `RuleEngine`**

| Method | Signature | Description |
|---|---|---|
| `evaluate_rules` | `(rules: List[Rule], input_data: Dict) → Dict` | Evaluates all rules against input. Blocking rules take priority. Returns response dict with `systemMessage`, `hookSpecificOutput`, and/or `decision`. Returns `{}` if no rules match. |
| `_rule_matches` | `(rule: Rule, input_data: Dict) → bool` | Checks tool matcher, then evaluates all conditions (AND logic). Rules with no conditions never match. |
| `_matches_tool` | `(matcher: str, tool_name: str) → bool` | Supports `*` (match all) and `\|`-separated alternatives. |
| `_check_condition` | `(condition, tool_name, tool_input, input_data) → bool` | Extracts field value and applies operator. |
| `_extract_field` | `(field, tool_name, tool_input, input_data) → Optional[str]` | Field extraction with tool-specific logic (see Performance section). |
| `_regex_match` | `(pattern: str, text: str) → bool` | Cached regex evaluation via `compile_regex()`. |

**Global function:**

| Function | Description |
|---|---|
| `compile_regex(pattern: str) → re.Pattern` | `@lru_cache(maxsize=128)` — compiles and caches regex patterns with `re.IGNORECASE`. |

**Blocking response format by event type:**

| Event | Response Structure |
|---|---|
| `Stop` | `{"decision": "block", "reason": "...", "systemMessage": "..."}` |
| `PreToolUse` / `PostToolUse` | `{"hookSpecificOutput": {"hookEventName": "...", "permissionDecision": "deny"}, "systemMessage": "..."}` |
| Other events | `{"systemMessage": "..."}` |

#### `plugins/security-guidance/hooks/security_reminder_hook.py`

Standalone Python hook script (no imports from hookify — self-contained).

**Functions:**

| Function | Description |
|---|---|
| `debug_log(message)` | Appends timestamped debug messages to `/tmp/security-warnings-log.txt` |
| `get_state_file(session_id)` | Returns `~/.claude/security_warnings_state_{session_id}.json` |
| `cleanup_old_state_files()` | Removes state files older than 30 days from `~/.claude/` |
| `load_state(session_id)` | Loads shown warning keys from session state file |
| `save_state(session_id, shown_warnings)` | Persists shown warning keys to session state file |
| `check_patterns(file_path, content)` | Iterates `SECURITY_PATTERNS` list — checks path-based then content-based patterns. Returns `(rule_name, reminder)` or `(None, None)`. |
| `extract_content_from_input(tool_name, tool_input)` | Extracts checkable content: Write → `content`, Edit → `new_string`, MultiEdit → concatenated `new_string` values |
| `main()` | Entry point: reads JSON from stdin, checks patterns, manages session state, exits 0 (allow) or 2 (block with warning) |

**Pattern matching order:** Patterns are evaluated in definition order. The first match wins — subsequent patterns for the same file are not checked in that invocation.

### Code Patterns and Conventions

**Plugin structure convention:**

Every plugin follows this directory layout:

```text
plugin-name/
├── README.md              # Plugin documentation (required)
├── commands/              # Slash commands as .md files
├── agents/                # Agent definitions as .md files
├── skills/                # Skill packs
│   └── skill-name/
│       ├── SKILL.md       # Core skill content
│       ├── references/    # Deep-dive documentation
│       └── examples/      # Working examples
├── hooks/
│   ├── hooks.json         # Event subscriptions
│   └── *.py / *.sh        # Hook scripts
└── scripts/               # Utility scripts (not auto-discovered)
```

**Path portability:** All hook configurations use `${CLAUDE_PLUGIN_ROOT}` for plugin-relative paths rather than hardcoded absolute paths. This makes plugins portable across machines and users.

**Hook script patterns:**

- All bash hooks start with `set -euo pipefail`
- Input is read from stdin (`input=$(cat)` for bash, `sys.stdin.read()` for Python)
- JSON parsing uses `jq` in bash, `json.loads()` in Python
- Exit code 0 = allow, 1 = error (user-visible), 2 = block (Claude-visible)
- Error output goes to stderr (`>&2` in bash, `file=sys.stderr` in Python)

**Progressive disclosure in skills:**

Skills use a three-tier structure to manage context window usage:

1. `SKILL.md` (~1,500-2,500 words) — core concepts, loaded automatically
2. `references/` — detailed specifications, loaded on demand
3. `examples/` — working code examples, loaded on demand

**Hookify conditions inline format:**

```yaml
conditions:
  - field: command, operator: regex_match, pattern: "rm\\s+-rf"
```

Or multi-line:

```yaml
conditions:
  - field: command
    operator: regex_match
    pattern: "rm\\s+-rf"
```

Both formats are supported by the custom YAML parser in `config_loader.py`.

### Testing

**Hook testing tools:**

| Tool | Path | Purpose |
|---|---|---|
| `hook-linter.sh` | `plugins/plugin-dev/skills/hook-development/scripts/` | Static analysis of hook scripts |
| `test-hook.sh` | `plugins/plugin-dev/skills/hook-development/scripts/` | Runtime testing with sample input |
| `validate-hook-schema.sh` | `plugins/plugin-dev/skills/hook-development/scripts/` | Validate `hooks.json` structure |

**Testing workflow:**

1. Lint: `./hook-linter.sh my-hook.sh`
2. Generate sample input: `./test-hook.sh --create-sample PreToolUse > test-input.json`
3. Test: `./test-hook.sh -v my-hook.sh test-input.json`
4. Validate config: `./validate-hook-schema.sh hooks/hooks.json`
5. Integration test: `claude --debug`

**Unit testing (hookify core):**

Both `config_loader.py` and `rule_engine.py` include `if __name__ == '__main__':` blocks with inline test cases:

- `config_loader.py`: Tests frontmatter parsing with a simple rule and outputs parsed frontmatter, message, and Rule object
- `rule_engine.py`: Tests rule evaluation against matching and non-matching Bash inputs

### Potential Improvements

- **Full YAML parser:** The custom YAML parser in `config_loader.py` handles a subset of YAML. Using `PyYAML` would add robustness for edge cases (nested structures, multiline strings, anchors)
- **Async hook evaluation:** Hooks currently run synchronously. Parallel evaluation would reduce latency when multiple plugins register hooks for the same event
- **Hook testing framework:** The shell-based testing scripts could be complemented by a Python test suite with proper assertions and CI integration
- **Plugin manifest (`plugin.json`):** The plugin-dev skill references a `plugin.json` manifest format, but the existing plugins in this repository don't use it — they rely on convention-based discovery. Formalizing this would enable dependency management and version pinning
- **Security pattern extensibility:** The security-guidance hook's patterns are hardcoded. A configuration file (similar to hookify rules) would allow admins to add custom patterns without modifying the Python script

### Contributing

**Plugin contributions:**

1. Create a new directory under `plugins/` following the standard structure
2. Include a `README.md` with plugin description, usage, and examples
3. If adding hooks: include `hooks.json` and use `${CLAUDE_PLUGIN_ROOT}` for paths
4. Lint hook scripts with `hook-linter.sh`
5. Test hooks with `test-hook.sh`
6. Submit a pull request

**Code style:**

- Python: Standard library only (no external dependencies beyond what Claude Code provides)
- Bash: Always `set -euo pipefail`, quote all variables, use `jq` for JSON
- Markdown: YAML frontmatter for metadata, content body for prompts/messages
- JSON: 2-space indentation, no trailing commas

## 9. Integration Points

### MCP Server Integration

Plugins can bundle MCP server configurations for three transport types:

| Transport | Config Location | Use Case |
|---|---|---|
| stdio | Plugin `mcpServers` config | Local tools (filesystem, database, custom scripts) |
| SSE | Plugin `mcpServers` config | Hosted cloud services (Asana, GitHub) |
| HTTP | Plugin `mcpServers` config | REST APIs with authentication |

Environment variable substitution (`${VAR_NAME}`) is supported in all MCP config fields, enabling secrets to be injected at runtime without hardcoding.

### Claude Code Runtime Integration

| Integration Point | Mechanism | Example |
|---|---|---|
| Slash commands | Markdown files in `commands/` | `/code-review`, `/commit`, `/review-pr` |
| Sub-agents | Markdown files in `agents/` | code-architect, code-reviewer, plugin-validator |
| Knowledge packs | `SKILL.md` in `skills/` | Plugin structure, hook development, MCP integration |
| Event hooks | `hooks.json` + scripts in `hooks/` | Security checks, output style, bash validation |
| Environment | `$CLAUDE_ENV_FILE` writes in SessionStart hooks | Project type detection, CI detection |
| Settings | JSON files applied via MDM or manual copy | Permission rules, sandbox config |

### External Dependencies

This repository has zero runtime package dependencies. All code uses language standard libraries:

- **Python hooks**: `json`, `os`, `sys`, `re`, `glob`, `random`, `datetime`, `functools`, `dataclasses`, `typing`
- **Bash hooks**: `jq` (recommended but not strictly required), `cat`, `echo`, `grep`, `sed`
- **TypeScript scripts** (issue management only): requires Node.js runtime

---

_Generated May 2026 from anthropics/claude-code at fb063cd. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
