This document covers installation, local configuration, troubleshooting, and rollback of Lefthook git hooks.
Lefthook runs local Git validations to catch issues before they reach the remote repository:
pre-commit— Validates journal markdown structure on staged files before each commitpre-push— Runs production build to ensure deployable code before pushing to remote
All hooks can be bypassed by git when needed (see Bypassing Hooks below).
Lefthook installs automatically via pnpm's lifecycle script:
pnpm install
```text
This runs `pnpm run postinstall`, which executes `lefthook install` and
configures git hooks.
### Manual Installation
If the automatic installation doesn't create git hooks:
```bash
pnpm dlx lefthook install
```text
Verify hooks are installed:
```bash
ls -la .git/hooks/
```text
You should see `pre-commit` and `pre-push` hook files.
## Validation Behaviour
### Pre-Commit: Journal Markdown Validation
Runs when committing staged files matching `content/journal/*.md`:
```bash
pnpm run journal:validate
```text
**What it checks:**
- Markdown frontmatter validity (YAML structure)
- Required fields (title, date, author)
**How it works:**
- Scans all `.md` files in `content/journal/` regardless of which files are staged
- Automatically skipped during `git merge` or `git rebase`
**Example:**
```bash
# Valid commit — passes
git add content/journal/post.md
git commit -m "Add new post"
# ✓ Pre-commit hook runs and passes
# Invalid commit — fails
git add content/journal/broken.md # Has malformed YAML
git commit -m "Add broken post"
# ✗ Hook blocks commit, shows validation errors
```text
### Pre-Push: Production Build Verification
Runs `pnpm run build` before pushing to remote:
```bash
pnpm run build
```text
**What it checks:**
- TypeScript compilation success
- Vite bundler output
- No build errors that would break deployment
**Skip conditions:**
- Skipped during rebase or merge operations
- Can be bypassed (see below)
**Example:**
```bash
git push origin my-feature
# ✗ Build fails
# Error: TypeScript compilation error in src/app/..
# Pushing blocked
# Fix the error
git add .
git commit -m "Fix TypeScript error"
# Retry push
git push origin my-feature
# ✓ Build passes, push succeeds
```text
## Bypassing Hooks
### When It's Safe to Bypass
- **Work in progress (WIP):** saving intermediate changes before a refactor
- **CI validation:** pushing to a branch where CI runs additional checks
- **Emergency hotfixes:** urgent production fix where you're confident in the code
### How to Bypass
Use `--no-verify` with git commands:
```bash
# Skip pre-commit hook
git commit --no-verify -m "WIP: partial changes"
# Skip pre-push hook
git push --no-verify
# Skip both
git commit --no-verify -m "msg" && git push --no-verify
```text
### Recommended Practice
**Never skip hooks without explicit reason.** If you find yourself repeatedly
using `--no-verify`, the issue is usually upstream:
- **Broken build?** Fix it in your branch; do not skip the check
- **Slow validation?** Run it locally first to debug
- **False positives?** Report the issue in the repository
## Troubleshooting
### Hooks Not Running
**Problem:** You committed/pushed but hooks didn't run.
**Solutions:**
1. **Verify installation:**
```bash
npx lefthook install
```text
1. **Check hook files exist:**
```bash
ls -la .git/hooks/ | grep -E "pre-commit|pre-push"
```text
Should show executable files like:
```text
-rwxr-xr-x 1 user group lefthook
```text
1. **Check `.lefthook-local.yml` isn't disabling hooks:**
```bash
cat .lefthook-local.yml 2>/dev/null || echo "No local overrides"
```text
1. **Manually run a hook to test:**
```bash
pnpm dlx lefthook run pre-commit
```text
### "Command Not Found" Error
**Problem:** Pre-commit or pre-push fails with `pnpm: command not found` or
`tsx: command not found`.
**Solution:** Ensure dependencies are installed:
```bash
pnpm install
pnpm dlx lefthook install
```text
If still failing, try running the validation manually:
```bash
pnpm run journal:validate
pnpm run build
```text
If manual run works but hook fails, reinstall lefthook:
```bash
rm -rf .git/hooks/pre-commit .git/hooks/pre-push
pnpm dlx lefthook install
```text
### Hook Runs but Validation Passes Locally, Fails in Hook
**Problem:** `pnpm run journal:validate` passes in terminal but fails in
pre-commit hook.
**Likely cause:** Different working directory or environment.
**Solution:**
1. Check what files are actually staged:
```bash
git diff --cached --name-only
```text
1. Run validation on staged files explicitly:
```bash
pnpm run journal:validate -- content/journal/specific-file.md
```text
1. Clear pnpm cache:
```bash
pnpm store prune
pnpm install
pnpm dlx lefthook install
```text
### Build Hook Slow or Timing Out
**Problem:** Pre-push build takes >30s or times out.
**Solution:**
1. Run build locally to benchmark:
```bash
time pnpm run build
```text
1. If consistently slow, consider using `--no-verify` for feature branches and relying on CI for final validation
1. Repo has no caching; build performs from scratch each push. This is intentional—it guarantees reproducibility.
## Rollback: Removing Lefthook
If Lefthook causes persistent issues and needs to be removed:
### 1. Uninstall Git Hooks
```bash
pnpm dlx lefthook uninstall
```text
### 2. Remove from Dependencies
```bash
pnpm remove lefthook
```text
### 3. Remove Configuration Files
```bash
rm -f lefthook.yml .lefthook-local.yml
```text
### 4. Restore Package.json
Remove the `postinstall` script from `package.json`:
```bash
pnpm run postinstall # command will no longer exist
```text
Edit `package.json` manually to remove the `postinstall` line if needed.
### 5. Verify Removal
```bash
pnpm dlx lefthook version # should fail (command not found)
ls -la .git/hooks/ | grep -c lefthook # should return 0
```text
## Configuration: Project vs Local Overrides
### Project Configuration (`lefthook.yml`)
Checked into Git, applies to all developers:
- Defines pre-commit and pre-push stages
- Specifies which commands run
- All team members use the same validation
### Local Overrides (`.lefthook-local.yml`)
**Not** checked into Git, per-developer:
```yaml
# .lefthook-local.yml (create manually if needed)
pre-commit:
skip: true # Disable pre-commit for this machine
pre-push:
commands:
build:
skip: true # Disable build check for this machine
```text
Use local overrides only when you have a specific reason (e.g., different system
setup).
## Viewing Hook Logs
Lefthook stores recent run logs in `.lefthook/`:
```bash
ls -la .lefthook/
cat .lefthook/lefthook.log | tail -50 # Last 50 lines
```text
View what hooks ran on your last commit/push:
```bash
grep -E "pre-commit|pre-push" .lefthook/lefthook.log | tail -20
```text
## Rapid Iteration (Development Mode)
When doing rapid development and frequent commits, you may want to skip hook
validation:
### Option 1: Skip Hooks Per Commit (Recommended)
Use `--no-verify` for individual commits:
```bash
# Make changes and commit without validation
git add .
git commit --no-verify -m "WIP: feature work"
# When ready, commit normally to re-enable validation
git add .
git commit -m "Feature complete"
# ✓ Hooks run and validate
```text
### Option 2: Disable Hooks Temporarily (Local Only)
Create `.lefthook-local.yml` in the repo root (never commit this):
```yaml
# .lefthook-local.yml (local machine only, .gitignore'd)
pre-commit:
skip: true
pre-push:
skip: true
```text
Re-enable by deleting the file:
```bash
rm .lefthook-local.yml
```text
### Option 3: Run Validation Manually
Skip hook-based validation and run checks when you choose:
```bash
# Commit without validation
git commit --no-verify -m "Work in progress"
# Run validation on demand
pnpm run journal:validate
pnpm run build
# When all pass, push
git push
```text
**Note:** Skipping hooks is safe only when you run equivalent validation before
pushing to `develop` or `main`.
## Performance Notes
- **Pre-commit:** Runs only on changed `.md` files—typically < 500ms
- **Pre-push:** Runs full `npm run build`—typically 10-20s depending on machine
- Both hooks can be skipped with `--no-verify` if needed for rapid iteration
## Further Reading
- **Lefthook docs:** https://lefthook.dev/
- **Project guidelines:** [guidelines/Guidelines.md](../guidelines/Guidelines.md)
- **Build script:** See `pnpm run build` in `package.json`
- **Validation script:** See `pnpm run journal:validate` in `package.json`