Skip to content

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

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

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
Contributor

@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
Contributor 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
Contributor Author

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

@sebastianbreguel
Copy link
Copy Markdown
Contributor Author

@tirth8205 up

@tirth8205
Copy link
Copy Markdown
Owner

Closing in favor of #208 which was just merged.

Your PR is very solid — it correctly fixes all three schema bugs (nested hooks array, removes PreCommit, converts timeouts to seconds), has excellent regression tests (test_does_not_emit_precommit and test_all_commands_wrapped_in_inner_hooks_array), and includes a CHANGELOG entry. The test coverage and the link to the official Claude Code docs in the description were particularly helpful.

The reason #208 was chosen over this PR is one feature: #208 restores the pre-commit behavior that was lost when removing the invalid PreCommit hook event. It does this correctly by adding install_git_hook() which writes a real .git/hooks/pre-commit script (with append-to-existing and idempotency support) rather than trying to use a non-existent Claude Code event.

One minor note: this PR keeps timeout: 5000 and timeout: 3000 for PostToolUse and SessionStart respectively. The Claude Code docs state timeouts are in seconds, so these would mean 83-minute and 50-minute timeouts. PR #208 corrects these to 30s and 10s. If you reopen or update this PR, that should be fixed too.

Thank you for the thorough fix and detailed write-up — it was the clearest description of the three bugs.

@tirth8205 tirth8205 closed this Apr 11, 2026
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