A Go library for building hooks for AI coding agents like Cursor, Claude Code, Windsurf Cascade, Factory Droid, and OpenAI Codex.
Hooks are a key component of Agentic Coding Security Management (ACSM) — they let you observe, control, and secure AI agent behavior in your development environment.
go get github.com/CorridorSecurity/hookshotpackage main
import (
"strings"
"github.com/CorridorSecurity/hookshot"
)
func main() {
// Stop hooks - prevent agent from stopping prematurely
hookshot.OnStop(func(ctx hookshot.StopContext) hookshot.StopDecision {
if ctx.ShouldSkip() {
return hookshot.AllowStop()
}
return hookshot.PreventStop("Please verify the changes")
})
// Execution hooks - control shell commands and MCP tools
hookshot.OnBeforeExecution(func(ctx hookshot.ExecutionContext) hookshot.ExecutionDecision {
if ctx.Type == hookshot.ExecutionShell {
if strings.Contains(ctx.Command, "rm -rf /") {
return hookshot.DenyExecution("Dangerous command blocked")
}
}
return hookshot.AllowExecution()
})
// File edit hooks - react to file changes
hookshot.OnAfterFileEdit(func(ctx hookshot.FileEditContext) hookshot.FileEditDecision {
return hookshot.FileEditOK()
})
// Prompt hooks - validate user prompts
hookshot.OnPromptSubmit(func(ctx hookshot.PromptContext) hookshot.PromptDecision {
return hookshot.AllowPromptDecision()
})
hookshot.RunCommand()
}Run with: ./my-hooks claude-stop or ./my-hooks cursor-stop
# Current platform
go build -o my-hooks .
# All platforms
hookshot build -all -output ./dist# Install to Claude Code and Cursor config files
hookshot install --binary /path/to/my-hooks{
"hooks": {
"Stop": [{ "hooks": [{ "type": "command", "command": "/path/to/my-hooks claude-stop" }] }],
"PreToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "/path/to/my-hooks claude-pre-tool-use" }] }]
}
}{
"version": 1,
"hooks": {
"stop": [{ "command": "/path/to/my-hooks cursor-stop" }],
"beforeShellExecution": [{ "command": "/path/to/my-hooks cursor-before-shell" }]
}
}Codex hooks are enabled by default (the hooks feature flag in Codex is
stable and on). No ~/.codex/config.toml change is required. If your
organization disabled hooks, set [features].hooks = true to turn them
back on.
{
"hooks": {
"Stop": [{ "hooks": [{ "type": "command", "command": "/path/to/my-hooks codex-stop" }] }],
"PreToolUse": [{ "matcher": "Bash|apply_patch|mcp__.*", "hooks": [{ "type": "command", "command": "/path/to/my-hooks codex-pre-tool-use" }] }],
"PostToolUse": [{ "matcher": "Bash|apply_patch|mcp__.*", "hooks": [{ "type": "command", "command": "/path/to/my-hooks codex-post-tool-use" }] }]
}
}Write once, run on all five platforms:
| Handler | Claude Code | Cursor | Windsurf Cascade | Factory Droid | OpenAI Codex |
|---|---|---|---|---|---|
OnStop |
Stop | stop | post-cascade-response | Stop | Stop |
OnBeforeExecution |
PreToolUse | beforeShellExecution, beforeMCPExecution | pre-run-command, pre-mcp-tool-use | PreToolUse | PreToolUse |
OnAfterFileEdit |
PostToolUse | afterFileEdit | post-write-code | PostToolUse | PostToolUse |
OnPromptSubmit |
UserPromptSubmit | beforeSubmitPrompt | pre-user-prompt | UserPromptSubmit | UserPromptSubmit |
For platform-specific features, use Register:
// Claude Code only: SessionStart
hookshot.Register("claude-session-start", func() {
hookshot.Run(func(input claude.SessionStartInput) claude.SessionStartOutput {
return claude.SessionStartContext("Project uses Go 1.21+")
})
})
// Cursor only: Tab completion
hookshot.Register("cursor-before-tab-read", func() {
hookshot.Run(func(input cursor.BeforeTabFileReadInput) cursor.BeforeTabFileReadOutput {
return cursor.AllowTabRead()
})
})
// Windsurf Cascade: Pre-write-code (not covered by unified API)
hookshot.Register("cascade-pre-write-code", func() {
hookshot.RunE(func(input cascade.PreWriteCodeInput) (cascade.PreWriteCodeOutput, error) {
return cascade.AllowWrite(), nil
})
})
// Factory Droid: Pre-tool use
hookshot.Register("droid-pre-tool-use", func() {
hookshot.Run(func(input droid.PreToolUseInput) droid.PreToolUseOutput {
return droid.PassThrough()
})
})
// OpenAI Codex: Pre-tool use (matches Bash, apply_patch, and MCP tools)
hookshot.Register("codex-pre-tool-use", func() {
hookshot.Run(func(input codex.PreToolUseInput) codex.PreToolUseOutput {
return codex.PassThrough()
})
})- Unified API Reference
- Claude Code Reference
- Cursor Reference
- Windsurf Cascade Reference
- Factory Droid Reference
- OpenAI Codex Reference
Full API documentation is available via godoc:
go doc github.com/CorridorSecurity/hookshot
go doc github.com/CorridorSecurity/hookshot/claude
go doc github.com/CorridorSecurity/hookshot/cursor
go doc github.com/CorridorSecurity/hookshot/cascade
go doc github.com/CorridorSecurity/hookshot/droid
go doc github.com/CorridorSecurity/hookshot/codexOr view online at pkg.go.dev/github.com/CorridorSecurity/hookshot.
MIT