Help us improve
Share bugs, ideas, or general feedback.
Hookify — cross-agent (Claude + Codex) hook runtime with a shared .hookify/ directory contract
npx claudepluginhub jasonkuhrt/hookifyHookify skills and hooks for Claude Code.
Share bugs, ideas, or general feedback.
Hookify standardizes hook discovery and execution for Claude and Codex without discarding either agent's native JSON.
One command, both agents:
npx hookify install
Hookify detects Claude Code and Codex on the machine and installs the plugin for each. After that, you author hooks in .hookify/ directories — no more editing agent-native hook config.
If you want to target one agent explicitly:
npx hookify install claude
npx hookify install codex
Claude: wraps claude plugin marketplace add jasonkuhrt/hookify + claude plugin install hookify-claude@hookify at user scope. Requires the claude CLI on PATH (install Claude Code from https://claude.ai/code).
Codex: Codex does not yet support remote plugin marketplaces, so this flow expects a local checkout. The recommended shape is:
git clone https://github.com/jasonkuhrt/hookify ~/.local/share/hookify
cd ~/.local/share/hookify
npx hookify install codex
The installer symlinks the repo's plugins/hookify/ into ~/plugins/hookify, adds a hookify plugin entry to ~/.agents/plugins/marketplace.json, and enables it in ~/.codex/config.toml. When Codex ships public plugin distribution, this collapses to a single marketplace command like the Claude path.
Both plugins ship a bundled Node-compatible dispatcher, so there is no runtime dependency beyond what the agent already has. Restart the agent after install.
Create executable handlers (.ts, .sh, .bash, etc.) or declarative markdown handlers (.md) under .hookify/<event>/ at either ~/.hookify/ (user scope) or <repo>/.hookify/ (project scope). See docs/hook-authoring.md for the event matrix, payload mapping, and markdown handler contract.
Coding agents can run hooks around prompt submission, tool calls, and session lifecycle events. Claude and Codex expose different event names, different payload shapes, and different output contracts for those same moments.
Teams that want one hook policy across agents end up maintaining two incompatible systems. Shared rules drift because the common ground is smaller than it first looks, while agent-specific rules become hard to colocate and reason about. Even when both agents support project hooks, their registration surfaces, event names, payloads, and output contracts differ enough that “same rule, two agents” turns into duplicate glue code.
Hookify splits the problem in two. A thin adapter speaks each agent's native hook protocol. The neutral runtime speaks one versioned contract for discovery, ordering, execution, and results.
Sharing is explicit in the filesystem. A hook file opts into .all, .claude, or .codex in its own name, so readers can tell whether a rule is shared or agent-specific without opening the file.
The runtime stays neutral about authoring style. It supports shared hooks, split hooks, raw native payload access, and normalized cross-agent access, but it does not encode opinions about which one a repository should prefer.
git clone git@github.com:jasonkuhrt/hookify.git
cd hookify
bun install
bun run check
bun run check runs formatting, lint, and tests for the whole workspace. Once it passes, start in the package that owns your change: packages/schema for the contract, packages/core for shared primitives, packages/runtime for execution mechanics, and packages/integration-* for installable agent glue. Contributor workflow lives in CONTRIBUTING.md.
An event is the normalized name for a hook moment such as pre-tool-use, post-tool-use, or session-start. Hookify keeps a closed set of event names so directory layout and adapter code can agree even when Claude and Codex use different native labels.
A scope tells the runtime where a hook was discovered. A scope is either user or project, which lets one user-level install stay small while project policy remains editable in the repository being worked on.
An applicability decides which agents are allowed to run a hook file. Hookify reads applicability from the filename suffix:
10-block-cmux.all.ts
20-rename-tabs.claude.sh
30-bash-guard.codex.ts
That keeps sharing explicit. .all means the file is eligible for both agents. .claude and .codex mean the file is agent-specific by choice, not by accident.
A native payload is the exact JSON emitted by an agent. A normalized event is the cross-agent shape Hookify can talk about without agent-specific field names. The envelope carries both, along with scope and session metadata, so a hook can stay portable without losing access to raw detail: