@incu/hooks
v0.2.0
Published
Package manager for AI agent hooks — npx hooks.sh add owner/repo
Readme
hooks
Package manager for AI agent hooks — the event-driven automations agents run
around their own lifecycle (before/after tool use, on session start, on stop, …).
Package, install, update, and remove hook packs from a Git repo, public or
private. Same workflow as npx skills and npx steering.sh, but for hooks.
npx skills add owner/repo → skills → .agents/skills/
npx steering.sh add owner/repo → rules → .kiro/steering/ etc.
npx hooks.sh add owner/repo → hooks → .claude/settings.json etc.Hooks are different from skills and rules: they are commands the agent executes
automatically on events, not content it reads. So hooks.sh:
- Always shows the full plan and asks for approval before touching anything —
every
event → matcher → command, the scripts it will copy, and the settings file it will merge into.--yesfor automation,--dry-runto preview. - Merges, never clobbers. Hooks live inside shared agent config
(
.claude/settings.json). Installs are additive, idempotent, and exactly reversible — your hooks and other packs' hooks are never touched. - Never executes anything. It only places and removes hooks. The agent runs them.
Install / invocation
Published under two names — same tool, pick whichever you prefer:
| Run with | Package |
|----------|---------|
| npx hooks.sh <cmd> | hooks.sh (short, brandable — recommended) |
| npx @incu/hooks <cmd> | @incu/hooks (canonical package) |
npm i -g hooks.sh # or: pnpm add -g hooks.sh
hooks add owner/repo # the `hooks` command is now on your PATHQuick start
npx hooks.sh add incu/hook-packs # plan → approve → merge
npx hooks.sh add incu/hook-packs --dry-run # preview the plan, write nothing
npx hooks.sh add incu/hook-packs -g -y # global, no prompt (automation)
npx hooks.sh list # installed packs + event summary
npx hooks.sh check # compare installed packs vs source
npx hooks.sh update # re-install changed packs (re-approve)
npx hooks.sh remove block-force-push # remove exactly what the pack addedHook pack format
A hook pack is a directory with a canonical hooks.json plus any scripts it
references:
my-hooks/
├── hooks.json # canonical manifest (Claude Code hooks schema)
├── hooks.sh.json # pack metadata: name, version, description
└── scripts/
└── check-gate.sh # referenced by hooks.json via $PACK/scripts/check-gate.sh// hooks.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "$PACK/scripts/check-gate.sh", "timeout": 30 }]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
// Prompt hooks: evaluated by the agent (Claude Code `type: prompt`, Kiro `askAgent`).
"hooks": [{ "type": "prompt", "prompt": "Validate the file you just wrote." }]
}
],
"SessionStart": [{ "hooks": [{ "type": "command", "command": "$PACK/scripts/banner.sh" }] }]
}
}$PACK expands at install time to the pack's installed scripts dir, so packs are
relocatable. Scaffold one with npx hooks.sh init my-hooks.
Placement targets (v1)
| Agent | Target | Mechanism |
| --- | --- | --- |
| Claude Code (pivot format) | .claude/settings.json (~/.claude/settings.json with -g); scripts under .claude/hooks/<pack>/ | managed merge |
| Cursor | .cursor/hooks.json | event-map conversion from the pivot (command hooks only) |
| Kiro | .kiro/hooks/<pack>--<event>-<n>.kiro.hook | managed file-drop: command → runCommand, prompt → askAgent; unmappable events degrade with a report |
| Codex | Codex CLI config | best-effort mapping; unmappable events degrade honestly |
| others | — | honest degradation: "no hook system mapped for <agent>" |
Without --agent, targets are auto-detected from the workspace, falling back to
Claude Code. Every unmappable event produces a visible degradation line — never a
silent drop.
Commands
| Command | Description |
| --- | --- |
| add <source> | Install a hook pack (owner/repo[/subdir][@ref], any git remote, or local path) — plan → approve → merge |
| list, ls | Installed packs per scope/agent, with event summary |
| check | Compare installed packs against their sources |
| update | Re-install changed packs (re-approval on content change) |
| remove <pack>, rm | Remove exactly the entries + scripts the pack contributed |
| init [name] | Scaffold a pack (hooks.json + hooks.sh.json + example script) |
| convert <source> | Convert a pack between agent hook formats (pivot: Claude Code) |
Flags: -g/--global, --agent <fmt> (repeatable), -y/--yes, --dry-run, --json.
--agent/--to/--from also accept the skills-CLI agent names (kiro-cli → kiro).
Exit codes: 0 placed / up to date · 1 refused/failed · 2 usage · 3 add:
nothing placed (all targets degraded). Programmatic callers: the --json shape
and exit-code semantics are frozen in docs/json-contract.md.
Sources
Besides GitHub (owner/repo, https://github.com/...), add/check/update
work with any git remote — GitLab, Bitbucket, Azure DevOps, Gitea or
self-hosted — over HTTPS or SSH:
npx hooks.sh add https://git.example.com/team/hook-packs.git
npx hooks.sh add [email protected]:team/hook-packs.git#main@block-force-pushGeneric git sources are shallow-cloned with your own git credentials (SSH agent or credential helper); hooks.sh never prompts for or stores tokens for them.
Environment
GITHUB_TOKEN/GH_TOKEN— auth for private repos & higher rate limits (GitHub API only).HOOKS_NO_BANNER/NO_COLOR— hide the wordmark banner.DISABLE_TELEMETRY/DO_NOT_TRACK— telemetry is disabled in this build.
License
MIT. Forked from steering.sh and
vercel-labs/skills.
