# Codex Native Hooks Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Give Codex CLI users native Superpowers startup behavior through trusted Codex plugin hooks, keep the current Codex plugin/skills path as a fallback while `plugin_hooks` is gated, and prepare Codex App user-facing parity behind a visible `/hooks` UI smoke test. **Architecture:** Add a Codex-specific hook manifest that points Codex at the existing shared `hooks/session-start` implementation through the existing cross-platform `hooks/run-hook.cmd` wrapper. Package the hook files into the official Codex plugin sync output. Keep Claude Code's existing `hooks/hooks.json`, Cursor's `hooks/hooks-cursor.json`, and Copilot/unknown-platform output behavior unchanged. **Tech Stack:** Bash hook scripts, JSON plugin manifests, shell regression tests, Node.js only for JSON parsing in tests, Codex CLI/app-server smoke verification. No new runtime dependencies. --- ## Source Map - Spec: `docs/superpowers/specs/2026-05-12-codex-native-hooks-design.md` - Codex plugin manifest: `.codex-plugin/plugin.json` - Claude hook manifest: `hooks/hooks.json` - Cursor hook manifest: `hooks/hooks-cursor.json` - New Codex hook manifest: `hooks/hooks-codex.json` - Shared hook wrapper: `hooks/run-hook.cmd` - Shared hook implementation: `hooks/session-start` - Codex plugin sync script: `scripts/sync-to-codex-plugin.sh` - Codex sync regression test: `tests/codex-plugin-sync/test-sync-to-codex-plugin.sh` - New hook output regression test: `tests/hooks/test-session-start.sh` - User docs: `README.md` - Windows hook docs: `docs/windows/polyglot-hooks.md` ## Locked Decisions - Use `hooks/hooks-codex.json` for Codex instead of changing the shared Claude `hooks/hooks.json`. - Do not add `resume` to the Claude matcher until Claude Code is explicitly verified to accept it. - Use Codex's verified `${PLUGIN_ROOT}` placeholder in the Codex manifest command. - Do not use or document `CODEX_PLUGIN_ROOT`; Codex plugin hooks provide `PLUGIN_ROOT`, `CLAUDE_PLUGIN_ROOT`, `PLUGIN_DATA`, and `CLAUDE_PLUGIN_DATA`. - Do not auto-trust hooks from Superpowers. Users trust executable hooks through Codex's `/hooks` UI. - Keep fallback behavior: Codex users without enabled/trusted plugin hooks still get installed skills, but not automatic startup bootstrap. - Treat App runtime support as verified through the bundled app-server, but only claim App user-facing parity after a visible App `/hooks` UI smoke test. ## Task 1: Baseline And Contract Check - [ ] Run: ```bash git status --short --branch codex --version codex features list /Applications/Codex.app/Contents/Resources/codex --version ``` - [ ] Expected observations: - Worktree status is understood before edits. - Local Codex is at least `0.130.0`. - `plugin_hooks` exists and is still under development/default-off, or any drift is recorded in the implementation notes. - App-bundled Codex can be invoked, or the App smoke task is marked blocked with the exact command error. - [ ] Read the files in the Source Map before editing. ## Task 2: Add SessionStart Output Regression Tests - [ ] Create `tests/hooks/test-session-start.sh`. - [ ] The test file must: - Run from any current working directory. - Use a temporary `HOME` for each scenario. - Invoke the real `hooks/session-start`. - Parse JSON with Node.js from stdin; do not add npm dependencies. - Fail on invalid JSON, empty injected context, or platform output shape drift. - [ ] Cover these scenarios: - Claude Code: `CLAUDE_PLUGIN_ROOT="$REPO_ROOT"` emits `hookSpecificOutput.hookEventName = "SessionStart"` and a non-empty `hookSpecificOutput.additionalContext`. - Codex plugin hooks: `PLUGIN_DATA="$tmp/data" CLAUDE_PLUGIN_DATA="$tmp/data" PLUGIN_ROOT="$REPO_ROOT" CLAUDE_PLUGIN_ROOT="$REPO_ROOT"` emits the same nested `hookSpecificOutput.additionalContext` shape. - Cursor: `CURSOR_PLUGIN_ROOT="$REPO_ROOT" CLAUDE_PLUGIN_ROOT="$REPO_ROOT"` emits top-level `additional_context` and does not also emit `hookSpecificOutput`. - Copilot CLI: `COPILOT_CLI=1 CLAUDE_PLUGIN_ROOT="$REPO_ROOT"` emits top-level `additionalContext` and does not also emit `hookSpecificOutput`. - Claude legacy warning: with `$HOME/.config/superpowers/skills` present and `CLAUDE_PLUGIN_ROOT="$REPO_ROOT"`, the injected context still contains the existing Claude migration guidance to `~/.claude/skills`. - Codex legacy warning: with `$HOME/.config/superpowers/skills` present and the Codex plugin-hook environment, the injected context does not mention `~/.claude/skills` or "Claude Code's skills system" and instead uses harness-neutral custom-skill wording. - [ ] Run the test before changing `hooks/session-start`: ```bash bash tests/hooks/test-session-start.sh ``` - [ ] Expected result before implementation: the Codex legacy warning scenario fails because the current shared hook sees `CLAUDE_PLUGIN_ROOT` and emits Claude-specific migration text. ## Task 3: Make Legacy Warning Text Harness-Aware - [ ] Edit `hooks/session-start`. - [ ] Preserve these existing behaviors: - The script derives the plugin root from its own location. - The script reads `skills/using-superpowers/SKILL.md`. - Cursor receives only top-level `additional_context`. - Claude receives only nested `hookSpecificOutput.additionalContext`. - Codex receives the same nested shape as Claude, because the verified Codex parser accepts it and Codex sets `CLAUDE_PLUGIN_ROOT`. - Copilot and unknown platforms receive only top-level `additionalContext`. - [ ] Add Codex detection before building the legacy warning. Use Codex data env vars, not the locally derived `PLUGIN_ROOT` variable: ```bash is_codex_hook=0 if [ -n "${PLUGIN_DATA:-}" ] || [ -n "${CLAUDE_PLUGIN_DATA:-}" ]; then is_codex_hook=1 fi ``` - [ ] Keep the current Claude legacy warning text for non-Codex Claude. - [ ] For Codex hook runs, use this neutral warning content when `$HOME/.config/superpowers/skills` exists: ```text WARNING: Superpowers now uses your coding agent's native skills system. Custom skills in ~/.config/superpowers/skills will not be read. Move custom skills to a skills location supported by your coding agent. To make this message go away, remove ~/.config/superpowers/skills ``` - [ ] Re-run: ```bash bash tests/hooks/test-session-start.sh ``` - [ ] Expected result after implementation: all session-start scenarios pass. ## Task 4: Add Codex Hook Manifest - [ ] Add `hooks/hooks-codex.json`: ```json { "hooks": { "SessionStart": [ { "matcher": "startup|resume|clear", "hooks": [ { "type": "command", "command": "\"${PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start", "async": false } ] } ] } } ``` - [ ] Edit `.codex-plugin/plugin.json` and add: ```json "hooks": "./hooks/hooks-codex.json" ``` - [ ] Keep `.claude-plugin/plugin.json`, `.cursor-plugin/plugin.json`, `hooks/hooks.json`, and `hooks/hooks-cursor.json` unchanged unless a test proves they must change. - [ ] Validate JSON: ```bash node -e 'for (const f of [".codex-plugin/plugin.json","hooks/hooks-codex.json","hooks/hooks.json","hooks/hooks-cursor.json"]) JSON.parse(require("fs").readFileSync(f,"utf8"));' ``` ## Task 5: Package Hooks In Codex Plugin Sync - [ ] Edit `scripts/sync-to-codex-plugin.sh`. - [ ] Remove the `/hooks/` entry from `EXCLUDES`. - [ ] Do not broaden the sync script beyond this packaging change. - [ ] Edit `tests/codex-plugin-sync/test-sync-to-codex-plugin.sh` fixtures: - In `write_upstream_fixture`, create: - `hooks/hooks-codex.json` - `hooks/session-start` - `hooks/run-hook.cmd` - Add those files to the upstream fixture commit. - In `write_synced_destination_fixture`, create and commit the same hook files under `plugins/superpowers/hooks/` so the clean no-op apply scenario stays clean. - [ ] Add preview assertions: - Preview includes `hooks/hooks-codex.json`. - Preview includes `hooks/session-start`. - Preview includes `hooks/run-hook.cmd`. - [ ] Add clean no-op assertion: - Clean no-op local apply reports no changes when hook files are already synced. - [ ] Run: ```bash bash tests/codex-plugin-sync/test-sync-to-codex-plugin.sh ``` - [ ] Expected result: all existing sync assertions still pass, and the new hook packaging assertions pass. ## Task 6: Update README Codex Docs - [ ] Edit `README.md`. - [ ] In `### Codex CLI`, keep the existing marketplace install steps and add a short optional preview subsection after install: ````markdown #### Automatic startup bootstrap Codex plugin hooks are still gated behind Codex's `plugin_hooks` feature. To opt in: ```bash codex features enable plugin_hooks ``` Restart Codex, open `/hooks`, review the Superpowers `SessionStart` hook, and trust it. Codex will ask you to re-review the hook after Superpowers updates if the hook definition changes. If `plugin_hooks` is disabled, unavailable, or untrusted, Superpowers still installs as a normal Codex plugin and the skills remain available. The automatic startup bootstrap is the part that waits for the trusted hook. ```` - [ ] In `### Codex App`, keep the existing install steps. - [ ] If the visible App `/hooks` UI smoke in Task 9 passes during implementation, add the same automatic startup bootstrap subsection to `### Codex App`, with the enablement step described as the persisted Codex config path: ```bash codex features enable plugin_hooks ``` - [ ] If the visible App `/hooks` UI smoke is blocked or fails, do not claim automatic App startup bootstrap in the README. Record the App smoke status in the implementation summary instead. - [ ] README wording must not imply automatic startup for Codex users who have not enabled and trusted plugin hooks. ## Task 7: Update Windows Hook Docs - [ ] Edit `docs/windows/polyglot-hooks.md`. - [ ] Update stale references: - Replace `session-start.cmd` with `run-hook.cmd`. - Replace `session-start.sh` with extensionless `session-start`. - Show `hooks/hooks-codex.json` as the Codex-specific manifest. - Keep `hooks/hooks.json` as the Claude Code manifest. - Mention Codex uses `${PLUGIN_ROOT}` and `startup|resume|clear`. - [ ] The docs must describe the current file structure: ```text hooks/ |-- hooks.json |-- hooks-codex.json |-- hooks-cursor.json |-- run-hook.cmd `-- session-start ``` - [ ] Update the Windows simulation command to: ```powershell $env:CLAUDE_PLUGIN_ROOT = "C:\path\to\plugin" cmd /c "C:\path\to\plugin\hooks\run-hook.cmd session-start" ``` - [ ] Do not add Windows-specific runtime dependencies. ## Task 8: Run Codex CLI Native Hook Smoke - [ ] Build a temporary isolated Codex home and staged plugin from the working tree: ```bash SMOKE_HOME="$(mktemp -d)" SMOKE_PLUGIN="$SMOKE_HOME/plugins/cache/debug/superpowers/local" mkdir -p "$SMOKE_PLUGIN" rsync -a --exclude .git ./ "$SMOKE_PLUGIN/" ``` - [ ] Use persisted feature config, not undocumented root CLI feature flags: ```bash cat > "$SMOKE_HOME/config.toml" <<'EOF' [features] plugins = true hooks = true plugin_hooks = true [plugins."superpowers@debug"] enabled = true EOF ``` - [ ] Run Codex `app-server --listen stdio://` against the temp home and call `hooks/list`: ```bash CODEX_HOME="$SMOKE_HOME" codex app-server --listen stdio:// ``` - [ ] Expected `hooks/list` result: - One Superpowers `SessionStart` plugin hook appears from `hooks/hooks-codex.json`. - The hook matcher is `startup|resume|clear`. - The expanded command points at `hooks/run-hook.cmd session-start`. - Initial `trustStatus` is `untrusted` unless the temp config already contains a trusted hash. - [ ] Trust the hook only inside the temp home using `hooks/list` `currentHash` plus `config/batchWrite`. - [ ] Start a clean Codex thread and trigger a turn. - [ ] Expected event/result: - `hook/started` and `hook/completed` events are emitted for the Superpowers `SessionStart` hook. - The resulting context includes the Superpowers startup text from `using-superpowers`. - [ ] Keep this as a development smoke only. Do not document headless trust as normal user setup. ## Task 9: Run Codex App Visible UI Smoke - [ ] Confirm the App-bundled Codex runtime version: ```bash /Applications/Codex.app/Contents/Resources/codex --version ``` - [ ] With `plugin_hooks` enabled in persisted Codex config, launch the Codex App. - [ ] Install or use the staged Superpowers plugin in the App. - [ ] Open a clean App thread and observe the startup warning, if any. - [ ] Open `/hooks`. - [ ] Expected UI result: - The Superpowers `SessionStart` hook is listed. - The UI shows the hook command/source for review. - Trusting the hook is possible from the UI. - Toggling enabled after trust makes the hook runnable. - [ ] Run the acceptance prompt in a clean App thread: ```text Let's make a react todo list ``` - [ ] Passing App result: - The agent sees the Superpowers startup context automatically. - `superpowers:brainstorming` triggers before code is written. - [ ] If the App UI smoke passes, update README App docs in Task 6 and record the transcript or concise evidence in the PR body. - [ ] If the App UI smoke is blocked or fails, leave README App docs limited to plugin installation and report the exact blocker. ## Task 10: Final Verification - [ ] Run: ```bash bash tests/hooks/test-session-start.sh bash tests/codex-plugin-sync/test-sync-to-codex-plugin.sh node -e 'for (const f of [".codex-plugin/plugin.json","hooks/hooks-codex.json","hooks/hooks.json","hooks/hooks-cursor.json"]) JSON.parse(require("fs").readFileSync(f,"utf8"));' git diff --check ``` - [ ] Run the Codex CLI smoke from Task 8. - [ ] Run the App UI smoke from Task 9, or record why it could not be completed. - [ ] Review the diff: ```bash git diff -- .codex-plugin/plugin.json hooks scripts tests README.md docs/windows/polyglot-hooks.md ``` - [ ] Confirm no unrelated files changed. - [ ] If opening a PR, follow `.github/PULL_REQUEST_TEMPLATE.md`, search open and closed PRs for overlapping Codex hook work, include the relevant smoke evidence, and call out whether App UI smoke passed. ## Completion Criteria - `hooks/hooks-codex.json` exists and is referenced by `.codex-plugin/plugin.json`. - Codex plugin sync includes the `hooks/` directory and tests prevent future accidental exclusion. - `hooks/session-start` still emits valid JSON for Claude, Codex, Cursor, Copilot, and unknown platform paths. - Codex docs explain enablement, `/hooks` trust, re-review after updates, and fallback behavior without overclaiming default automatic startup. - App docs claim automatic startup only if the visible App `/hooks` UI smoke passes. - No new dependencies are introduced. - Claude Code, Cursor, and Copilot behavior is not changed except for any neutral warning text that tests explicitly cover.