precommit-setup
Configures pre-commit hooks for linting, type checking, formatting, and testing. Use when setting up a new project or adding quality gates to an existing one.
Install
npx skills add https://github.com/athola/claude-night-market/tree/master/plugins/attune/skills/precommit-setup
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install athola-claude-night-market@llmmart
git clone https://github.com/athola/claude-night-market.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole athola/claude-night-market collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Pre-commit Setup Skill
Configure a three-layer pre-commit quality system that enforces linting, type checking, and testing before every commit.
When To Use
- Setting up a new project with code-quality enforcement
- Adding pre-commit hooks to an existing project
- Upgrading from basic linting to a full quality system
- Setting up monorepo or plugin architecture with per-component quality checks
- Updating pre-commit hook versions
When NOT To Use
- Pre-commit hooks already configured and working optimally
- Project does not use git version control
- Team explicitly avoids pre-commit hooks for workflow reasons
Philosophy: Three-Layer Defense
The system is organised in three layers, each with a different cost / coverage tradeoff:
- Layer 1: Standard hooks: fast global checks (50-200ms total). Lints and type-checks every staged file.
- Layer 2: Component-specific checks: per-component lint, typecheck, and test (10-30s total). Only the components touched by the staged files are run.
- Layer 3: Validation hooks: project-specific structure and pattern checks (varies). Catches violations that generic linters miss.
This layering keeps the fast feedback loop fast while still catching the slow / project-specific bugs before they land.
Module Loading
The detailed configuration patterns are in modules; load only the ones you need:
modules/standard-hooks.md: Layer 1 patterns for Python, Rust, and TypeScript (load when configuring base linters).modules/component-level-hooks.md: Layer 2 monorepo scripts and pre-commit wiring (load when project has multiple components / plugins).modules/validation-hooks.md: Layer 3 custom hooks and SKIP patterns (load when enforcing project conventions beyond linting).modules/ci-integration.md: GitHub Actions workflow plus a complete.pre-commit-config.yamlexample (load when wiring CI to mirror local checks).modules/troubleshooting.md: timing tables, cache clearing, hook-failure recovery (load when hooks are slow or failing).
Workflow
1. Create Configuration Files
```bash
Create .pre-commit-config.yaml
python3 plugins/attune/scripts/attune_init.py \ --lang python \ --name my-project \ --path .
Create quality check scripts (for monorepos)
mkdir -p scripts chmod +x scripts/run-component-*.sh ```
2. Configure Python Type Checking
Create pyproject.toml with strict type checking:
```toml [tool.mypy] python_version = "3.12" warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true strict = true
Per-component configuration
[[tool.mypy.overrides]] module = "plugins.*" strict = true ```
3. Configure Testing
```toml [tool.pytest.ini_options] testpaths = ["tests"] pythonpath = ["src"] addopts = [ "-v", # Verbose output "--strict-markers", # Strict marker enforcement "--cov=src", # Coverage for src/ "--cov-report=term", # Terminal coverage report ]
markers = [ "slow: marks tests as slow (deselect with '-m \"not slow\"')", "integration: marks tests as integration tests", ] ```
4. Install and Test Hooks
```bash
Install pre-commit tool
uv sync --extra dev
Install git hooks
uv run pre-commit install
Test on all files (first time)
uv run pre-commit run --all-files
Normal usage - test on staged files
git add . git commit -m "feat: add feature"
Hooks run automatically
```
5. Create Manual Quality Scripts
For full quality checks (CI/CD, monthly audits):
```bash #!/bin/bash
scripts/check-all-quality.sh: full quality check for all components
set -e
echo "=== Running Full Quality Checks ==="
./scripts/run-component-lint.sh --all ./scripts/run-component-typecheck.sh --all ./scripts/run-component-tests.sh --all
echo "=== All Quality Checks Passed ===" ```
Hook Execution Order
Pre-commit hooks run in this fixed order; all must pass for the commit to succeed:
- File validation (whitespace, EOF, YAML/TOML/JSON syntax)
- Security scanning (bandit)
- Global linting (ruff, all files)
- Global type checking (mypy, all files)
- Component linting (changed components only)
- Component type checking (changed components only)
- Component tests (changed components only)
- Custom validation (structure, patterns, etc.)
Best Practices
For New Projects
Start with strict settings from the beginning: they are
easier to maintain over time. Configure type checking with
strict = true in pyproject.toml, set up testing early
(include pytest in pre-commit), and document the reason
whenever you must skip a hook.
For Existing Projects
Use a gradual adoption strategy. Start with global checks
(Layer 1), then add component-specific checks (Layer 2)
once legacy issues are resolved. Use --no-verify only for
true emergencies and document why.
For Monorepos and Plugin Architectures
Standardize per-component Makefiles for lint, typecheck,
and test targets. Centralize common settings in a root
pyproject.toml while allowing per-component overrides.
Automate change detection so commits stay fast, and use
progressive disclosure (summary first, detail on failure).
Related Skills
Skill(attune:project-init): Full project initializationSkill(attune:workflow-setup): GitHub Actions setupSkill(attune:makefile-generation): Generate component MakefilesSkill(pensive:shell-review): Audit shell scripts for exit-code and safety issues
See Also
- Quality Gates: three-layer validation: pre-commit hooks (formatting, linting), CI checks (tests, coverage), and PR review gates (code quality, security).
Exit Criteria
-
.pre-commit-config.yamlexists at the project root with hooks covering at minimum Layer 1 (whitespace, YAML/TOML/JSON syntax, global linting). -
uv run pre-commit run --all-filesexits 0 after the configuration is installed, confirming all hooks pass on the current codebase state. -
git commitwith a staged change triggers the pre-commit hooks automatically (verified byuv run pre-commit installexit code 0 and presence of.git/hooks/pre-commit). - Any
--no-verifybypass is absent from the project's documented workflows; if one is found in existing scripts, it is flagged as a violation rather than silently accepted.
Files (claude-night-market)
-
modules
-
ci-integration.md 2.7 KB
--- name: ci-integration description: GitHub Actions and GitLab CI workflow patterns mirroring local pre-commit checks. parent: precommit-setup load_when: configuring CI to run the same checks as pre-commit --- # CI Integration Verify CI runs the same thorough checks that pre-commit runs locally. Drift between local hooks and CI is the most common cause of "works on my machine" PRs. ## GitHub Actions \`\`\`yaml # .github/workflows/quality.yml name: Code Quality on: [push, pull_request] jobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install uv run: pip install uv - name: Install dependencies run: uv sync - name: Run Comprehensive Quality Checks run: ./scripts/check-all-quality.sh - name: Upload Coverage uses: codecov/codecov-action@v4 with: files: ./coverage.xml \`\`\` ## Complete Example: Python Monorepo \`\`\`yaml # .pre-commit-config.yaml repos: # Layer 1: Fast Global Checks - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-toml - id: check-json - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.14.2 hooks: - id: ruff args: [--fix] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.13.0 hooks: - id: mypy args: [--ignore-missing-imports] - repo: https://github.com/PyCQA/bandit rev: 1.8.3 hooks: - id: bandit args: [-c, pyproject.toml] # Layer 2: Component-Specific Checks - repo: local hooks: - id: run-component-lint name: Lint Changed Components entry: ./scripts/run-component-lint.sh language: system pass_filenames: false files: ^plugins/.*\\.py\$ - id: run-component-typecheck name: Type Check Changed Components entry: ./scripts/run-component-typecheck.sh language: system pass_filenames: false files: ^plugins/.*\\.py\$ - id: run-component-tests name: Test Changed Components entry: ./scripts/run-component-tests.sh language: system pass_filenames: false files: ^plugins/.*\\.(py|md)\$ # Layer 3: Validation Hooks - repo: local hooks: - id: validate-plugin-structure name: Validate Plugin Structure entry: python3 scripts/validate_plugins.py language: system pass_filenames: false files: ^plugins/.*\$ \`\`\` -
component-level-hooks.md 4.9 KB
--- name: component-level-hooks description: Layer 2 per-component pre-commit checks for monorepos and plugin architectures. parent: precommit-setup load_when: project has multiple components or plugins --- # Component-Specific Checks (Layer 2) For monorepos, plugin architectures, or projects with multiple components, add per-component quality checks. Each script detects changed components from staged files and runs lint / typecheck / test only against the affected components. ## Python Monorepo or Plugin Architecture Create three quality-check scripts under `scripts/`. All three share the same change-detection pattern. ### 1. Lint Changed Components (`scripts/run-component-lint.sh`) \`\`\`bash #!/bin/bash # Lint only changed components based on staged files set -euo pipefail # Detect changed components from staged files CHANGED_COMPONENTS=\$(git diff --cached --name-only | grep -E '^(plugins|components)/' | cut -d/ -f2 | sort -u) || true if [ -z "\$CHANGED_COMPONENTS" ]; then echo "No components changed" exit 0 fi echo "Linting changed components: \$CHANGED_COMPONENTS" FAILED=() for component in \$CHANGED_COMPONENTS; do if [ -d "plugins/\$component" ]; then echo "Linting \$component..." # Capture exit code to properly propagate failures local exit_code=0 if [ -f "plugins/\$component/Makefile" ] && grep -q "^lint:" "plugins/\$component/Makefile"; then (cd "plugins/\$component" && make lint) || exit_code=\$? else (cd "plugins/\$component" && uv run ruff check .) || exit_code=\$? fi if [ "\$exit_code" -ne 0 ]; then FAILED+=("\$component") fi fi done if [ \${#FAILED[@]} -gt 0 ]; then echo "Lint failed for: \${FAILED[*]}" exit 1 fi \`\`\` ### 2. Type Check Changed Components (`scripts/run-component-typecheck.sh`) \`\`\`bash #!/bin/bash # Type check only changed components set -euo pipefail CHANGED_COMPONENTS=\$(git diff --cached --name-only | grep -E '^(plugins|components)/' | cut -d/ -f2 | sort -u) || true if [ -z "\$CHANGED_COMPONENTS" ]; then exit 0 fi echo "Type checking changed components: \$CHANGED_COMPONENTS" FAILED=() for component in \$CHANGED_COMPONENTS; do if [ -d "plugins/\$component" ]; then echo "Type checking \$component..." # Capture output and exit code separately to properly propagate failures local output local exit_code=0 if [ -f "plugins/\$component/Makefile" ] && grep -q "^typecheck:" "plugins/\$component/Makefile"; then output=\$(cd "plugins/\$component" && make typecheck 2>&1) || exit_code=\$? else output=\$(cd "plugins/\$component" && uv run mypy src/ 2>&1) || exit_code=\$? fi # Display output (filter make noise) echo "\$output" | grep -v "^make\[" || true if [ "\$exit_code" -ne 0 ]; then FAILED+=("\$component") fi fi done if [ \${#FAILED[@]} -gt 0 ]; then echo "Type check failed for: \${FAILED[*]}" exit 1 fi \`\`\` ### 3. Test Changed Components (`scripts/run-component-tests.sh`) \`\`\`bash #!/bin/bash # Test only changed components set -euo pipefail CHANGED_COMPONENTS=\$(git diff --cached --name-only | grep -E '^(plugins|components)/' | cut -d/ -f2 | sort -u) || true if [ -z "\$CHANGED_COMPONENTS" ]; then exit 0 fi echo "Testing changed components: \$CHANGED_COMPONENTS" FAILED=() for component in \$CHANGED_COMPONENTS; do if [ -d "plugins/\$component" ]; then echo "Testing \$component..." # Capture exit code to properly propagate failures local exit_code=0 if [ -f "plugins/\$component/Makefile" ] && grep -q "^test:" "plugins/\$component/Makefile"; then (cd "plugins/\$component" && make test) || exit_code=\$? else (cd "plugins/\$component" && uv run pytest tests/) || exit_code=\$? fi if [ "\$exit_code" -ne 0 ]; then FAILED+=("\$component") fi fi done if [ \${#FAILED[@]} -gt 0 ]; then echo "Tests failed for: \${FAILED[*]}" exit 1 fi \`\`\` ## Add to Pre-commit Configuration \`\`\`yaml # .pre-commit-config.yaml (continued) # Layer 2: Component-Specific Quality Checks - repo: local hooks: - id: run-component-lint name: Lint Changed Components entry: ./scripts/run-component-lint.sh language: system pass_filenames: false files: ^(plugins|components)/.*\\.py\$ - id: run-component-typecheck name: Type Check Changed Components entry: ./scripts/run-component-typecheck.sh language: system pass_filenames: false files: ^(plugins|components)/.*\\.py\$ - id: run-component-tests name: Test Changed Components entry: ./scripts/run-component-tests.sh language: system pass_filenames: false files: ^(plugins|components)/.*\\.(py|md)\$ \`\`\` -
standard-hooks.md 1.5 KB
--- name: standard-hooks description: Layer 1 fast global pre-commit checks for Python, Rust, and TypeScript projects. parent: precommit-setup load_when: configuring base linters --- # Standard Hooks (Layer 1) Fast global checks that run on every commit (typically 50-200ms total). ## Python Projects ### Basic Quality Checks 1. **pre-commit-hooks**: file validation (trailing whitespace, EOF, YAML/TOML/JSON syntax) 2. **ruff**: ultra-fast linting and formatting (~50ms) 3. **ruff-format**: code formatting 4. **mypy**: static type checking (~200ms) 5. **bandit**: security scanning ### Configuration \`\`\`yaml # .pre-commit-config.yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-toml - id: check-json - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.14.2 hooks: - id: ruff args: [--fix] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.13.0 hooks: - id: mypy args: [--ignore-missing-imports] - repo: https://github.com/PyCQA/bandit rev: 1.8.3 hooks: - id: bandit args: [-c, pyproject.toml] \`\`\` ## Rust Projects 1. **rustfmt**: code formatting 2. **clippy**: linting 3. **cargo-check**: compilation check ## TypeScript Projects 1. **eslint**: linting 2. **prettier**: code formatting 3. **tsc**: type checking -
troubleshooting.md 2.7 KB
--- name: troubleshooting description: Performance tuning and failure-recovery patterns for slow or broken pre-commit hooks. parent: precommit-setup load_when: hooks are slow or failing --- # Performance and Troubleshooting ## Typical Timings | Check | Single Component | Multiple Components | All Components | |-------|------------------|---------------------|----------------| | Global Ruff | ~50ms | ~200ms | ~500ms | | Global Mypy | ~200ms | ~500ms | ~1s | | Component Lint | ~2-5s | ~4-10s | ~30-60s | | Component Typecheck | ~3-8s | ~6-16s | ~60-120s | | Component Tests | ~5-15s | ~10-30s | ~120-180s | | **Total** | **~10-30s** | **~20-60s** | **~2-5min** | ## Optimization Strategies 1. **Only test changed components**: default behavior in the Layer 2 scripts. 2. **Parallel execution**: pre-commit runs hooks concurrently when possible. 3. **Caching**: dependencies cached by uv; mypy uses `.mypy_cache/`. 4. **Incremental mypy**: enable `--incremental` for repeat commits in the same session. ## Hooks Too Slow Only changed components are checked by default. For even faster commits during active development: \`\`\`bash # Skip tests during development SKIP=run-component-tests git commit -m "WIP: feature development" # Run tests manually when ready ./scripts/run-component-tests.sh --changed \`\`\` ## Cache Issues \`\`\`bash # Clear pre-commit cache uv run pre-commit clean # Clear component caches find . -name "__pycache__" -type d -exec rm -rf {} + find . -name ".pytest_cache" -type d -exec rm -rf {} + find . -name ".mypy_cache" -type d -exec rm -rf {} + \`\`\` ## Hook Failures \`\`\`bash # See detailed output uv run pre-commit run --verbose --all-files # Run specific component checks manually cd plugins/my-component make lint make typecheck make test \`\`\` ## Import Errors in Tests \`\`\`toml # Ensure PYTHONPATH is set in pyproject.toml [tool.pytest.ini_options] pythonpath = ["src"] \`\`\` ## Type Checking Errors **Fix the implementation first.** A typecheck error almost always points at a real bug: a value that might be `None`, a return type that doesn't match, a function that lies about its signature. Loosening the typechecker hides the bug; it does not solve it. Only reach for per-module overrides as a last resort, after confirming the error reflects a deliberate escape hatch (e.g. interop with an untyped third-party library you cannot annotate). When you do override, narrow the scope tightly and leave a comment naming the underlying issue. \`\`\`toml # LAST RESORT: fix the implementation before reaching for this. # Narrow the scope to the offending module only; do not blanket-disable. [[tool.mypy.overrides]] module = "legacy_module.*" disallow_untyped_defs = false # tracked: <issue link> \`\`\` -
validation-hooks.md 1.8 KB
--- name: validation-hooks description: Layer 3 custom validation hooks for project-specific structure and pattern checks. parent: precommit-setup load_when: enforcing project conventions or schema rules --- # Validation Hooks (Layer 3) Add custom validation hooks for project-specific requirements beyond what generic linters cover (structure, ADR compliance, schema invariants, security patterns). ## Example: Plugin Structure Validation \`\`\`yaml # Layer 3: Validation Hooks - repo: local hooks: - id: validate-plugin-structure name: Validate Plugin Structure entry: python3 scripts/validate_plugins.py language: system pass_filenames: false files: ^plugins/.*\$ \`\`\` ## Custom Hook Patterns Add project-specific hooks for architectural or coverage rules: \`\`\`yaml - repo: local hooks: - id: check-architecture name: Validate Architecture Decisions entry: python3 scripts/check_architecture.py language: system pass_filenames: false files: ^(plugins|src)/.*\\.py\$ - id: check-coverage name: Verify Test Coverage entry: python3 scripts/check_coverage.py language: system pass_filenames: false files: ^(plugins|src)/.*\\.py\$ \`\`\` ## Hook Bypass Policy `SKIP=<hook> git commit` and `git commit --no-verify` **must not be used**. Hooks exist to keep the tree green; bypassing them moves broken code into history, where the next commit fights yesterday's bug instead of today's feature. If a hook fails, fix the underlying issue. If a hook is wrong (false positive, slow, irrelevant), fix the hook configuration. If commit pressure is the problem, land a smaller change. There is no supported workflow in this codebase that ends with a bypassed hook.
-
-
SKILL.md 6.9 KB
--- name: precommit-setup description: Configures pre-commit hooks for linting, type checking, formatting, and testing. Use when setting up a new project or adding quality gates to an existing one. globs: "**/.pre-commit-config.yaml" alwaysApply: false # Custom metadata (not used by Claude for matching): model: sonnet tools: - Read - Write - Bash category: infrastructure tags: - pre-commit - quality-gates - linting - type-checking - testing complexity: intermediate model_hint: standard estimated_tokens: 1800 progressive_loading: true modules: - modules/standard-hooks.md - modules/component-level-hooks.md - modules/validation-hooks.md - modules/ci-integration.md - modules/troubleshooting.md --- # Pre-commit Setup Skill Configure a three-layer pre-commit quality system that enforces linting, type checking, and testing before every commit. ## When To Use - Setting up a new project with code-quality enforcement - Adding pre-commit hooks to an existing project - Upgrading from basic linting to a full quality system - Setting up monorepo or plugin architecture with per-component quality checks - Updating pre-commit hook versions ## When NOT To Use - Pre-commit hooks already configured and working optimally - Project does not use git version control - Team explicitly avoids pre-commit hooks for workflow reasons ## Philosophy: Three-Layer Defense The system is organised in three layers, each with a different cost / coverage tradeoff: - **Layer 1: Standard hooks**: fast global checks (50-200ms total). Lints and type-checks every staged file. - **Layer 2: Component-specific checks**: per-component lint, typecheck, and test (10-30s total). Only the components touched by the staged files are run. - **Layer 3: Validation hooks**: project-specific structure and pattern checks (varies). Catches violations that generic linters miss. This layering keeps the fast feedback loop fast while still catching the slow / project-specific bugs before they land. ## Module Loading The detailed configuration patterns are in modules; load only the ones you need: - `modules/standard-hooks.md`: Layer 1 patterns for Python, Rust, and TypeScript (load when configuring base linters). - `modules/component-level-hooks.md`: Layer 2 monorepo scripts and pre-commit wiring (load when project has multiple components / plugins). - `modules/validation-hooks.md`: Layer 3 custom hooks and SKIP patterns (load when enforcing project conventions beyond linting). - `modules/ci-integration.md`: GitHub Actions workflow plus a complete `.pre-commit-config.yaml` example (load when wiring CI to mirror local checks). - `modules/troubleshooting.md`: timing tables, cache clearing, hook-failure recovery (load when hooks are slow or failing). ## Workflow ### 1. Create Configuration Files \`\`\`bash # Create .pre-commit-config.yaml python3 plugins/attune/scripts/attune_init.py \\ --lang python \\ --name my-project \\ --path . # Create quality check scripts (for monorepos) mkdir -p scripts chmod +x scripts/run-component-*.sh \`\`\` ### 2. Configure Python Type Checking Create `pyproject.toml` with strict type checking: \`\`\`toml [tool.mypy] python_version = "3.12" warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true strict = true # Per-component configuration [[tool.mypy.overrides]] module = "plugins.*" strict = true \`\`\` ### 3. Configure Testing \`\`\`toml [tool.pytest.ini_options] testpaths = ["tests"] pythonpath = ["src"] addopts = [ "-v", # Verbose output "--strict-markers", # Strict marker enforcement "--cov=src", # Coverage for src/ "--cov-report=term", # Terminal coverage report ] markers = [ "slow: marks tests as slow (deselect with '-m \\"not slow\\"')", "integration: marks tests as integration tests", ] \`\`\` ### 4. Install and Test Hooks \`\`\`bash # Install pre-commit tool uv sync --extra dev # Install git hooks uv run pre-commit install # Test on all files (first time) uv run pre-commit run --all-files # Normal usage - test on staged files git add . git commit -m "feat: add feature" # Hooks run automatically \`\`\` ### 5. Create Manual Quality Scripts For full quality checks (CI/CD, monthly audits): \`\`\`bash #!/bin/bash # scripts/check-all-quality.sh: full quality check for all components set -e echo "=== Running Full Quality Checks ===" ./scripts/run-component-lint.sh --all ./scripts/run-component-typecheck.sh --all ./scripts/run-component-tests.sh --all echo "=== All Quality Checks Passed ===" \`\`\` ## Hook Execution Order Pre-commit hooks run in this fixed order; all must pass for the commit to succeed: 1. File validation (whitespace, EOF, YAML/TOML/JSON syntax) 2. Security scanning (bandit) 3. Global linting (ruff, all files) 4. Global type checking (mypy, all files) 5. Component linting (changed components only) 6. Component type checking (changed components only) 7. Component tests (changed components only) 8. Custom validation (structure, patterns, etc.) ## Best Practices ### For New Projects Start with strict settings from the beginning: they are easier to maintain over time. Configure type checking with `strict = true` in `pyproject.toml`, set up testing early (include pytest in pre-commit), and document the reason whenever you must skip a hook. ### For Existing Projects Use a gradual adoption strategy. Start with global checks (Layer 1), then add component-specific checks (Layer 2) once legacy issues are resolved. Use `--no-verify` only for true emergencies and document why. ### For Monorepos and Plugin Architectures Standardize per-component Makefiles for `lint`, `typecheck`, and `test` targets. Centralize common settings in a root `pyproject.toml` while allowing per-component overrides. Automate change detection so commits stay fast, and use progressive disclosure (summary first, detail on failure). ## Related Skills - `Skill(attune:project-init)`: Full project initialization - `Skill(attune:workflow-setup)`: GitHub Actions setup - `Skill(attune:makefile-generation)`: Generate component Makefiles - `Skill(pensive:shell-review)`: Audit shell scripts for exit-code and safety issues ## See Also - **Quality Gates**: three-layer validation: pre-commit hooks (formatting, linting), CI checks (tests, coverage), and PR review gates (code quality, security). ## Exit Criteria - [ ] `.pre-commit-config.yaml` exists at the project root with hooks covering at minimum Layer 1 (whitespace, YAML/TOML/JSON syntax, global linting). - [ ] `uv run pre-commit run --all-files` exits 0 after the configuration is installed, confirming all hooks pass on the current codebase state. - [ ] `git commit` with a staged change triggers the pre-commit hooks automatically (verified by `uv run pre-commit install` exit code 0 and presence of `.git/hooks/pre-commit`). - [ ] Any `--no-verify` bypass is absent from the project's documented workflows; if one is found in existing scripts, it is flagged as a violation rather than silently accepted.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.