pragmatic-audit
Code-quality audits for AI-generated code. A zero-dependency CLI and agent skill that check a repository against The Pragmatic Programmer.
AI made writing code cheap. Changing it is still expensive.
pragmatic-audit checks a repository against the durable principles from The Pragmatic Programmer — DRY, orthogonality, contracts, resource ownership, external configuration, tests, and more — then hands the judgment calls to your agent with a focused review packet. Read the project site for the AI code audit workflow and the Pragmatic Programmer checklist.
It is for humans reviewing agent output, and for agents that need to write code worth keeping.
Why this matters in the agentic era
Agents can produce code faster than humans can review it. They also copy patterns — including bad ones — at scale. Prototypes that were meant to be thrown away become production systems, and the small compromises compound.
The bottleneck has moved. It is no longer how fast a team can type. It is how cheaply the code can change next week.
Principles are portable guardrails. They survive model upgrades, framework churn, and team changes. A deterministic audit gives humans and agents the same vocabulary for a review:
- DRY asks whether one piece of knowledge has one authoritative home.
- Orthogonality asks whether a change stays local.
- Contracts ask whether a boundary fails loudly or lies quietly.
- Resource ownership asks who closes what they opened.
- Tests ask whether behavior is pinned down or merely exercised.
pragmatic-audit finds the mechanical violations. The bundled skill teaches an agent how to reason about the rest.
What you get
| Audit | A fast, offline scan with file-and-line findings, severity, confidence, and a concrete fix. 20 core checks, plus 3 opt-in history checks. |
| Explain | Every finding names the principle and tip it comes from. The report separates mechanical findings from questions that need human judgment. |
| Coach | --agent-packet writes a JSON and Markdown briefing your agent can use to review the code, confirm or dismiss findings, and propose the smallest useful change. |
No network. No telemetry. No LLM calls inside the CLI. No dependencies outside the Python standard library.
Quick start
Run it against any repository without installing anything:
git clone --depth 1 https://github.com/CobaltChaser/pragmatic-audit.git /tmp/pragmatic-audit
cd /tmp/pragmatic-audit && python3 -m pragmatic_audit /path/to/repo
Or install the CLI from PyPI:
pip install pragmatic-audit
pragmatic-audit .
With pipx:
pipx install pragmatic-audit
pragmatic-audit .
Common modes:
# Human-readable report
pragmatic-audit .
# Stable JSON for CI and agents
pragmatic-audit . --format json
# Findings plus a review packet for your coding agent
pragmatic-audit . --agent-packet
# Fail the build on high-severity findings
pragmatic-audit . --ci --fail-on high
Python 3.11 or newer. Nothing else.
Install the agent skill
The skill lives in skills/pragmatic-programmer. Every command below is repeatable and self-cleaning.
Claude Code
rm -rf ~/.cache/pragmatic-audit && git clone --depth 1 https://github.com/CobaltChaser/pragmatic-audit.git ~/.cache/pragmatic-audit && mkdir -p ~/.claude/skills && cp -R ~/.cache/pragmatic-audit/skills/pragmatic-programmer ~/.claude/skills/
Claude Cowork / claude.ai
rm -rf ~/.cache/pragmatic-audit && git clone --depth 1 https://github.com/CobaltChaser/pragmatic-audit.git ~/.cache/pragmatic-audit && cd ~/.cache/pragmatic-audit/skills && zip -r ~/Downloads/pragmatic-programmer.zip pragmatic-programmer
Then open Customize → Skills → Upload and select pragmatic-programmer.zip.
ChatGPT Work / CoWork
rm -rf ~/.cache/pragmatic-audit && git clone --depth 1 https://github.com/CobaltChaser/pragmatic-audit.git ~/.cache/pragmatic-audit && cd ~/.cache/pragmatic-audit/skills && zip -r ~/Downloads/pragmatic-programmer.zip pragmatic-programmer
Then open Plugins → Skills → Create → Upload from your computer and select the ZIP.
For local Codex:
rm -rf ~/.cache/pragmatic-audit && git clone --depth 1 https://github.com/CobaltChaser/pragmatic-audit.git ~/.cache/pragmatic-audit && mkdir -p ~/.codex/skills && cp -R ~/.cache/pragmatic-audit/skills/pragmatic-programmer ~/.codex/skills/
OpenCode
rm -rf ~/.cache/pragmatic-audit && git clone --depth 1 https://github.com/CobaltChaser/pragmatic-audit.git ~/.cache/pragmatic-audit && mkdir -p ~/.config/opencode/skills && cp -R ~/.cache/pragmatic-audit/skills/pragmatic-programmer ~/.config/opencode/skills/
Project-local variant:
mkdir -p .opencode/skills && cp -R /path/to/pragmatic-audit/skills/pragmatic-programmer .opencode/skills/
Everything else (Agent Skills standard)
rm -rf ~/.cache/pragmatic-audit && git clone --depth 1 https://github.com/CobaltChaser/pragmatic-audit.git ~/.cache/pragmatic-audit && mkdir -p ~/.agents/skills && cp -R ~/.cache/pragmatic-audit/skills/pragmatic-programmer ~/.agents/skills/
Host notes:
- Claude Code reads
~/.claude/skills/and.claude/skills/. - OpenCode reads
~/.config/opencode/skills/,~/.claude/skills/,~/.agents/skills/, and their project equivalents. - Codex reads local skills from
~/.codex/skills/. ChatGPT workspace skills are uploaded through the UI. - Cursor and other compatible hosts can use
~/.agents/skills/or their documented local skill directory. - Keep
SKILL.mdat the root of the skill folder. The folder name must match the skill name.
See docs/agent-skill.md for invocation examples and compatibility notes.
Use it in CI
name: pragmatic-audit
on:
push:
pull_request:
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pipx install pragmatic-audit
- run: pragmatic-audit . --ci --fail-on high --format markdown --output pragmatic-audit.md
- uses: actions/upload-artifact@v4
if: always()
with:
name: pragmatic-audit
path: pragmatic-audit.md
Exit codes:
| Code | Meaning |
|---|---|
0 |
Audit completed, gate passed |
1 |
Audit completed, gate failed |
2 |
Invalid usage or unreadable path |
3 |
Internal error |
The gate is opt-in. By default the CLI reports and exits 0. Use --fail-on medium when the codebase is ready for a stricter ratchet.
The 20 core checks
Open the rule table
| Rule | Principle | What it catches |
|---|---|---|
PP-DRY |
Don't repeat yourself | Duplicated normalized blocks of 6+ lines and duplicate functions |
PP-CONFIG |
External configuration | Hardcoded secrets, environment URLs, absolute paths, and non-local IPs |
PP-MAGIC |
Policy is metadata | Unexplained numeric thresholds in comparisons |
PP-ORTHO |
Orthogonality | Import cycles and modules with excessive internal fan-out |
PP-GLOBALS |
Avoid global data | Module-level mutable state, global, and mutable defaults |
PP-TRAINWRECK |
Decoupled code | Call chains that reach through three or more objects |
PP-INHERIT |
Composition over inheritance | Inheritance depth over two |
PP-CONTRACTS |
Design with contracts | Empty catches, swallowed errors, and bare except |
PP-RESOURCES |
Resource ownership | Acquired resources without a guaranteed release path |
PP-COINCIDENCE |
Rely on reliable things | Mutable defaults, float equality, loose JS equality, and stale var |
PP-COMPLEXITY |
Good design is easier to change | Long functions, deep nesting, high branch count, and too many parameters |
PP-NAMING |
Express intent | Single-letter and generic names, and vague boolean names |
PP-COMMENTS |
Good code is its own documentation | Commented-out code blocks |
PP-BROKEN-WINDOWS |
Fix bad code when you see it | Skip markers, unexplained suppressions, and TODO/FIXME density |
PP-TESTS |
Design to test | Missing tests, thin coverage, and assertion-free tests |
PP-TEST-HYGIENE |
A good test is a good neighbor | Sleeps, real network calls, and nondeterministic input in tests |
PP-AUTOMATION |
Automate the routine | Missing CI, task automation, and unscripted release steps |
PP-VCS |
Version control everything | Missing git, missing .gitignore, tracked secrets, and large files |
PP-E2E |
Build end-to-end | Unit-only suites with no smoke or end-to-end path |
PP-DOCS |
Documentation lives with the code | Missing or unhelpful README documentation |
Opt-in history and architecture checks:
| Rule | Principle | What it catches |
|---|---|---|
PP-SMALL-STEPS |
Small reversible steps | Commits touching more than 30 files or 1,000 lines |
PP-REVERSIBILITY |
There are no final decisions | Vendor SDKs spread across modules without an adapter boundary |
PP-SHARED-STATE |
Avoid shared mutable state | Mutable module state in files that use concurrency |
Enable them with --include-history or --all.
Full rationale, examples, false positives, and tuning: docs/rules.md.
Hybrid by design
Static analysis is good at finding mechanical violations. It is bad at judging design.
This tool does not pretend otherwise.
- The scanner produces deterministic findings with locations and fixes. It reads Python and JavaScript/TypeScript structurally, and uses conservative text heuristics for Go, Java, Ruby, PHP, Rust, and others.
- The report adds a manual review queue: tracer bullets, boundary contracts, orthogonality, domain language, reversibility, test design, and speculative code.
- The packet gives an agent the evidence and a question set. The agent must open the files, confirm or dismiss each finding, and report only the few changes that most improve changeability.
pragmatic-audit . --agent-packet
That writes pragmatic-audit.packet.json and pragmatic-audit.packet.md in the current directory. Neither file is required for normal use; both are designed to be pasted into an agent session.
What it will not do
- It will not auto-fix code.
- It will not make network requests or call an LLM.
- It will not replace your linter, type checker, test runner, or security scanner.
- It will not produce a definitive quality score. The number is directional and always shown next to raw counts.
- It will not understand every framework’s conventions. False positives are expected; dismiss them with a reason or tune the rule.
- It will not prove that code is correct.
Treat every finding as a hypothesis. Read the code before changing it.
Example report
The bundled bad repository produces a real report: examples/report.md.
The examples are deliberately small and are used by the test suite:
pragmatic-audit examples/bad-repo
pragmatic-audit examples/good-repo
Tuning
Create .pragmatic-audit.toml at the repository root:
[scan]
exclude = ["generated", "public/vendor", "*.min.js"]
languages = ["python", "javascript", "typescript"]
[thresholds]
long_function = 60
deep_nesting = 4
max_params = 5
test_ratio = 0.3
[ignore]
rules = ["PP-MAGIC"]
paths = ["migrations/**"]
[ci]
fail_on = "high"
min_confidence = "medium"
Suppress a single line when the finding is genuinely wrong:
if len(items) > 42: # pragmatic-audit: ignore PP-MAGIC pagination boundary from the API contract
Suppress a file when the whole file is a known exception:
# pragmatic-audit: ignore-file PP-GLOBALS this module is the state owner
Every suppression needs a written reason. A suppression without a reason is a broken window.
Self-audited
This repository runs pragmatic-audit on itself in CI, and the test suite includes the rules it ships. The current self-audit report is examples/self-audit.md, generated by scripts/self_audit.sh.
The tool is not expected to score 100. It is expected to show its own trade-offs honestly, including deliberate exceptions and false positives.
Contributing
PRs are open. This project gets better when more people encode the principles they actually use. Rule proposals, false-positive reports, new language patterns, docs fixes, and examples are all welcome.
Good first contributions:
- Add a language pattern to an existing rule, with a positive and negative fixture.
- Improve a rule description or a fix suggestion.
- Add a false-positive case that the current tests miss.
- Make an example repository more realistic.
- Tighten the docs.
Read CONTRIBUTING.md before opening a pull request. The short version:
python3 -m unittest discover -s tests -v
python3 -m compileall pragmatic_audit
python3 -m pragmatic_audit . --ci --fail-on high
No new runtime dependencies. Every rule needs a test. Every behavior claim needs a test or a code link.
License
Apache-2.0. Use it at work, in commercial products, and in closed-source repositories. Keep the copyright, license, and NOTICE file, and state significant changes.
Full terms: LICENSE.
Credits
The Pragmatic Programmer, 20th Anniversary Edition is by David Thomas and Andrew Hunt. This project is an independent, unofficial tool. Tip names and numbers are referenced descriptively with attribution. No book text is reproduced. The project is not affiliated with the authors or The Pragmatic Programmers, LLC.
The audit text, prompts, and documentation in this repository are original paraphrases and implementations.
Metadata
Release files for pragmatic-audit 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pragmatic_audit-0.1.0.tar.gz | 471.5 kB | With provenance | Details for pragmatic_audit-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pragmatic_audit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for pragmatic_audit-0.1.0-py3-none-any.whl |
Total release size: 530.2 kB
Release files / pragmatic_audit-0.1.0.tar.gz
| Download URL | pragmatic_audit-0.1.0.tar.gz |
|---|---|
| Size | 471.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4079acab08cbc8572aae743d9d858e37540a81ecc6b31fe9c3c040f555b0d433
|
|
BLAKE2b-256 checksum How to use checksums |
92d6ea96d79ca65e8b1ad313ef4ce92b4f6644a51c182bf5c3044e9888b79d14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logRelease files / pragmatic_audit-0.1.0-py3-none-any.whl
| Download URL | pragmatic_audit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 58.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3c77b247017adc9d4377376b6fa765c1b2acf18b311e4f2fb3eb37437fdbaf7b
|
|
BLAKE2b-256 checksum How to use checksums |
b1b63b7c53e5779ee300d3b0668041581c6568d43efd05750b335c57d20f438e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logSecurity for pragmatic-audit 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pragmatic_audit-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.