Skip to content
Docs

Auto Code Quality

The auto code quality plugin keeps your code clean without any manual effort. Every file you edit gets automatically formatted and linted at the end of each assistant turn, so you never need to remember to run your formatters or worry about style inconsistencies creeping in.

The plugin operates in four phases during a session, each triggered by a different hook:

  1. On every edit (PostToolUse) — When Claude writes or edits a file, the plugin records the file path and validates data file syntax immediately.
  2. At the end of each turn (Stop) — All edited files are batch-formatted using the appropriate tool for each language.
  3. After formatting (Stop) — All edited files are linted and any issues are reported.
  4. After linting (Stop) — If a test framework is detected, affected tests are run automatically.

This “collect, then batch process” approach avoids running formatters on every keystroke while ensuring nothing slips through.

Quality checks run as advisory hooks — they report findings without blocking your workflow. Formatting is applied silently, while lint warnings and test failures are surfaced as context that Claude can act on. If tests fail, the hook blocks the Stop so Claude addresses the failures before finishing.

When you edit a data file (JSON, JSONC, YAML, or TOML), the syntax-validator.py script validates it immediately. This catches broken configuration files the moment they’re saved rather than waiting for something downstream to fail.

Validated formats:

FormatValidation
.jsonJSON parse check
.jsoncComment-stripped JSON parse check
.yaml / .ymlYAML safe_load (requires PyYAML)
.tomlTOML parse check (Python 3.11+)

At the end of each turn, format-on-stop.py processes every file that was edited during the conversation. It selects the right formatter based on file extension:

FormatterLanguages / ExtensionsNotes
Ruff (or Black fallback).py, .pyiRuff preferred; falls back to Black if unavailable
gofmt.goStandard Go formatting
Biome.js, .jsx, .ts, .tsx, .mjs, .cjs, .mts, .cts, .css, .json, .jsonc, .graphql, .gql, .html, .vue, .svelte, .astroChecks project-local install first, then global
shfmt.sh, .bash, .zsh, .mksh, .batsShell script formatting
dprint.md, .markdown, .yaml, .yml, .toml, DockerfileUses global dprint config
rustfmt.rsConditional — only runs if installed

After formatting, lint-file.py runs language-appropriate linters on the same set of edited files:

LinterLanguagesWhat It Catches
PyrightPythonType errors, missing imports, incorrect signatures
RuffPythonStyle violations, unused imports, correctness issues
BiomeJS/TS/CSS/GraphQLLint rules, accessibility, suspicious patterns
ShellCheckShell scriptsCommon shell scripting pitfalls, quoting issues
go vetGoSuspicious constructs, printf format mismatches
hadolintDockerfileDockerfile best practices, security issues
clippyRustIdiomatic Rust patterns, performance, correctness

Lint results appear as context messages with per-file summaries showing up to 5 issues each, including line numbers and severity levels.

The advisory-test-runner.py script is the final quality gate. It detects your project’s test framework, identifies which tests are affected by your changes, and runs only those tests.

FrameworkDetectionTargeted Testing
pytestpytest.ini, conftest.py, pyproject.toml, tests/ dirMaps source files to test_*.py counterparts
vitestvitest.config.* or test in vite.config.*Uses --related for dependency-graph analysis
jestjest.config.* or jest in package.jsonUses --findRelatedTests
mochamocha in dependenciesRuns full suite
npm testscripts.test in package.jsonRuns full suite
go testgo.modMaps .go files to package directories
cargo testCargo.tomlRuns full suite

When tests pass, you see a brief confirmation message. When tests fail, the hook blocks the Stop with the last 30 lines of test output, giving Claude the information needed to fix the failures before finishing. Tests have a 15-second timeout to keep the feedback loop fast.

ScriptHookTriggerPurpose
collect-edited-files.pyPostToolUseEdit, WriteRecords which files were modified
syntax-validator.pyPostToolUseEdit, WriteValidates JSON/YAML/TOML syntax immediately
format-on-stop.pyStopEnd of turnBatch-formats all edited files
lint-file.pyStopEnd of turnBatch-lints all edited files
advisory-test-runner.pyStopEnd of turnRuns affected tests

The plugin works out of the box with no configuration needed. It automatically detects which tools are available and skips any that aren’t installed. To disable specific quality checks, you can modify the plugin’s hooks.json to remove individual scripts.

See Configuration for details on adjusting plugin settings.