Automatic Setup
Pre-commit hooks are configured indevenv.nix and installed automatically when you enter the devenv shell:
pre-commit install needed. Devenv manages the git hooks lifecycle.
Configured Hooks
treefmt
Purpose: Multi-language formatter for Nix, Go, and TypeScript Configuration:- Nix - nixfmt or nixpkgs-fmt (configured in treefmt-programs.nix)
- Go - gofmt (via golangci-lint)
- TypeScript - Biome formatter
golangci-lint
Purpose: Go code linting and static analysis Configuration:.go files except generated code in services/gen/go/
Runs: Full golangci-lint run in the services/ directory
Checks include:
- Dead code detection
- Code complexity
- Error handling patterns
- Style violations
- Security issues
goimports
Purpose: Go import statement organization and formatting Configuration:.go files except generated code
Actions:
- Adds missing imports
- Removes unused imports
- Organizes imports into groups (stdlib, third-party, local)
- Formats code with gofmt
-l- List files with incorrect formatting-w- Write changes back to files
biome (Frontend)
Purpose: TypeScript and React linting/formatting Configuration:.ts and .tsx files in the frontend
Checks:
- TypeScript linting rules
- React best practices
- Code formatting (Prettier-compatible)
- Import sorting
- 20-30x faster than ESLint + Prettier
- Single tool for linting and formatting
- Automatic fixes for many issues
go test
Purpose: Run Go unit tests before committing Configuration:.go files except generated code
Runs: Complete test suite with go test ./...
Prevents:
- Committing code that breaks existing tests
- Regression bugs
- Incomplete implementations
Hook Execution Flow
When you rungit commit, hooks execute in this order:
- treefmt - Format all modified files
- goimports - Organize Go imports (runs even if treefmt fails)
- golangci-lint - Lint Go code
- biome - Lint TypeScript/React
- go test - Run Go unit tests
Hook Behavior
pass_filenames: false
All hooks usepass_filenames = false, meaning they run on the entire codebase (within their directory), not just staged files.
Why: Go and TypeScript projects have complex dependencies. Checking only staged files could miss:
- Import changes affecting other files
- Interface changes breaking implementations
- Test failures in dependent packages
Excluding Generated Code
Generated code directories are excluded:services/gen/go/- Protobuf-generated Go code (buf generate)frontend/src/gen/- Protobuf-generated TypeScript (buf generate)
Bypassing Hooks (Not Recommended)
In rare cases (emergency hotfix, hook bugs), you can skip hooks:Hook Failure Troubleshooting
treefmt Failures
golangci-lint Failures
- Unused variables: Remove them or prefix with
_ - Unchecked errors: Add proper error handling
- Code complexity: Refactor long functions
goimports Failures
Rare - goimports usually succeeds or auto-fixes. If it fails:- Syntax errors in Go files
- Invalid import paths
biome Failures
go test Failures
Manual Hook Testing
Test hooks without committing:pre-commit command may not be available since devenv manages hooks directly. Use the manual commands for each tool instead.
Devenv Scripts vs Hooks
Devenv provides convenience scripts that run similar checks:| Script | Equivalent Hooks | Usage |
|---|---|---|
fmt | treefmt + goimports | Format all code and stage changes |
lint | golangci-lint + biome | Lint all code (no auto-fix) |
Hook Performance
Typical hook execution times:| Hook | Time (small change) | Time (large change) |
|---|---|---|
| treefmt | 1-2s | 3-5s |
| goimports | 1-2s | 2-4s |
| golangci-lint | 5-10s | 15-30s |
| biome | 0.5-1s | 1-2s |
| go test | 3-10s | 10-30s |
Relationship to CI
Pre-commit hooks run the same checks as CI:| Hook | CI Job | Purpose |
|---|---|---|
| golangci-lint | go-lint | Go linting |
| go test | go-test | Go unit tests |
| biome | frontend-lint + node-lint | TypeScript linting |
buf lintandbuf breaking- Proto validationnpm run build- TypeScript compilation and Vite buildnix build- Reproducible binary builds
Customizing Hooks
Hooks are configured indevenv.nix under the git-hooks.hooks section. To modify:
- Edit
devenv.nix - Exit and re-enter the devenv shell:
- Hooks are automatically reinstalled
Best Practices
- Run
fmtbefore committing - Catches formatting issues instantly - Commit frequently - Smaller commits = faster hook execution
- Don’t bypass hooks - They save time by catching issues early
- Fix hook failures immediately - Don’t accumulate issues
- Keep generated code out of PRs - Run
buf generatelocally, hooks ignore it
Related Documentation
- GitHub Actions CI/CD - CI pipeline reference
- Commands Reference - All devenv commands
- Environment Setup - Setting up devenv