Building ai-hooks: A Universal Hook Engine for AI Coding Tools
Building ai-hooks: A Universal Hook Engine for AI Coding Tools
The Problem
Every team working with AI coding assistants hits the same wall:
- No unified policy layer. Each tool — Claude Code, Cursor, Codex — has its own hook format. Your guardrails get duplicated, drift, and break silently.
- No external control plane. If you need to programmatically steer the AI client a developer is using — set boundaries, collect signals, enforce workflow rules — there's no standard way to do it. You're locked into one vendor's API.
- Fragmented audit trails. Shell commands, file writes, and tool calls are logged in different formats per tool, making compliance and debugging painful.
- Inconsistent enforcement. Some tools can block dangerous actions before they happen; others can only observe after the fact.
I built ai-hooks to solve this. It's a universal hook engine that works across every major AI coding tool.
What ai-hooks Does
ai-hooks gives you a single policy engine that can steer any AI coding client with native hook support. Write rules once, and adapters translate them into the exact config format each tool understands.
Two ways to use it:
-
Config-driven — Write an
ai-hooks.config.ts, runai-hooks generate, and adapters produce native hook configs for every detected tool. -
Library / control plane — Import the engine into your platform. Programmatically steer the AI client — set boundaries, collect signals, enforce workflow rules — all through a standard API.
Supported Tools
| Tool | Blocking | Observation | Events |
|---|---|---|---|
| Claude Code | Yes | Yes | 13 |
| Codex CLI | Yes | Yes | 13 |
| Gemini CLI | Yes | Yes | 13 |
| Cursor | Yes | Yes | 9 |
| Kiro | Yes | Yes | 14 |
| OpenCode | Yes | Yes | 13 |
| Factory Droid | Yes | Yes | 9 |
| Cline | Yes | Yes | 7 |
| Amp | Yes | Yes | 2 |
Plus VS Code 1.109+ agent hooks (same format as Claude Code).
Built-in Safety Hooks
ai-ships with 4 hooks you can use immediately:
| Hook | Phase | What it does |
|---|---|---|
block-dangerous-commands | before | Blocks rm -rf /, DROP DATABASE, fork bombs |
scan-secrets | before | Detects API keys, tokens, private keys in file writes |
protect-sensitive-files | before | Prevents writes to .env, credentials.json, SSH keys |
audit-shell | after | Records command, exit code, duration, tool name |
Universal Event Model
15 event types across the full AI tool lifecycle:
| Category | Before (blockable) | After (observe-only) |
|---|---|---|
| Session | session:start | session:end |
| Prompt | prompt:submit | prompt:response |
| Tool | tool:before | tool:after |
| File | file:write, file:edit, file:delete | file:read |
| Shell | shell:before | shell:after |
| MCP | mcp:before | mcp:after |
| System | — | notification |
Config Example
// ai-hooks.config.ts
import { defineConfig, hook, builtinHooks } from "@premierstudio/ai-hooks";
export default defineConfig({
extends: [{ hooks: builtinHooks }],
hooks: [
hook("before", ["shell:before"], async (ctx, next) => {
if (ctx.event.command.includes("npm publish")) {
ctx.results.push({ blocked: true, reason: "Publishing is restricted" });
return;
}
await next();
})
.id("org:block-publish")
.name("Block npm publish")
.priority(10)
.build(),
],
settings: {
hookTimeout: 5000,
failMode: "open",
logLevel: "warn",
},
});Using as a Library
If you're building a platform that orchestrates AI agents — a PM tool, CI system, or custom control plane — import the engine directly:
import { HookEngine, builtinHooks } from "@premierstudio/ai-hooks";
const engine = new HookEngine({
hooks: builtinHooks,
settings: { failMode: "closed" },
});
// Check if an action should be blocked
const result = await engine.isBlocked(event, { name: "my-platform", version: "1.0" });
if (result.blocked) {
console.log(`Blocked: ${result.reason}`);
}Plannable Integration
ai-hooks powers the PM-AI hooks in Plannable. When you connect your AI coding tools to Plannable via @premierstudio/plannable, it automatically:
- Authenticates via OAuth
- Detects your AI tools (Claude Code, Cursor, Gemini CLI, etc.)
- Configures MCP server connections
- Installs intelligent guardrails via ai-hooks
This lets Plannable:
- Guide your AI toward the right tasks and priorities
- Enforce project conventions automatically
- Signal file and shell activity back to Plannable for risk detection
- Block unsafe operations before they happen
The Journey
Building ai-hooks went through several iterations:
- Monorepo consolidation — Started as 13 separate packages, consolidated to 2 (
@premierstudio/ai-hooksand@premierstudio/plannable) - Adapter registry issues — Solved module duplication problems with a globalThis singleton pattern
- Dynamic versioning — Switched from build-time to runtime version resolution for better publish workflows
- OIDC publisher — Set up trusted publisher for secure npm publishing
The project now has 100% test coverage and uses oxlint for strict TypeScript enforcement.
What's Next
- Amp hooks support (planned)
- More built-in safety hooks
- Event replay and auditing
- Integration with more platforms beyond Plannable
Links:
- GitHub: https://github.com/PremierStudio/ai-hooks
- npm:
@premierstudio/ai-hooks