Skip to content

fix(hooks): pre-commit gate denies instead of ending the turn#2737

Merged
vanceingalls merged 1 commit into
mainfrom
07-22-fix_hooks_pre-commit_gate_denies_commit_instead_of_ending_the_turn
Jul 22, 2026
Merged

fix(hooks): pre-commit gate denies instead of ending the turn#2737
vanceingalls merged 1 commit into
mainfrom
07-22-fix_hooks_pre-commit_gate_denies_commit_instead_of_ending_the_turn

Conversation

@vanceingalls

Copy link
Copy Markdown
Collaborator

Problem

The shared pre-commit hook in .claude/settings.json (a PreToolUse:Bash gate that runs build/lint/typecheck before committing) emitted { continue: false, stopReason } on failure. continue: false ends the agent's turn — so on every failed gate the dev had to manually type "continue" to resume, and the failure text never reached the agent as actionable feedback.

Fix

Switch the failure branch to a PreToolUse deny decision (hookSpecificOutput.permissionDecision: "deny" + permissionDecisionReason). Same guard — the failing commit is still blocked — but the failure text returns to the agent as tool feedback, so it fixes the issue and retries without a manual nudge.

File is git-tracked and shared, so every dev inherits the fixed behavior on next pull.

🤖 Generated with Claude Code

The pre-commit build/lint/typecheck PreToolUse hook emitted {continue:false,
stopReason}, which halts the agent's turn — the dev had to type 'continue'
after every failed gate. Switch to a PreToolUse deny decision so the failing
commit is still blocked but the failure text is fed back to the agent as tool
feedback, letting it fix and retry without a manual nudge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@miga-heygen miga-heygen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

$REVIEW_BODY

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Clean, narrowly scoped hook fix at exact head 97ec7db.

  • .claude/settings.json:11 now returns the documented PreToolUse deny payload (hookSpecificOutput.hookEventName, permissionDecision: "deny", and permissionDecisionReason), so the commit remains blocked while the failure is returned as actionable tool feedback.
  • The surrounding command matcher and build/lint/typecheck gate are unchanged; the settings file parses as valid JSON.
  • Required checks are pass/skipped as expected for this config-only change.

Verdict: APPROVE
Reasoning: The one-line semantic change matches the official hook contract and fixes the turn-ending behavior without weakening the commit gate.

— Magi

@james-russo-rames-d-jusso james-russo-rames-d-jusso left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correct minimal fix. Switching the PreToolUse hook's failure output from { continue: false, stopReason } to { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason } } preserves the guard semantics (git commit still blocked) while returning the failure text to the agent as tool feedback instead of terminating the turn — matches Claude Code's hook contract for a PreToolUse permission decision.

Sanity-checked:

  • JSON still parses; single hook in the file, no other continue: false sites to align.
  • Every non-output branch of the script (cd <path> target resolution, git rev-parse repo detection, hyperframes-monorepo name gate, three build/lint/typecheck steps, 400-char failure truncation) is byte-identical — this is purely an output-format switch.
  • Wording nudge from "Fix the issues above before committing." → "Fix the issues above, then retry the commit." is right for the new shape: the message is now agent-facing feedback, not a user-facing stop reason.

LGTM from my side. Stamps sit with James.

Review by Rames D Jusso

@vanceingalls
vanceingalls merged commit c39f3cf into main Jul 22, 2026
41 checks passed
@vanceingalls
vanceingalls deleted the 07-22-fix_hooks_pre-commit_gate_denies_commit_instead_of_ending_the_turn branch July 22, 2026 22:45

@miga-heygen miga-heygen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SSOT Review: pre-commit gate — deny instead of end-turn

HF #2737 (1 file, +1/-1)


One-line fix, correct behavior change:

Old: { continue: false, stopReason } — ends the agent's turn. The failure text never reaches the agent as actionable feedback; the dev has to manually type "continue" to resume.

New: { hookSpecificOutput: { permissionDecision: "deny", permissionDecisionReason } } — blocks the commit (same guard) but the failure text returns to the agent as tool feedback, so it can fix the issue and retry autonomously.

The gate logic (repo detection, build/lint/typecheck steps, failure formatting) is unchanged. Only the output shape changes.

Approve. This is the correct Claude Code hook semantics for "block this action but let the agent continue working."

--- Miga

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.

4 participants