Confirmed the report before fixing it: .codex/hooks.json was copied wholesale by _copy_skeleton under --force. It was in neither NEVER_OVERWRITE_DOWNSTREAM nor the state-protected set, so any repo-owned entry in that file was destroyed. Codex reads ONE hooks file per repo, so the plugin's entries and the repo's necessarily share it - exactly the case .claude/settings.json was already merged for.

.codex/hooks.json is now protected from the wholesale copy and refreshed by _merge_codex_hooks instead: entries whose command runs prd_hook_dispatch are ours and get replaced; everything else is kept. Ownership is read off the command rather than tracked in a manifest, so repos installed by older versions are handled with no record of what was written last time. An unreadable hooks.json is left untouched.

Five tests, two of which failed before the change: the repo's hook survives; the plugin's five entries are present and byte-equal to the shipped template; a stale plugin entry is replaced rather than duplicated; an unparseable file is never rewritten; a fresh repo still gets the shipped file exactly.
