Skip to content

fix: generate valid Claude Code hook schema (closes #138)#141

Open
sebastianbreguel wants to merge 1 commit intotirth8205:mainfrom
sebastianbreguel:fix/138-valid-hook-schema
Open

fix: generate valid Claude Code hook schema (closes #138)#141
sebastianbreguel wants to merge 1 commit intotirth8205:mainfrom
sebastianbreguel:fix/138-valid-hook-schema

Conversation

@sebastianbreguel
Copy link
Copy Markdown

@sebastianbreguel sebastianbreguel commented Apr 8, 2026

Closes #138

Problem

generate_hooks_config() emits a hooks config that Claude Code rejects with schema errors, so code-review-graph install corrupts ~/.claude/settings.json. Three bugs in the same function:

  1. PreCommit is not a valid Claude Code hook eventInvalid key in record.
  2. Missing inner hooks array wrapper. Each entry must have hooks: [{type: "command", command, timeout}], but the old output put command/timeout directly on the entry → hooks: Expected array, but received undefined (the exact error in the issue for SessionStart).
  3. Timeouts in milliseconds instead of seconds. 5000, 3000, 10000 — the PostToolUse hook effectively had an 83-minute timeout.

Verified against the official schema: https://docs.claude.com/en/docs/claude-code/hooks

Fix

Rewrite generate_hooks_config() to match the documented schema:

"PostToolUse": [
  {
    "matcher": "Edit|Write|Bash",
    "hooks": [
      {"type": "command", "command": "code-review-graph update --quiet --skip-flows", "timeout": 5}
    ]
  }
]
  • Remove the PreCommit entry (no equivalent Claude Code event; pre-commit behavior belongs in a git hook).
  • Wrap PostToolUse and SessionStart handlers in hooks: [{type: "command", ...}].
  • Convert timeouts from ms to seconds (50005, 30003).

Testing

  • test_has_post_tool_use / test_has_session_start updated for the nested structure
  • New test_does_not_emit_precommit — regression guard for this issue
  • New test_all_commands_wrapped_in_inner_hooks_array — structural invariant
  • Full suite: 611 passed, 5 skipped, 0 failed
  • ruff check clean

@sebastianbreguel
Copy link
Copy Markdown
Author

@tirth8205 hey! could you review this one too? it fixes the hook schema generation (issue #138)

Copy link
Copy Markdown
Owner

@tirth8205 tirth8205 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a critical correctness fix — the hook schema rewrite looks solid. 4 regression tests, clean approach.

Please rebase on latest main (PR #152 just merged and touches the same skills.py file). Once rebased and CI passes, this is good to merge.

The hooks config emitted by `generate_hooks_config()` did not match the
Claude Code schema, so `code-review-graph install` was writing an
invalid ~/.claude/settings.json. Three problems:

1. `PreCommit` is not a valid hook event — removed.
2. Every event entry needs an inner `hooks: [{type: "command", ...}]`
   array; the old output put `command`/`timeout` directly on the entry,
   which Claude Code rejects with "hooks: Expected array, but received
   undefined".
3. Timeouts were in milliseconds (5000, 3000, 10000), but the schema
   uses seconds — the PostToolUse hook effectively had an 83-minute
   timeout. Converted to 5 and 3 seconds.

Verified against the official schema at
https://docs.claude.com/en/docs/claude-code/hooks.

Tests updated to assert the new nested structure and guard against
regressions (PreCommit not emitted, all handlers wrapped in inner
hooks array with type=command).
@sebastianbreguel sebastianbreguel force-pushed the fix/138-valid-hook-schema branch from 573b855 to 27c0cc3 Compare April 8, 2026 19:42
@sebastianbreguel
Copy link
Copy Markdown
Author

@tirth8205 Rebased on latest main, conflicts resolved, CI is green. Ready to merge when you are!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PreCommit and SessionStart are not valid hook events but aren't documented as invalid

2 participants