scaffold-codex-hooks
scaffold-codex-hooks
Audit the target project first, then scaffold Codex hooks with a deterministic managed layout around the current official hook model.
Decision Tree
What is the user asking for?
- New project-local Codex hooks in a repo with no hook setup yet: Verify the live official docs and schemas, audit the repo, inspect the effective feature flag, enable it if needed, then scaffold.
- Existing
.codex/hooks.json,.codex/config.toml, or.codex/hooks/files: Audit what exists first, chooseadditiveoroverhaul, then refresh only the managed hook layer. - Hooks that exist on disk but never seem to affect Codex:
Inspect the effective
hooksfeature first. If it is still off, enable it deliberately. If it is on, remember that repo-local.codex/config.tomlonly loads in trusted projects, then debughooks.json. - Explanation only, not implementation:
Read
references/hook-events.md,references/feature-flag.md, andreferences/scaffold-layout.md, then answer without scaffolding.
Quick Reference
| Task | Action |
|---|---|
| Verify the current official Codex hook model | Read https://developers.openai.com/codex/hooks, https://developers.openai.com/codex/config-basic, the generated schemas listed in assets/hook-events.json, and the runtime source links in that manifest |
| Audit a target repo | Run scripts/audit_project.sh /path/to/project |
Inspect the effective hooks feature |
Run python3 scripts/check_hooks_feature.py --project /path/to/project --json |
| Enable hooks in project config | Run python3 scripts/check_hooks_feature.py --project /path/to/project --enable --scope project |
| Enable hooks in user config | Run python3 scripts/check_hooks_feature.py --project /path/to/project --enable --scope user |
| Understand the current event catalog | Read references/hook-events.md |
| Decide additive vs overhaul | Read references/merge-strategy.md |
| Generate or refresh the managed hook scaffold | Run `scripts/scaffold_hooks.sh --project /path/to/project --plan /path/to/plan.json --mode additive |
Merge generated handlers into .codex/hooks.json |
Let scripts/scaffold_hooks.sh call scripts/merge_hooks_json.sh, or run the merge script directly |
| Regenerate the hooks README in a target project | Run scripts/render_hooks_readme.sh --project /path/to/project --plan /path/to/plan.json |
Non-Negotiable Workflow
- Verify the live official Codex hook docs before planning any scaffold.
- Compare the live docs, current schemas, and
assets/hook-events.jsonbefore assuming the event set or output contract is unchanged. - Audit the target project in detail before deciding which events to enable or which commands to run.
- Inspect the effective
hooksfeature in the target project before treating any repo-localhooks.jsonas active. - If the feature is off, enable it deliberately in the right scope:
- default to project scope for shared repo scaffolds
- use user scope for personal/global hooks or when the repo should not commit
.codex/config.toml
- Inspect any existing
.codex/config.toml,.codex/hooks.json,.codex/hooks/,AGENTS.md,README*, and other automation files before choosing a merge mode. - Produce or update a concrete hook plan JSON. Keep the scaffold deterministic by putting project-specific judgment into the plan, not into the scaffold script.
- Scaffold every current official event as a commented bash stub under the managed hook root, even if that event stays disabled in
hooks.json. - Wire only the enabled events into
.codex/hooks.jsonso inactive stubs stay cheap. - Regenerate
.codex/hooks/README.mdso the target project always has a readable event map. - If hooks still appear inactive after a real scaffold, re-check the effective feature state and remember that project config files only load in trusted projects.
Feature First Heuristic
Check hooks early whenever any of these signals appear:
- the user asks to scaffold Codex hooks into a repo
.codex/hooks.jsonexists, but nothing seems to happen- the user is unsure whether the feature flag is on
- a repo-local
.codex/config.tomlexists, but the effective feature still looks off - existing config uses the legacy
codex_hooksalias
Use this flow:
- Canonicalize the target project path first.
- Run
python3 scripts/check_hooks_feature.py --project /path/to/project --json. - If the effective status is off, enable the feature deliberately with canonical
[features].hooks = true:--scope projectfor shared repo-local setups--scope userfor personal/global setups
- Re-run the inspection after enabling.
- Only then spend time debugging
hooks.json, matcher choices, or hook script logic.
Live Docs First
The official Codex docs are the source of truth:
https://developers.openai.com/codex/hookshttps://developers.openai.com/codex/config-basichttps://developers.openai.com/codex/config-reference
For exact wire formats and current parser behavior, also verify:
https://github.com/openai/codex/tree/main/codex-rs/hooks/schema/generatedhttps://raw.githubusercontent.com/openai/codex/main/codex-rs/features/src/lib.rshttps://raw.githubusercontent.com/openai/codex/main/codex-rs/features/src/legacy.rshttps://raw.githubusercontent.com/openai/codex/main/codex-rs/hooks/src/lib.rshttps://raw.githubusercontent.com/openai/codex/main/codex-rs/config/src/hook_config.rshttps://raw.githubusercontent.com/openai/codex/main/codex-rs/hooks/src/engine/discovery.rshttps://raw.githubusercontent.com/openai/codex/main/codex-rs/hooks/src/events/common.rshttps://raw.githubusercontent.com/openai/codex/main/codex-rs/hooks/src/events/compact.rshttps://raw.githubusercontent.com/openai/codex/main/codex-rs/hooks/src/events/permission_request.rshttps://raw.githubusercontent.com/openai/codex/main/codex-rs/core/src/tools/hook_names.rs
If docs and runtime source disagree, prefer the source-backed current CLI behavior for scaffold inputs and record the docs drift. As of the current manifest, the canonical feature key is hooks; codex_hooks is a legacy alias.
Use the article at https://reading.sh/codex-hooks-just-gave-you-back-complete-control-over-your-code-57d044bcae1b as secondary material for practical patterns, not as the source of truth. Early hook writeups drifted as the feature evolved.
Project Analysis Rules
Before choosing any hook structure, inspect:
- repo root and workspace shape
- whether the project already has
.codex/config.toml,.codex/hooks.json, or.codex/hooks/ - languages and package managers
- build, test, lint, format, and validation entry points
- monorepo tools like Turborepo, Nx, pnpm workspaces, Bun workspaces, Cargo workspaces, or custom task runners
- existing AI instructions such as
AGENTS.md, project rules, or repo automation docs - existing Git hooks, Husky, Lefthook, or CI gates
- sensitive paths like
.env, secrets, lockfiles, generated code, migrations, and infra directories - whether the hook setup should be shareable in repo config or kept user-local
Run scripts/audit_project.sh first, then read references/project-analysis.md when you need the full checklist.
Deterministic vs Project-Specific Work
Keep these parts deterministic:
- managed hook root path
- event stub filenames
- generated
hooks.generated.jsonshape - merge behavior for previously managed hooks
- hooks README generation
- event manifest coverage for every current official Codex hook event
- feature-flag inspection and reporting
Allow these parts to stay project-specific:
- which events are enabled
- matcher regexes for supported events
- timeouts and status messages
- whether feature enablement belongs in project or user config
- the actual logic inside enabled event scripts
- whether the refresh is
additiveoroverhaul
Repeat-Run Rules
When the skill is invoked again against a project:
- Re-verify the live docs and schemas before assuming the event set is unchanged.
- Re-audit the project before assuming the current hook plan still fits.
- Re-check the effective feature state before assuming repo-local hooks are active.
- Preserve non-managed hooks by default.
- Treat previously generated hooks under the managed root as replaceable in
overhaulmode. - Treat previously generated hooks as append-only in
additivemode unless the managed layer or README is stale. - If the official event set or parser rules changed, update the scaffold inputs first.
Scaffold Rules
- Generate bash scripts, not Python, for the managed runtime hook stubs.
- Comment the generated bash stubs with the event-specific input and output contract.
- Default to a managed root of
.codex/hooks/generated. - Default to a hooks file target of
.codex/hooks.json. - Default to enabling
hooksin.codex/config.tomlfor shared repo scaffolds. - Use
~/.codex/config.tomlonly when the hook setup should stay personal or machine-local. - Keep one managed script per official event so the event map stays obvious.
- Keep the merged
hooks.jsondeterministic: remove only previously managed handlers, never unrelated custom hooks. - Never assume
async,prompt, oragenthooks work today. The current runtime skips them. - Treat
PreToolUse,PermissionRequest, andPostToolUseas tool-path-specific. Current support covers Bash,apply_patchwithEdit/Writematcher aliases, and MCP tool names when those paths expose hook payloads; it still does not coverWebSearchor every possible shell path. - Treat
PreCompactandPostCompactas compaction-trigger hooks. Their matcher values aremanualandauto. - Treat
Stopcarefully. For that event,decision: "block"means "continue Codex with this new prompt", not "reject the turn".
Reading Guide
| Need | Read |
|---|---|
| Full audit checklist and planning questions | references/project-analysis.md |
How to inspect and enable hooks safely |
references/feature-flag.md |
| Current source-backed event list, matcher support, and output semantics | references/hook-events.md |
| Managed folder layout and plan file shape | references/scaffold-layout.md |
| Additive versus overhaul behavior | references/merge-strategy.md |
| Runtime limits, docs drift, and fail-open traps | references/gotchas.md |
Operational Scripts
scripts/audit_project.shbuilds a project profile from real repo signals.scripts/check_hooks_feature.pyinspects or enableshooksin user or project config.scripts/scaffold_hooks.shrenders the managed hook tree, manifest, fragment, README, and feature setup.scripts/merge_hooks_json.shpreserves non-managed handlers while replacing previously managed ones.scripts/render_hooks_readme.shrebuilds.codex/hooks/README.mdfrom the manifest and current plan.scripts/validate.pychecks structure, frontmatter, manifest integrity, and cross-references.scripts/test_skill.pyruns lightweight validation plus temp-project integration checks.
Gotchas
- The feature key is
hooks;codex_hooksis only a legacy alias. Write the canonical key when editing config. matcheris ignored forUserPromptSubmitandStop. Do not design logic that depends on those matchers.async,prompt, andagentparse in config shapes, but the current runtime skips them with warnings.- Multiple matching command hooks for the same event run concurrently. One hook cannot stop another matching hook from starting.
PostToolUsecannot undo command side effects. At best it can replace the feedback Codex sees next.Stopwithdecision: "block"continues Codex with a new prompt. It does not reject the turn.- Repo-local
.codex/config.tomlonly loads in trusted projects. If you enable the feature in project scope but the project is not trusted, the effective feature can still look off. - Generated schemas currently list eight hook events, including
PermissionRequest,PreCompact, andPostCompact. Early docs and articles described smaller event sets, so re-check the official docs, schemas, and runtime source every time you scaffold for real.
More from jpcaparas/skills
markdown-new
Use markdown.new when the user explicitly wants markdown.new, Cloudflare Markdown for Agents, URL-to-Markdown conversion, file-to-Markdown conversion, crawl-to-Markdown, or the hosted markdown.new editor. Trigger on: 'markdown.new', 'convert this URL to markdown', 'crawl this docs site into markdown', 'file to markdown', 'upload this PDF to markdown', 'markdown.new API', or 'markdown editor'. Do NOT trigger for generic web search/scraping when another tool is enough, or for editing local Markdown without using the markdown.new service.
32skill-creator-advanced
Advanced skill creator for mission-critical, installable skills — API wrappers, progressively-disclosed technical documentation, CLI tool integrations, and complex multi-reference skills. Use when creating or improving skills that demand rigorous progressive disclosure, verified examples, tested operations, cross-harness compatibility, smart placement into the right repo-local or global skills directory, and self-improvement feedback loops. Triggers on: 'advanced skill', 'create API skill', 'create wrapper skill', 'production skill', 'installable skill', 'improve this skill for progressive disclosure', 'rigorous skill', 'mission-critical skill', or when skill-creator's output needs to be more thorough. Also use when upgrading an existing skill to production quality.
32azure-devops-wiki-markdown
Use when writing, fixing, or reviewing Azure DevOps wiki Markdown, Mermaid diagrams, `_TOC_` and `_TOSP_`, collapsible `<details>` blocks, query-table embeds, `@` mentions, work-item links, KaTeX math, HTML video embeds, code fences, or Azure DevOps surface-specific support differences across Wiki, PR, README, Widget, and Done fields. Triggers on Azure DevOps wiki, markdown guidance, Mermaid sequence/graph/timeline/ER diagrams, proposal decision trees, table-of-subpages, query-table, code fence aliases, line-break bugs, and wiki page formatting. Do NOT use for GitHub-only Markdown, generic Mermaid authoring outside Azure DevOps, or non-Azure documentation platforms.
29ripgrep
Prefer ripgrep (`rg`) for text search, recursive codebase search, ignore-aware grep replacement, filename discovery via `rg --files`, and machine-readable search output. Use when the user asks to search for text, find occurrences, inspect a large tree, locate files by name or pattern, or when `grep`, `grep -R`, `find | grep`, or manual file reads would be slower. Triggers on: 'search for', 'find occurrences', 'grep', 'grep -R', 'ripgrep', 'rg', 'find files', 'look for pattern'. Do NOT trigger for reading entire files, structured JSON queries better handled by `jq`, or filesystem metadata tasks that need `find` or `fd`.
29synthetic-search
Use this skill when the user explicitly wants Synthetic Search, the Synthetic API, `api.synthetic.new`, `SYNTHETIC_API_KEY`, or zero-data-retention web search with raw `curl`/`jq` examples. It covers live-verified search requests, quota checks, and a zero-dependency Node helper for readable output. Triggers on: 'Synthetic Search', 'Synthetic API', 'api.synthetic.new', 'SYNTHETIC_API_KEY', 'Synthetic quotas'. Do NOT trigger for general browser automation, full-site crawling, or unrelated search providers.
29tweet-replicate
Rebuild a public X/Twitter status into a deterministic local replica with a frozen snapshot, local HTML/CSS, Playwright capture, X-like media-frame fill behavior, a high-quality MP4 master, and a companion GIF capped under 24 MB. Use when asked to replicate a tweet/X post, freeze a status into video, make a tweet look like X offline, or create rerenderable tweet assets with a saved build folder. Trigger on: 'replicate this tweet', 'turn this X post into MP4', 'make this tweet into a GIF too', 'freeze this status locally'. Do NOT use for plain tweet text extraction, raw media download only, live X browser capture, authenticated pages, DMs, or promises of a pixel-perfect private X renderer.
29