Hooks aren't firing in my consumer project — how do I debug?

The symptom: a hook that used to block (commit messages, gates) silently stopped. Debug in this order — each step catches a different failure class:

  1. Watch the hook log live while you trigger an action:

    cos hooks-log --follow
    

    If entries appear, hooks are firing and the question becomes why one passed. If nothing appears, continue.

  2. Check symlink integrity. Consumer projects receive core hooks as live symlinks; moving/renaming the project directory or an aggressive git clean can dangle them:

    cos sync-doctor --repair
    
  3. Run the doctor — it verifies the whole chain (env vars, agent settings file, state dir):

    cos doctor
    
  4. Check your agent settings file — the adapter registers hooks in the runtime’s settings (e.g. .claude/settings.json for Claude Code). If it was ever hand-edited, re-run cos update to re-render it.

  5. Runtime check — Claude Code and Codex both run hooks at full parity. On an unsupported runtime, in-session hooks won’t fire at all and the git-level hooks are the safety net.

Most real cases are #2 — dangling symlinks after a directory move. cos sync-doctor --repair fixes them in place.