Creation and configuration of event hooks/plugins to manage agent behavior, command filtering, auditing, and automation. Works across IDEs (Cursor, Claude Code, OpenCode). Use when you need to: (1) Create a new hook (e.g., for formatting or security checks), (2) Configure hooks/plugins, (3) Implement logic for blocking or modifying agent actions via scripts.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add korchasa/flowai --skill engineer-hook --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Engineer Hook?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/korchasa-engineer-hook)More formats (shields.io, HTML) on the badges page.
---
name: engineer-hook
description: "Creation and configuration of event hooks/plugins to manage agent behavior, command filtering, auditing, and automation. Works across IDEs (Cursor, Claude Code, OpenCode). Use when you need to: (1) Create a new hook (e.g., for formatting or security checks), (2) Configure hooks/plugins, (3) Implement logic for blocking or modifying agent actions via scripts."
---
# Hook / Plugin Creator
## Overview
This skill helps design and implement event hooks (or plugins). Hooks allow intercepting agent actions (command execution, file read/write, tool usage) and applying rules: allow, block (with explanation), request confirmation, or modify input data.
## IDE Detection and Hook Placement
### Hook Paths by IDE
| IDE | User Hooks | Project Hooks | Format |
|-----|-----------|--------------|--------|
| **Cursor** | `~/.cursor/hooks.json` | `.cursor/hooks.json` | JSON config + shell scripts |
| **Claude Code** | `~/.claude/settings.json` | `.claude/settings.json`<br>`.claude/settings.local.json` | JSON config (4 hook types) |
| **OpenCode** | `~/.config/opencode/plugins/*.{js,ts}` | `.opencode/plugins/*.{js,ts}`<br>`opencode.json` `plugin` (npm) | JS/TS modules (event-based) |
### Detection Strategy
1. Check for IDE-specific markers:
- `.cursor/` directory → Cursor
- `.claude/` directory → Claude Code
- `.opencode/` directory or `opencode.json` → OpenCode
2. If multiple detected or none → ask the user
**IMPORTANT**: After detecting the IDE, read ONLY the corresponding reference file. Do not load all references.
## Hook Type Availability Matrix
| Type | Cursor | Claude Code | OpenCode |
|------|--------|-------------|----------|
| **Command** (shell script) | Yes | Yes | No (use plugin code) |
| **Prompt** (LLM-evaluated) | Yes | Yes (8 events) | No |
| **HTTP** (POST to URL) | No | Yes | No |
| **Agent** (multi-turn subagent) | No | Yes (8 events) | No |
| **Programmatic** (JS/TS code) | No | No | Yes |
## Cross-IDE Event Mapping
| Cursor Event | Claude Code Event | OpenCode Equivalent |
|:---|:---|:---|
| `beforeShellExecution` | `PreToolUse` (matcher: `"Bash"`) | `tool.execute.before` |
| `afterShellExecution` | `PostToolUse` (matcher: `"Bash"`) | `tool.execute.after` |
| `preToolUse` | `PreToolUse` | `tool.execute.before` |
| `postToolUse` | `PostToolUse` | `tool.execute.after` |
| `postToolUseFailure` | `PostToolUseFailure` | `event` → `tool.execute.after` |
| `sessionStart` | `SessionStart` | `event` → `session.created` |
| `sessionEnd` | `SessionEnd` | `event` → `session.deleted` |
| `subagentStart` | `SubagentStart` | — |
| `subagentStop` | `SubagentStop` | — |
| `stop` | `Stop` | `event` → `session.idle` |
| `preCompact` | `PreCompact` | `experimental.session.compacting` |
| `afterFileEdit` | `PostToolUse` (matcher: `"Edit\|Write"`) | `event` → `file.edited` |
| `beforeSubmitPrompt` | `UserPromptSubmit` | `chat.message` |
| `beforeMCPExecution` | `PreToolUse` (matcher: `"mcp__.*"`) | `tool.execute.before` |
| `afterMCPExecution` | `PostToolUse` (matcher: `"mcp__.*"`) | `tool.execute.after` |
| `beforeReadFile` | `PreToolUse` (matcher: `"Read"`) | `tool.execute.before` |
| — | `PermissionRequest` | `permission.ask` |
| — | `Notification` | `event` → various |
| — | `TeammateIdle` | — |
| — | `TaskCompleted` | `event` → `todo.updated` |
| — | `ConfigChange` | — |
| — | `InstructionsLoaded` | — |
| — | `WorktreeCreate` / `WorktreeRemove` | — |
## Main Workflow
1. **Detect IDE** using markers above
2. **Read the IDE-specific reference** (see Resources below)
3. **Define the Event**: Choose from the mapping table above
4. **Choose Implementation Type** per availability matrix
5. **Configure**: Add config to the correct location
6. **Implement Logic**: Create the script/plugin
7. **Test**: Verify the hook fires correctly
## Cursor Hooks
JSON config + shell scripts. Two types: `command` and `prompt`.
### Configuration
In `.cursor/hooks.json`:
```json
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": ".cursor/hooks/format.sh" }],
"beforeShellExecution": [
{ "command": ".cursor/hooks/guard.sh", "matcher": "rm " }
]
}
}
```
### Implementation Types
1. **Command-based**: Shell script receiving JSON via stdin, returning JSON via stdout. Exit 0 = success, 2 = deny.
2. **Prompt-based**: LLM-evaluated condition.
```json
{ "type": "prompt", "prompt": "Is this command safe?", "timeout": 10 }
```
### Full Reference
For events list, input/output schemas, env vars, matcher values: see [hooks_api.md](references/hooks_api.md).
### Example: Blocking Dangerous Commands
**guard.sh**:
```bash
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.command')
if [[ "$command" == *"rm -rf"* ]]; then
echo '{"permission": "ask", "user_message": "Are you sure?", "agent_message": "rm -rf requires confirmation."}'
else
echo '{"permission": "allow"}'
fi
```
## Claude Code Hooks
JSON config in `settings.json`. Four types: `command`, `http`, `prompt`, `agent`.
### Configuration
In `.claude/settings.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/guard.sh",
"timeout": 30
}
]
}
]
}
}
```
Note the **nested structure**: each event maps to an array of matcher groups, each containing a `hooks` array.
### Implementation Types
1. **Command**: Shell script. Exit 0 = allow, exit 2 = block (stderr = reason).
2. **HTTP**: POST event data to URL. Response body parsed as JSON.
3. **Prompt**: Single-turn LLM evaluation with `$ARGUMENTS` placeholder.
4. **Agent**: Multi-turn subagent verification with tool access (up to 50 turns).
Prompt/agent types only available for 8 events: `PermissionRequest`, `PostToolUse`, `PostToolUseFailure`, `PreToolUse`, `Stop`, `SubagentStop`, `TaskCompleted`, `UserPromptSubmit`.
### Full Reference
For all 18 events, input/output schemas, env vars, exit code behavior per event: see [claude_code_hooks_api.md](references/claude_code_hooks_api.md).
### Example: Blocking Dangerous Commands
**guard.sh** (same script works for both Cursor and Claude Code):
```bash
#!/bin/bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name // empty')
tool_input=$(echo "$input" | jq -r '.tool_input.command // empty')
if [[ "$tool_input" == *"rm -rf"* ]]; then
echo "Blocked: rm -rf requires manual confirmation" >&2
exit 2
fi
exit 0
```
## OpenCode Plugins
JS/TS modules returning a `Hooks` object. No JSON config — all logic is code.
### Plugin Structure
```typescript
import type { Plugin } from "@opencode-ai/plugin"
export default (async ({ project, client, $, directory, worktree }) => {
return {
"tool.execute.before": async (input) => {
// inspect/modify tool arguments
return input
},
event: async (event) => {
// handle any system event
},
}
}) satisfies Plugin
```
### Distribution
- Local: `.opencode/plugins/*.ts`
- npm: `opencode.json` → `"plugin": ["package-name"]`
### Full Reference
For all hooks, events, `tool()` helper, examples: see [opencode_plugins_api.md](references/opencode_plugins_api.md).
### Example: Blocking Dangerous Commands
```typescript
import type { Plugin } from "@opencode-ai/plugin"
export default (async ({ client }) => ({
"tool.execute.before": async (input) => {
if (input.tool === "bash" && input.args?.command?.includes("rm -rf")) {
client.app.log({ body: { level: "warn", message: "Blocked rm -rf" } })
return { ...input, args: { command: "echo 'Blocked: rm -rf not allowed'" } }
}
return input
},
})) satisfies Plugin
```
## Resources
- [hooks_api.md](references/hooks_api.md) — Cursor: full event list, I/O formats, env vars
- [claude_code_hooks_api.md](references/claude_code_hooks_api.md) — Claude Code: 18 events, 4 hook types, settings.json format
- [opencode_plugins_api.md](references/opencode_plugins_api.md) — OpenCode: plugin API, hooks, events, tool() helper
- `assets/hook_template.sh` — Bash script template for command-type hooks
## Tips
- **All IDEs**: Paths in hook configs are relative to project root
- **Cursor**: Use `matcher` so hooks only fire for relevant commands
- **Cursor**: Debug via "Hooks" tab in settings or "Hooks" output channel
- **Cursor**: Set `failClosed: true` for security-critical hooks
- **Claude Code**: Use `claude --debug` or `Ctrl+O` for verbose hook logging
- **Claude Code**: Interactive `/hooks` menu available for managing hooks
- **Claude Code**: Check `stop_hook_active` in Stop hooks to prevent infinite loops
- **Claude Code**: `PermissionRequest` hooks don't fire in non-interactive mode (`-p`)
- **OpenCode**: Plugin dependencies go in `.opencode/package.json` (Bun auto-installs)
- **OpenCode**: Plugin tools override built-in tools with matching names
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!