| name | opencode-hooks |
| version | 0.1.0 |
| description | Configure and manage hooks in OpenCode. Use for: blocking dangerous commands (rm, sudo), logging tool usage, enforcing policies, auditing sessions. Hooks are configured in hooks.json files. Search paths: .opencode/hooks.json, ~/.config/opencode/hooks.json, .claude/settings.json |
| author | opencode-hooks team |
opencode-hooks Skill
Non-Negotiable Rules
- Read hooks.json from known search paths before assuming policies
- Use
error field for simple blocking — no process spawning needed
- Use
if conditions to target specific tool arguments
- PreToolUse blocks — the action is denied before execution
- PostToolUse does not block — action already completed, only for logging
hooks.json Format
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(rm *)",
"error": "rm commands are not allowed"
}
]
}
]
}
}
Event Mapping
| Hook Event | OpenCode Event | Blocks? |
|---|
| PreToolUse | tool.execute.before | ✅ |
| PostToolUse | tool.execute.after | ❌ |
| SessionStart | session.created | ⚠️ |
| SessionEnd | session.deleted | ⚠️ |
| Stop | session.idle | ⚠️ |
⚠️ = May not fire in headless/CLI mode
'if' Condition Syntax
Format: ToolName(pattern) where pattern supports * wildcard
Bash(rm *) → bash commands starting with rm
Edit(*.ts) → Edit calls on .ts files
Bash(sudo *) → sudo commands
Bash(rm *|mv *) → rm OR mv commands
Tool names are case-insensitive: Bash matches bash, Edit matches edit.
Blocking Patterns
Simple blocking (preferred)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(rm *)",
"error": "rm commands are blocked"
}
]
}
]
}
}
Multiple dangerous patterns
{
"type": "command",
"if": "Bash(rm *|mv *|*chmod *)",
"error": "Destructive commands are not allowed"
}
Logging/Auditing
PostToolUse fires after tool success — use for logging:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": ["/path/to/log-edit.sh"]
}
]
}
]
}
}
Tool Name Reference
| OpenCode Tool | if Condition |
|---|
| bash | Bash(command) |
| edit | Edit(file_path) |
| write | Write(file_path) |
| read | Read(file_path) |
| glob | Glob(pattern) |
| grep | Grep(pattern) |
Troubleshooting
Hook not firing?
- Check
OPENCODE_HOOKS_DEBUG=true for verbose output
- Verify matcher matches lowercase tool name
- PreToolUse conditions checked BEFORE tool runs
- Some events don't fire in headless mode (session.start, etc.)
Blocking not working?
- Ensure
type: "command" is set
- Use
error field for direct blocking (no script needed)
- Exit code 2 from script also blocks