Skip to content

ai hooks write an absolute binary path into committed .claude/settings.json #1482

Description

@timvandam

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions