Pre-commit Usage Guide
February 1, 2026 · View on GitHub
Overview
This project uses pre-commit to automatically run code checks and formatting before Git commits, ensuring code quality and style consistency.
Pre-commit will automatically check and fix the following issues on each git commit:
- YAML file syntax checking
- TOML file syntax checking
- JSON file syntax checking
- End-of-file newline fixing
- Trailing whitespace removal
- Python code linting (ruff)
- Python code formatting (ruff-format)
- Frontend code checking (Biome)
- Frontend TypeScript type checking
- Frontend code line count check (max 500 lines of effective code per file)
- Backend code line count check (max 500 lines of effective code per file)
Installation & Configuration
1. Install pre-commit Dependencies
Using uv (Recommended)
# Sync pre-commit dependencies from pyproject.toml
uv sync --group dev
2. Configure Git Hooks (Repo-Local)
This repo uses a shared .githooks/ directory (repo-local) instead of pre-commit install.
Run the setup script once per clone/worktree to set core.hooksPath:
# macOS/Linux
bash scripts/setup_hooks_here.sh
# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -File scripts/setup_hooks_here.ps1
Note: After core.hooksPath is set, pre-commit install will refuse to run. This is expected.
3. (Optional) Warm Up Hooks
pre-commit run --all-files
Repo Hooks (Post-checkout)
This repo also ships a post-checkout hook under .githooks/ to keep worktree
dependencies linked. It runs:
scripts/link_worktree_deps_here.sh(preferred)- falls back to
scripts/link_worktree_deps_here.ps1if needed
The hook is safe to run repeatedly and will skip existing links unless --force is used.
Usage
Automatic Trigger (Recommended)
Pre-commit will automatically run on each commit:
git add .
git commit -m "your commit message"
If checks pass, the commit succeeds; if checks fail, the commit is blocked and you need to fix the issues and commit again.
Note: The repo hook prefers
pre-commitif available, and falls back touv run pre-commitwhenuvis installed.
Example Output:
check-yaml........................................................Passed
check-toml........................................................Passed
check-json........................................................Passed
end-of-file-fixer................................................Passed
trailing-whitespace..............................................Passed
ruff.............................................................Passed
ruff-format......................................................Passed
biome-check......................................................Passed
[main abc123] your commit message
1 file changed, 3 insertions(+)
Manual Execution
Run All Checks
pre-commit run --all-files
Run Specific Checks
# Check specific files only
pre-commit run --files path/to/file.py
# Run ruff check only
pre-commit run ruff --all-files
# Run ruff format only
pre-commit run ruff-format --all-files
# Run Biome check only
pre-commit run biome-check --all-files
# Run frontend code line count check only
pre-commit run check-frontend-code-lines --all-files
# Run backend code line count check only
pre-commit run check-backend-code-lines --all-files
View Detailed Output
pre-commit run --all-files -v
Common Scenarios
Scenario 1: Code Line Count Exceeds Limit
If you see an error like this when committing:
Check frontend TS/TSX code lines (max 500)............................Failed
❌ The following files exceed 500 lines:
apps/chat/components/ChatPanel.tsx -> 623 lines
Solution:
- Split the oversized file into smaller modules/components
- Extract common logic into separate utility files
- Consider if there's duplicate code that can be abstracted
Note: Line count statistics exclude empty lines and comment lines, counting only effective code lines.
Scenario 2: Check Failed on Commit
If you see an error like this when committing:
Trailing whitespace..............................................Failed
- hook id: trailing-whitespace
- args: [--markdown-linebreak-ext=md]
Some files have trailing whitespace, please remove them.
Solution:
-
Fix and re-add files:
git add path/to/file.py -
Commit again:
git commit -m "your message"
Scenario 3: Skip Checks (Emergency)
Not recommended, use only in emergencies:
git commit -m "emergency fix" --no-verify
Configuration
The .pre-commit-config.yaml file in the project root contains all check configurations:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-yaml
exclude: pnpm-lock.yaml
- id: check-toml
- id: check-json
- id: end-of-file-fixer
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.10
hooks:
# Run the linter.
- id: ruff
language_version: python3.12
files: ^lifetrace/
types_or: [ python, pyi ]
args: [ --fix ]
# Run the formatter.
- id: ruff-format
language_version: python3.12
files: ^lifetrace/
types_or: [ python, pyi ]
# Biome for frontend (JavaScript/TypeScript)
- repo: https://github.com/biomejs/pre-commit
rev: "v0.6.1"
hooks:
- id: biome-check
additional_dependencies: ["@biomejs/biome@2.3.13"]
files: ^(free-todo-frontend/)
# Local hooks
- repo: local
hooks:
# TypeScript type checking
- id: tsc-free-todo-frontend
name: TypeScript type check (free-todo-frontend)
entry: bash -c 'cd free-todo-frontend && pnpm run type-check'
language: system
files: ^free-todo-frontend/.*\.(ts|tsx)$
pass_filenames: false
# Frontend code line count check (max 500 lines of effective code)
- id: check-frontend-code-lines
name: Check frontend TS/TSX code lines (max 500)
entry: node free-todo-frontend/scripts/check_code_lines.js --include apps,components,electron,lib --exclude lib/generated
language: system
files: ^free-todo-frontend/.*\.(ts|tsx)$
pass_filenames: true
# Backend code line count check (max 500 lines of effective code)
- id: check-backend-code-lines
name: Check backend Python code lines (max 500)
entry: uv run python lifetrace/scripts/check_code_lines.py --include lifetrace --exclude lifetrace/__pycache__,lifetrace/dist,lifetrace/migrations/versions
language: system
files: ^lifetrace/.*\.py$
pass_filenames: true
Key Configuration:
files: ^lifetrace/- Only check Python files in thelifetrace/directoryfiles: ^free-todo-frontend/- Only check frontend files in thefree-todo-frontend/directorylanguage_version: python3.12- Specify Python versionargs: [ --fix ]- Automatically fix fixable issuesadditional_dependencies- Specify dependency version for Biomepass_filenames: true/false- Whether to pass the list of staged files to the scripttrue: Script only checks passed files (code line count check uses this mode, only checking staged files)false: Script determines its own check scope (TypeScript type check uses this mode, needs to check the entire project)
Troubleshooting
Issue: pre-commit: command not found
Cause: Virtual environment not activated or pre-commit not installed
Solution:
# Activate virtual environment
source .venv/bin/activate
# Using uv run
uv run pre-commit --version
Issue: Checks not triggered on commit
Cause: Hooks not configured or .githooks missing
Solution:
# Ensure hooksPath is set
git config --get core.hooksPath
# Re-run repo hook setup (in repo root)
bash scripts/setup_hooks_here.sh
# or
powershell -ExecutionPolicy Bypass -File scripts/setup_hooks_here.ps1
Issue: pre-commit install fails with core.hooksPath
Cause: This repo uses .githooks/ via core.hooksPath, so pre-commit install will refuse.
Solution:
# Do not run pre-commit install. Use:
pre-commit run --all-files
Issue: Checks are too slow
Optimization Methods:
-
Only check changed files:
pre-commit run -
Use parallel execution:
pre-commit run --all-files --jobs 4
Best Practices
-
✅ Run checks before each commit
pre-commit run --all-files -
✅ Update check tools regularly
pre-commit autoupdate -
✅ Ensure all team members have hooks installed when collaborating
git clone <repo> cd <repo> uv sync --group dev bash scripts/setup_hooks_here.sh # or: powershell -ExecutionPolicy Bypass -File scripts/setup_hooks_here.ps1 pre-commit run --all-files -
✅ Don't use
--no-verifyunless it's an emergency -
✅ Maintain consistent Python code style
Code Line Count Check Rules
Rule Description
To maintain code readability and maintainability, the project limits the effective code lines per file:
- Frontend (TS/TSX): Max 500 lines of effective code per file
- Backend (Python): Max 500 lines of effective code per file
Counting Rules
Line count statistics exclude the following:
- Empty lines (lines that are empty strings after
trim()/strip()) - Comment lines:
- Frontend: Lines starting with
//,/*,*,*/ - Backend: Lines starting with
#
- Frontend: Lines starting with
Check Scope
Frontend Check Directories (adjustable via parameters):
- Include:
apps/,components/,electron/,lib/ - Exclude:
lib/generated/(Orval auto-generated API code)
Backend Check Directories (adjustable via parameters):
- Include:
lifetrace/ - Exclude:
lifetrace/__pycache__/,lifetrace/dist/,lifetrace/migrations/versions/
Manual Check Execution
The script supports two execution modes:
Mode 1: Scan Entire Directory (Standalone Execution)
# Check all frontend TS/TSX files
node free-todo-frontend/scripts/check_code_lines.js
# Check all backend Python files
uv run python lifetrace/scripts/check_code_lines.py
# Use custom parameters
node free-todo-frontend/scripts/check_code_lines.js --include apps,components,electron --exclude lib/generated --max 600
uv run python lifetrace/scripts/check_code_lines.py --include lifetrace --exclude lifetrace/__pycache__ --max 600
Mode 2: Check Specific Files (Pre-commit Mode)
# Check only specified files
node free-todo-frontend/scripts/check_code_lines.js apps/chat/ChatPanel.tsx apps/todo/TodoList.tsx
uv run python lifetrace/scripts/check_code_lines.py lifetrace/routers/chat.py lifetrace/services/todo.py
Note: During
git commit, pre-commit automatically passes staged files, checking only these files instead of the entire directory.
Solutions for Exceeding Limits
When a file's code line count exceeds the limit, consider:
- Split Files: Split large files into multiple smaller files by functional modules
- Extract Common Logic: Abstract duplicate code into independent utility functions/components
- Use Composition Pattern: Split complex components into multiple sub-components
- Evaluate Comment Volume: Add appropriate comments (not counted in lines) to explain complex logic
Resources
FAQ
Q: Will Pre-commit modify my code? A: Yes! Ruff will automatically fix fixable issues such as unnecessary imports, unused variables, etc. Review your changes and commit again.
Q: Can I use different pre-commit configurations on different branches?
A: Yes! .pre-commit-config.yaml can be adjusted per branch.
Q: What programming languages does Pre-commit support? A: This project configuration supports Python (via Ruff) and JavaScript/TypeScript (via Biome). The Pre-commit framework itself supports multiple languages, including Go, Rust, etc.
Q: How do I add custom checks?
A: Modify the .pre-commit-config.yaml file and add new repositories or hooks.
Q: Can the code line count check threshold be adjusted?
A: Yes! Modify the entry parameter of the corresponding hook in .pre-commit-config.yaml and add --max <number>. For example: --max 600 adjusts the limit to 600 lines.
Q: Why are certain directories not checked?
A: To avoid checking auto-generated code (such as Orval-generated API code), some directories are excluded from the check scope. You can adjust the exclusion list via the --exclude parameter.
Contact
If you encounter issues or need help, please:
- Check the troubleshooting section of this guide
- Run
pre-commit run --all-files -vto view detailed errors - Check project Issues or submit a new Issue
Happy Coding! 🎉