fix(hooks): use $CLAUDE_PROJECT_DIR for Stop-hook commands (AL-34)#20
Merged
Conversation
Both Stop-hook commands in `.claude/settings.json` referenced the
hook scripts via the relative path `.claude/hooks/<name>.sh`. The
hook runtime invokes those commands via `/bin/sh -c`, which resolves
relative paths against the session's current working directory. When
Claude Code is launched from any directory other than the project
root, the shell reports "not found" for both hooks and the Stop-hook
chain emits a non-blocking warning instead of running the reminders.
Symptom observed in a real session today (2026-05-09):
Stop hook error: Failed with non-blocking status code:
/bin/sh: 1: .claude/hooks/review-reminder.sh: not found
Stop hook error: Failed with non-blocking status code:
/bin/sh: 1: .claude/hooks/session-tracker-reminder.sh: not found
The hook scripts themselves are present in the repository on every
branch. Pure path-resolution failure.
Fix: prepend `$CLAUDE_PROJECT_DIR` to each command, with the whole
path enclosed in double quotes (escaped within the JSON string) so
project paths containing spaces don't break the shell parse. This is
the documented Claude Code hook-portability pattern.
Audit: searched the rest of the .claude tree for similar relative-path
patterns. The only `command` fields in any settings.json file are these
two hooks. Skill SKILL.md and agent definition files use Claude Code's
own loader (project-anchored), not `/bin/sh` from a CWD, so they are
not affected.
Acceptance: launching Claude Code from at least one directory above the
project root, then triggering a Stop event, shows both hook reminders
firing with their expected text and no shell-not-found errors in the
transcript.
Refs: AL-34.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4da5a5e to
51dfdfd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Both Stop-hook commands in
.claude/settings.jsonuse CWD-relative paths (.claude/hooks/<name>.sh). When the hook runtime invokes them via/bin/sh -c, the relative path resolves against the session's CWD — so launching Claude Code from anywhere other than the project root breaks both reminder hooks with "not found".Symptom (observed today)
The scripts themselves are present in the repository on every branch. Pure path-resolution failure.
Fix
Prepend
$CLAUDE_PROJECT_DIRto each command, with the whole path enclosed in escaped double-quotes inside the JSON string so project paths containing spaces don't break the shell parse. Standard Claude Code hook-portability pattern.Audit
Searched the rest of the
.claude/tree for similar relative-path patterns. The onlycommandfields in anysettings.jsonfile are these two hooks. SkillSKILL.mdand agent definition files use Claude Code's own loader (project-anchored), not/bin/shfrom a CWD, so they're not affected.Test plan
gate-1-precommit(only.claude/settings.jsonchanged; pre-commit JSON-schema check should pass)gate-2-docker × {22.04, 24.04, 26.04}(no behavioral change to installer; should pass clean)Refs: AL-34