Skip to main content

Command Palette

Search for a command to run...

AI Coding Tip 027 - Force Code Standards

Style errors double when nobody enforces them.

Updated
7 min readView as Markdown
AI Coding Tip 027 - Force Code Standards
M

I’m a senior software engineer loving clean code, and declarative designs. S.O.L.I.D. and agile methodologies fan.

TL;DR: Wire your standards into hooks, skills, and a judge, so the harness blocks violations before a human opens the diff.

Common Mistake ❌

You paste your coding standards into AGENTS.md and trust the AI to remember them.

Then a human reviewer manually checks naming, indentation, and spacing on every pull request.

Nobody wires a hook, a skill, or a judge that blocks the diff before a human ever opens it.

The standards live in prose, and prose is optional.

Problems Addressed 😔

How to Do It 🛠️

  1. Turn each standard into a machine-checkable rule instead of a paragraph of prose.

  2. Wire a pre-commit or pre-merge hook that runs the linter automatically on every change.

  3. Add a validator skill that reads the rule set fresh and re-checks the whole diff, not just what the AI remembers.

  4. Route ambiguous rules, like naming intent, to a large language model (LLM) judge instead of a human reviewer.

  5. Block the commit, the merge, or the session end until every gate reports zero violations.

  6. Log every violation the judge catches as a new rule, so the harness never misses it again.

Benefits 🎯

  1. Consistent gate: Every diff hits the same rule set, so two reviewers never catch two different subsets of the same violation.

  2. Faster reviews: Humans spend their attention on design and correctness, not indentation or casing.

  3. No memory decay: A skill reads the standards file fresh every session instead of trusting what the AI claims to remember.

  4. Judge for nuance: An LLM judge catches the semantic violations a regular expression can't parse, like a misleading name.

  5. Compounding rules: Every violation the judge finds becomes a new check, so the harness gets stricter over time.

  6. Measurable drop: You can track the naming and style defect rate over time and watch it fall toward zero.

Context 🧠

Standards enforcement isn't new.

Stephen C. Johnson wrote the first lint in 1978 to catch mistakes in C code nobody wanted to check by eye.

Checkstyle, PMD, and ESLint followed, each one refusing to trust a human to notice a mixed indentation.

SonarQube added a server that gates a whole pipeline, not just a single file.

Mago does the same for PHP now, running a linter, a formatter, and a static analyzer in one Rust binary fast enough to run on every keystroke.

None of these tools ever asked a human to vote on a tab versus a space or a mixedCase versus snake_case name.

AI coding didn't remove that need.

It multiplied it.

A CodeRabbit analysis of 470 pull requests found AI-generated code carries about 1.7x more defects overall than human-only code.

Naming and style consistency errors came in at nearly 2x, the exact class of mistake a linter was built to catch decades ago.

A model can now write in any human language, misspell an identifier, or reorder parameters inconsistently across two files it never compared side by side.

A linter still catches the syntactic version of these mistakes.

The semantic version, like a name that lies about its role, needs a judge that reads intent, not just tokens.

That's where an LLM-as-judge step fits: a second AI pass, wired into the same harness that runs the linter, checking the rules no regular expression can express.

Skills are the natural home for that judge.

A skill reads the standards file fresh every time, instead of trusting a memory that decays across sessions.

Pair the judge with a criteria check before the task ends, so the AI can't say a task is done until the standards gate reports zero violations.

A gate that blocks the diff is just another way to force the AI to obey you, not by asking nicely, but by refusing to let a violation through.

This doesn't replace reviewing every line before commit.

It removes the mechanical part of that review, so a human is free to judge design instead of counting spaces.

When the judge catches a new violation, log it the same way you'd log a pitfall, so the harness never makes that mistake twice.

Prompt Reference 📝

Bad Prompt 🚫

Please follow our coding standards for this feature.
Use consistent naming and formatting like the rest of the codebase.
I'll check it during code review before we merge.

Good prompt 👉

Before you say this task is done, run this standards checklist:

- [ ] Run the linter on every changed file, fix every violation.

- [ ] Run the formatter, don't hand-format a single line.

- [ ] Invoke the code-standards-validator skill on the full diff.

- [ ] Check every identifier: no abbreviations, no misleading names.

- [ ] Check indentation matches the project config, no mixed tabs.

- [ ] Check casing: one convention, no mixedCase next to snake_case.

- [ ] Check parameter order against other functions in the file.

- [ ] Check spelling in every identifier, comment, and string.

- [ ] Judge comment quality: flag dead comments and restated code.

- [ ] Judge naming intent: does each name say what it does?

- [ ] Confirm no file mixes languages in identifiers or comments.

- [ ] Log any new violation type as a rule for the next run.

- [ ] Don't report the task done until every box above is checked.

Show me the completed checklist, not just the final code.

Considerations ⚠️

A linter still beats an LLM judge on speed and cost for anything syntactic.

Reserve the judge for rules that need intent, not tokens.

A gate that blocks too aggressively gets bypassed with --no-verify, which defeats the whole point.

Review the judge's false positives the same way you'd review a flaky linter rule.

Type 📝

[X] Semi-Automatic

Limitations ⚠️

An LLM judge costs tokens and time on every gate, so it doesn't replace a linter.

It complements one.

A judge can disagree with itself across two runs on borderline style calls, so keep the deterministic rules in the linter and reserve the judge for what's genuinely ambiguous.

Tags 🏷️

  • Knowledge Management

Level 🔋

[X] Intermediate

Related Tips 🔗

https://maximilianocontieri.com/ai-coding-tip-004-use-modular-skills

https://maximilianocontieri.com/ai-coding-tip-006-review-every-line-before-commit

https://maximilianocontieri.com/ai-coding-tip-011-initialize-agents-md

https://maximilianocontieri.com/ai-coding-tip-015-force-the-ai-to-obey-you

https://maximilianocontieri.com/ai-coding-tip-016-feed-your-pr-lessons-into-the-ai-brain

https://maximilianocontieri.com/ai-coding-tip-019-tell-the-ai-why-not-just-what

https://maximilianocontieri.com/ai-coding-tip-022-give-ai-a-harness-to-work-with

https://maximilianocontieri.com/ai-coding-tip-024-force-a-criteria-check-before-the-task-ends

https://maximilianocontieri.com/ai-coding-tip-025-pair-every-skill-with-a-pitfalls-file

Conclusion 🏁

A linter never asked permission to reject bad code.

Neither should your harness.

Wire the standards into hooks, skills, and a judge, so the diff gets rejected before a human ever has to say so.

More Information ℹ️

Lint (software) - Wikipedia

State of AI vs Human Code Generation Report - CodeRabbit

When AIs Judge AIs: The Rise of Agent-as-a-Judge Evaluation for LLMs

Awesome Static Analysis - curated list of linters and code quality tools

Also Known As 🎭

  • Harness-Enforced-Standards
  • Machine-Judged-Style
  • Standards-as-Code
  • Linter-Native-Review

Tools 🧰

Mago

ESLint

SonarQube

PHP_CodeSniffer

Ruff

RuboCop

Checkstyle

golangci-lint

Clippy

Disclaimer 📢

The views expressed here are my own.

I am a human who writes as best as possible for other humans.

I use AI proofreading tools to improve some texts.

I welcome constructive criticism and dialogue.

I shape these insights through 30 years in the software industry, 25 years of teaching, and writing over 500 articles and a book.


This article is part of the AI Coding Tip series.

https://maximilianocontieri.com/ai-coding-tips

2 views