Description
With ai.claude configured, lefthook install writes an absolute path to the lefthook binary into .claude/settings.json:
"command": "/Users/me/project/node_modules/.pnpm/lefthook-darwin-arm64@2.1.10/node_modules/lefthook-darwin-arm64/bin/lefthook run validate"
.claude/settings.json is normally committed and shared with the team. That path contains the home directory, the OS and arch (darwin-arm64), the lefthook version, and if you use git worktrees, the worktree it was generated in. So the generated config only works for the person who ran install. It also breaks on Linux CI, and after any lefthook upgrade.
#1433, which specified this feature, shows the intended output as:
"command": "lefthook run validate"
Two smaller things in the same output. The generated entries have no matcher, so a PostToolUse mapping runs on every tool call instead of only on file edits. And there is no way to set a timeout; Claude Code defaults to 60 seconds, which a full typecheck plus test run exceeds.
Related: #1398 reports the same problem in the .git/hooks shim.
lefthook.yml
ai:
claude:
Stop: validate
validate:
jobs:
- run: echo hi
Commands to reproduce
export LEFTHOOK_VERBOSE=true
mkdir repro && cd repro && git init
npm install lefthook
# add the lefthook.yml above
npx lefthook install
cat .claude/settings.json
Lefthook version
2.1.10 8d9cfec5f52367af6374a5430b4e9568844856e5
Installed via pnpm (lefthook-darwin-arm64@2.1.10), macOS arm64.
Possible solution
Resolve the binary at runtime instead of baking in the path, the way the git hook template already does with its call_lefthook function. For npm and pnpm installs, npx lefthook run <hook> or pnpm exec lefthook run <hook> is portable on its own.
Alternatively, an option to write .claude/settings.local.json instead. Claude Code reads that file and it is gitignored by convention, so a machine specific path in it does no harm.
ai:
claude:
local: true # write .claude/settings.local.json
Stop: validate
Description
With
ai.claudeconfigured,lefthook installwrites an absolute path to the lefthook binary into.claude/settings.json:.claude/settings.jsonis normally committed and shared with the team. That path contains the home directory, the OS and arch (darwin-arm64), the lefthook version, and if you use git worktrees, the worktree it was generated in. So the generated config only works for the person who ran install. It also breaks on Linux CI, and after any lefthook upgrade.#1433, which specified this feature, shows the intended output as:
Two smaller things in the same output. The generated entries have no
matcher, so aPostToolUsemapping runs on every tool call instead of only on file edits. And there is no way to set atimeout; Claude Code defaults to 60 seconds, which a full typecheck plus test run exceeds.Related: #1398 reports the same problem in the
.git/hooksshim.lefthook.ymlCommands to reproduce
Lefthook version
Installed via pnpm (
lefthook-darwin-arm64@2.1.10), macOS arm64.Possible solution
Resolve the binary at runtime instead of baking in the path, the way the git hook template already does with its
call_lefthookfunction. For npm and pnpm installs,npx lefthook run <hook>orpnpm exec lefthook run <hook>is portable on its own.Alternatively, an option to write
.claude/settings.local.jsoninstead. Claude Code reads that file and it is gitignored by convention, so a machine specific path in it does no harm.