| name | repo-local-git-hooks |
| description | Detect and repair cases where repository-local Git hooks are bypassed by a global core.hooksPath, especially on macOS machines managed by nix-darwin/home-manager that inject global gitleaks/git-hooks paths. Use when CI catches lint/format/test issues that pre-commit or pre-push should have caught, when .git/hooks exists but Git ignores it, when installing pre-commit refuses because core.hooksPath is set, or when a repo needs local pre-commit/pre-push hooks to override global hooks. |
Repo Local Git Hooks
Use this skill when a repo expects local hooks but Git is using a global core.hooksPath. The common symptom is: .git/hooks/pre-commit exists, yet commits/pushes run only a global Nix/gitleaks hook or no repo-specific lint at all.
Audit First
Run the bundled audit script from the target repo:
path/to/repo-local-git-hooks/scripts/audit_git_hooks.sh
Or inspect manually:
git config --show-origin --get-all core.hooksPath || true
git rev-parse --git-common-dir
git rev-parse --git-path hooks
Interpretation:
git rev-parse --git-path hooks must match $(git rev-parse --git-common-dir)/hooks when repo-local .git/hooks should be effective.
- If
core.hooksPath comes from ~/.config/git/config, /etc/gitconfig, or a /nix/store/...-git-hooks path, this is a global Git config override. In Eotel's setup that normally comes from nix-darwin/home-manager, not from the repo's devenv.
devenv can install tools or configure project hooks when the repo explicitly uses git-hooks.hooks, but a global core.hooksPath visible via git config --show-origin is outside the repo and can bypass .git/hooks.
Fix Pattern
Prefer the repo's own hook installer. Typical names:
just install-hooks
just pre-commit-install
The installer should be idempotent and should:
git config --local --unset-all core.hooksPath || true
GIT_CONFIG_GLOBAL=/dev/null uvx pre-commit install
GIT_CONFIG_GLOBAL=/dev/null uvx pre-commit install --hook-type pre-push
git config --local core.hooksPath "$(git rev-parse --git-common-dir)/hooks"
For prek, use the same pattern but run prek install while GIT_CONFIG_GLOBAL=/dev/null if it refuses to install with core.hooksPath set.
Agent Workflow
- Confirm the failure mode with the audit script or the manual commands above.
- Check whether the repo already has an install recipe (
just --list, rg "install-hooks|pre-commit-install").
- Patch that recipe so it writes repo-local
core.hooksPath after installing hooks.
- If the repo has a Claude/Codex session-start hook, make it verify the effective hook path, not just the existence of
.git/hooks/pre-commit.
- Run the actual hooks after the fix:
.git/hooks/pre-commit
uvx pre-commit run --hook-stage pre-push --all-files
If pre-commit is unavailable, use the repo's tool (prek, lefthook, etc.) and still verify git rev-parse --git-path hooks.
Session Hook Guard
Existence checks are insufficient. A correct guard checks both hook files and effective path:
EXPECTED_HOOKS_DIR="$(git rev-parse --git-common-dir)/hooks"
EFFECTIVE_HOOKS_DIR="$(git rev-parse --git-path hooks)"
if [ "$EFFECTIVE_HOOKS_DIR" != "$EXPECTED_HOOKS_DIR" ]; then
just install-hooks
fi
Also verify generated hook files contain the expected launcher marker, such as File generated by pre-commit, when the repo uses pre-commit.
Resource
scripts/audit_git_hooks.sh: deterministic audit/fix helper for this exact failure mode.