Go Hooks SDK
The Go Hooks SDK lets a single executable register typed, native agent hooks, dispatch one invocation and return a host-specific result. It is not an installer and does not make Skills or MCP portable automatically.
Install and choose the contract
The independently versioned Go module is github.com/777genius/plugin-kit-ai/sdk. The SDK README documents the published v1.3.0 module:
go get github.com/777genius/plugin-kit-ai/sdk@v1.3.0The module declares Go 1.22 with a Go 1.26.10 toolchain directive. For reliable reproduction use the toolchain and module version recorded in your build. Source main may expose later beta events; those are not implicitly available in v1.3.0.
Minimal typed handler
Register handlers before calling Run. The host passes the native hook name as an invocation argument. The SDK reads the event, dispatches its typed callback and writes the correct response.
package main
import (
"os"
uap "github.com/777genius/plugin-kit-ai/sdk"
"github.com/777genius/plugin-kit-ai/sdk/claude"
"github.com/777genius/plugin-kit-ai/sdk/codex"
)
func main() {
app := uap.New(uap.Config{Name: "review-hooks"})
app.Claude().OnStop(func(event *claude.StopEvent) *claude.Response {
return claude.Allow()
})
app.Codex().OnNotify(func(event *codex.NotifyEvent) *codex.Response {
return codex.Continue()
})
os.Exit(app.Run())
}This example demonstrates registration and dispatch, not automatic delivery. Build an executable and configure the chosen agent's native hook to invoke it with the expected event name and payload. Hook names, registration syntax and native installation differ by client. See runtime examples in source.
Public surfaces
- Root:
New(Config),App.Use,App.Run,App.RunContext,Supported()and platform registrarsClaude(),Codex(),Gemini(),Qoder(). - Typed platforms:
sdk/claude,sdk/codex,sdk/geminiandsdk/qoder. Other source-tree registrars have their own maturity and release boundaries. Supported()exposes runtime event status; it is not a matrix of supported installers, profile scopes or authenticated services.
For the documented stable event subset, see the SDK's runtime boundary. It includes Claude Stop / PreToolUse / UserPromptSubmit, Codex Notify, Gemini's promoted nine-hook path and the documented Qoder hooks in current source. Other events can be public-beta; consult the version-specific support matrix and stability policy. In particular, Cursor's stop observer is beta, not equivalent to a qualified native Cursor integration.
Examples of event-level capabilities
| Agent | Example events | Typical use |
|---|---|---|
| Claude Code | PreToolUse, UserPromptSubmit, Stop | Observe tool calls, prompts or turn completion |
| Codex | Notify | Handle native notifications |
| Gemini CLI | BeforeModel, AfterModel, BeforeToolSelection | Observe or intentionally adjust model/tool selection |
| Gemini CLI | BeforeTool, AfterTool, BeforeAgent, AfterAgent, SessionStart, SessionEnd | Control tool/turn flows or emit advisory session messages |
| Qoder | session_start, user_prompt_submit, post_tool_use, stop | Respond to the native Qoder lifecycle |
For Gemini, gemini.BeforeToolContinue() is a no-op, while gemini.BeforeToolRewriteInputValue(...) rewrites validated tool input. gemini.BeforeToolSelectionAllowOnly(...) emits an accepted ANY allowlist. SessionStart and SessionEnd are advisory, not stop/decision controls. See the Go runtime source documentation and the pinned version's stability policy before changing control flow.
Event lifecycle
- Agent launches the configured hook executable and supplies its native event (stdin or invocation-specific transport).
RunContext(ctx)resolves the invoked platform/event, decodes bounded data and applies middleware/registered handlers.- The SDK serializes the matching response and exit code to the hook process; use stderr for diagnostics, not random stdout logs.
- Test the exact agent, version, hook registration and payload separately. An SDK unit test proves protocol handling, not native activation.
App.Use adds middleware for subsequent dispatch. Configure Config{Args, IO, Env, Logger} when embedding or testing. The shared MaxPayloadBytes constant is the runtime input limit; do not invent your own maximum.
Shared executable and detection
If one binary may be called by multiple clients, use Host detection on the same captured payload before selecting a platform-specific path. Do not consume stdin once for detection and expect Run to read it again unless you provide a suitable replayable Config.IO.
Troubleshooting
| Symptom | Check |
|---|---|
| Hook never runs | Native hook registration, executable permissions, client reload and exact event name |
| Unknown invocation | Arguments/event spelling and whether that event exists in the pinned SDK version |
| Invalid payload | Host-specific wire format, size limit and whether data is stdin JSON or legacy argv JSON |
| Unexpected text in response | Keep stdout reserved for SDK wire output |
| Hook works in a unit test but not in a client | Reproduce with the exact native host version and profile; installation is a separate contract |