# Hook Manager

> List, enable, or disable individual core hooks and check their prerequisites. Use for "list hooks", "enable a hook", "disable a hook", "hook setup", "hooks config", or a [BOPEN-HOOKS-SETUP] directive. For the full harness view, use setup.

- Skill: `b-open-io-prompts/hook-manager` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add b-open-io-prompts/hook-manager`
- Raw SKILL.md: https://api.skillmd.com/api/skills/b-open-io-prompts/hook-manager/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: b-open-io (https://skillmd.com/u/b-open-io-prompts)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/b-open-io-prompts/hook-manager

---


# Hook Manager

Manage the hooks that ship with the core plugin across Claude Code, Codex,
and Grok Build. The catalog source of truth is `hooks/manifest.json` in the
installed plugin — read it live rather than trusting a memorized list:

```bash
cat "$(ls -d ~/.claude/plugins/cache/b-open-io/core/*/ | sort -V | tail -1)hooks/manifest.json"
```

Each entry carries `name`, `event`, `matcher`, `tier`, `runtimes`, `summary`, and
`description`. Hooks register automatically when the plugin is installed;
this skill controls which ones actually run.

## The config file

Per-hook enable/disable lives in a JSON config. Resolution order (first file
with an explicit `true`/`false` verdict for a hook wins):

1. `$BOPEN_HOOKS_CONFIG` — explicit override (tests, scripts)
2. `<project>/.claude/bopen-hooks.json` — per-project (Claude)
3. `<project>/.grok/bopen-hooks.json` — per-project (Grok)
4. `~/.claude/core/hooks-config.json` — per-user (Claude)
5. `~/.grok/core/hooks-config.json` — per-user (Grok)

```json
{
  "version": 1,
  "hooks": {
    "bouncer": true,
    "damage-control": true,
    "publish-gate": true,
    "agent-browser-solo": true,
    "session-context": true,
    "hammertime": true,
    "browser-intent": true
  }
}
```

A hook is disabled ONLY by an explicit `false`. Missing files, missing keys,
or unparseable JSON all mean enabled — a broken config must never silently
switch the guards off. Changes take effect on the next hook invocation; no
restart is required.

## First-time setup (the [BOPEN-HOOKS-SETUP] directive)

When session context carries `[BOPEN-HOOKS-SETUP]`, the user has no config
yet. Do not interrupt their task; offer setup at a natural pause. The flow:

1. Read the manifest (command above) and present the hooks in two tiers via
   AskUserQuestion (multiSelect):
   - **Guards (recommended on)**: entries with `tier: "guard"` —
     they prevent work loss, secret exposure, and unticketed publishes.
   - **Workflow (preference)**: entries with `tier: "workflow"`.
2. Run the prerequisite checks below and fold findings into the
   recommendation (e.g. agent-browser-solo without agent-browser installed
   silently falls back to native WebFetch — still safe to leave on).
3. Write `~/.claude/core/hooks-config.json` (Claude/Codex) or
   `~/.grok/core/hooks-config.json` (Grok) with the full hooks map —
   include every hook with an explicit boolean, even the all-defaults case.
   Writing the file is what dismisses the setup notice permanently.

## Enabling / disabling a hook

Edit the user config (or project config for repo-scoped changes) with the
Read and Write tools — read, flip the boolean, write back. Create the file
from the template above when it does not exist. Never edit files inside the
plugin cache; updates overwrite them.

Expect a confirmation prompt on every config write: damage-control treats
these files as ask-tier so guards can never be disarmed without the user's
explicit yes (on Codex the write is denied outright — have the user edit
the file themselves). This is by design; do not route around it.

Warn before disabling guards: bouncer stops `git reset --hard`-class work
loss, damage-control enforces zero-access paths like `.env`, publish-gate
blocks unticketed npm/on-chain publishes. Disabling them is the user's call,
but say plainly what protection goes away.

## Diagnosis

When a hook misbehaves or the user asks "why did X get blocked/skipped":

```bash
# Which config verdict applies to a hook?
for f in "$BOPEN_HOOKS_CONFIG" ./.claude/bopen-hooks.json ./.grok/bopen-hooks.json ~/.claude/core/hooks-config.json ~/.grok/core/hooks-config.json; do
  [ -f "$f" ] && echo "$f: $(jq -r '.hooks["<name>"] // "no verdict"' "$f")"
done

# Prerequisites
command -v jq || echo "jq missing — hooks fail open without it"
command -v agent-browser || echo "agent-browser missing — agent-browser-solo falls back to native WebFetch"
[ -n "$LINEAR_API_KEY" ] || echo "LINEAR_API_KEY unset — publish-gate fails closed on gated publishes"
command -v python3 || echo "python3 missing — hammertime and JSON escaping degrade"
```

- Hard denies surface to the model as structured permission denials; on the
  Codex runtime they arrive as stderr JSON with exit 2. Both are by design.
- hammertime also has its own controls — `Skill(core:hammertime)` and
  the `hammertime:manage` skill — for rule-level tuning beyond on/off.
- The definitive behavior reference for every hook is its script header in
  the plugin's `hooks/` directory; read it before guessing.

## What this skill never does

- Never copies hook files into `~/.claude` — hooks ship with the plugin and
  update through `claude plugin update core@b-open-io`.
- Never edits `hooks/*.sh`, `claude-hooks.json`, or anything in the plugin
  cache.
- Never disables a guard hook without telling the user what it protected.

