A coding standard sets out the rules a team agrees its code will meet. Some rules cover how the code looks, such as indentation, line length and naming. Others set limits a tool can count, such as how long a function may be or how many paths run through it.
A standard only sticks where something checks it. Put each rule a tool can check into your linter’s config as an error. A linter reads code without running it and reports every rule the code breaks. Then run every check in CI, short for continuous integration, on every pull request. A change that breaks a rule can’t merge, whether a person or a coding agent wrote it. The rules no tool can check go on a short list for review.
What coding standards cover
Coding style usually means layout: indentation, spacing, line length and where the braces go. Code guidelines, or conventions, add naming, file layout, imports and error handling. A full coding standard adds limits that a tool can measure on every change.
Google’s style guide index (2026) calls a style guide a set of conventions, some of them arbitrary. It adds that a large codebase is much easier to understand when all of it is in one style. PEP 8, by Guido van Rossum, Barry Warsaw and Alyssa Coghlan (2001), starts from the same place. It notes that code is read much more often than it’s written.
Which arbitrary choice a guide makes hardly matters, because the value comes from everyone following the same rules. PSR-12 (2019), PHP-FIG’s coding style for PHP, puts the guide’s benefit in the sharing of its rules.
Coding standards examples
Here are four standards and the tools that check them:
| Standard | Language | What it covers | What checks it |
|---|---|---|---|
| PEP 8 | Python | Layout, whitespace, comments and naming | Ruff, whose E, W and N rules come from pycodestyle and pep8-naming |
| PSR-12 | PHP | Files, lines, indenting, declarations and control structures | PHP_CodeSniffer, which checks against PSR-12 unless told not to |
| Prettier’s output | JavaScript, TypeScript, CSS and more | Formatting only | Prettier rewrites each file in its own style |
| The Prickles canon | TypeScript, JavaScript, Python, Java and PHP | Size, complexity, duplication and naming, among 51 tenets | A lint config for each language, plus rule files for coding agents |
Prettier’s Why Prettier? (2026) gives an end to arguments over style as the main reason to adopt it. Google’s The Standard of Code Review (2026) treats the style guide as the final word on style, and any style point it doesn’t cover as personal preference. Pick a guide and let a formatter apply as much of it as it can. A review then no longer has to settle layout.
A written rule is a request
A rule in a wiki is followed while people remember it and a reviewer spots the miss. A coding agent is in the same position with its instruction file. Anthropic’s How Claude remembers your project (2026) says Claude reads CLAUDE.md as context rather than as configuration it must obey. It adds that strict compliance isn’t guaranteed.
Anthropic’s Best practices for Claude Code (2026) contrasts an instruction with a hook. A hook is a script that Claude Code runs automatically at a set point, such as after each edit. In the page’s words, “Unlike CLAUDE.md instructions which are advisory, hooks are deterministic and guarantee the action happens.”
Yujun Zhou and colleagues measured the gap in Getting Better at Working With You (2026). They ran six models on 19 coding-agent tasks with 29 checks, built from corrections one researcher made to coding agents over about two months. With every rule placed in the agent’s context as text, the agents passed 55.0% of the checks. With the same rules compiled into checks the run had to pass before it could finish, they passed 70.1%. With no rules at all, they passed 31.6%.
So put every rule a tool can check where the tool checks it, and make the check fail. TA1 Linter as Law makes every gate an error, never a warning. ESLint’s Configure Rules page (2026) shows why the severity matters. A rule set to "warn" leaves the exit code alone. A rule set to "error" makes ESLint exit with 1. CI fails a step that exits with anything but 0, so only an error stops the build.
These core ESLint rules set five of the canon’s limits, and its magic-number rule, as errors in eslint.config.mjs:
const LIMITS = {
complexity: 3,
depth: 3,
params: 3,
functionLines: 15,
fileLines: 150,
};
export default [
{
files: ["**/*.js", "**/*.mjs"],
rules: {
complexity: ["error", LIMITS.complexity],
"max-depth": ["error", LIMITS.depth],
"max-params": ["error", LIMITS.params],
"max-lines-per-function": ["error", { max: LIMITS.functionLines, skipBlankLines: true }],
"max-lines": ["error", { max: LIMITS.fileLines, skipBlankLines: true }],
"no-magic-numbers": ["error", { ignore: [-1, 0, 1] }],
},
},
];
On 12 October 2026, with ESLint 9.39.5, this config passed its own rules. A function with four paths and two bare numbers failed it with three errors. With each "error" changed to "warn", the same three problems came back as warnings and the run passed.
Code quality metrics you can gate on
A metric is worth a gate when a tool can count it on every change. The count should also say something about how hard the code is to read or change. These are the limits the Prickles canon sets. Each pack’s lint config enforces the ones its language’s tools can measure.
| Metric | Canon limit | What it counts |
|---|---|---|
| Cyclomatic complexity | 3 | Independent paths through one function |
| Nesting depth | 3 | Blocks inside blocks |
| Function length | 15 lines | Lines in one function, leaving out blank lines |
| File length | 150 lines | Lines in one file, leaving out blank lines |
| Statements | 10 | Statements in one function |
| Parameters | 3 | Arguments one function takes |
| Cognitive complexity | 15 | How hard a function is to follow, weighted for depth |
| Duplication | 50 tokens | Smallest copied block counted as a clone |
| Magic numbers | None beyond -1, 0 or 1 | Bare numbers in the code |
Cyclomatic complexity starts at one and adds one for each branch in the function. A magic number is a number whose meaning isn’t named, such as 18 where ADULT_AGE would say what it is. For duplication, jscpd counts tokens, the words and symbols a parser splits code into.
These limits are strict on purpose. S2 Cyclomatic Caps explains why the complexity cap is 3, and Code complexity covers the metric in depth. The same cap is set differently in each pack’s tools:
- TypeScript and JavaScript use ESLint’s
complexityrule, set to 3. - Python uses Ruff’s
max-complexity, set to 3. - Java uses PMD’s
CyclomaticComplexity, withmethodReportLevelset to 4, because PMD reports a method that reaches the level it’s given. - PHP uses PHP_CodeSniffer’s
Generic.Metrics.CyclomaticComplexity, set to 3.
How to measure code quality
Count what a tool can count, give each count a limit and fail any change that crosses one. Measured that way, each change passes or fails whoever reviews it.
This site’s own repository works this way. Its CI runs these checks on every pull request and every push to main, and any failure fails the run. All of them passed on main on 12 October 2026.
| Check | Tool | Fails the run when |
|---|---|---|
| Lint | ESLint with its sonarjs and unicorn plugins | Any rule reports an error, including 15 lines a function, 150 a file and complexity 3 |
| Formatting | Prettier | A file differs from Prettier’s output |
| Types | tsc and astro check | There’s a type error anywhere |
| Duplication | jscpd | A copied block of 50 tokens or more appears anywhere in the source |
| Unit tests | Vitest | A test fails, or coverage of lines, functions, branches or statements falls below 100% |
| Build | astro build | Astro can’t build the site |
| End-to-end tests | Playwright, running scenarios written in Gherkin | A scenario fails in the browser |
| Security audit | npm audit | A dependency has a known vulnerability rated high or above |
Most of the same checks run on a developer’s machine with one command, npm run quality. It also runs a Sonar analysis locally. P4 Continuous Quality Feedback asks for this, so the check runs while the change is fresh, before CI sees it.
Over time, count the exceptions. Every comment that disables a rule on a line, and every folder a rule is switched off for, is a place where the standard doesn’t apply. On 12 October 2026, the source of the repository behind this site held no inline disable comments.
How to set up coding standards for a team
- Pick a published style guide for each language, and let a formatter apply as much of it as it can.
- Write each limit into the lint config as an error before the first violation is merged, as TA1 Linter as Law asks.
- Give the team one command that runs every check, and run it while you work, before CI sees the change, as P5 Shift-Left Quality describes. A pre-commit hook can run the fast checks before each commit.
- Run the same checks in CI on every pull request, and make the CI job a required status check. GitHub’s About protected branches (2026) says every required check must pass before anyone can merge into a protected branch.
- Put the rules in your coding agent’s instruction file too, so it writes to the standard the first time. CLAUDE.md vs AGENTS.md covers which file each agent reads.
- When a rule trips, fix the code. For older code that can’t meet a limit yet, switch the rule off for that folder alone. Keep a plan to remove the exception, as TA2 Duplication Detection does for duplicates.
- Write the checks no tool can make as a short definition-of-done checklist, and review each change against it, as P3 Definition of Done sets out.
A lint error gives a coding agent its feedback. Anthropic’s best practices tell you to give Claude a check it can run, such as tests, a build or a linter. Without one, Claude stops when the work looks done.
John Yang and colleagues measured what a lint check does for an agent in SWE-agent (2024). With GPT-4 Turbo on the 300 tasks of SWE-bench Lite, SWE-agent resolved 18.0% when its edit command refused edits that failed a lint check for syntax errors. Without the check, it resolved 15.0%.
What a linter can’t check
Each Prickles pack’s lint config lists, in its header, the tenets it enforces out of the canon’s 51:
| Language | Lint tools in the pack | Tenets the config enforces |
|---|---|---|
| TypeScript | ESLint and its plugins | 19 |
| JavaScript | ESLint and its plugins | 16 |
| Python | Ruff and Pylint | 16 |
| Java | PMD | 13 |
| PHP | PHP_CodeSniffer with PHPMD and phpmnd | 12 |
Other tenets take judgement, such as whether a name says what the code does or whether a function has one reason to change. TA1 asks you to name the line between what the linter checks and what it can’t, so nobody mistakes the lint gate for the whole standard. A short checklist and a reviewer cover what lies beyond it, and AI code review has a checklist for that review.
Each Prickles pack carries both halves. The lint config fails the build on what a tool can count. The agent’s rule files carry every tenet. A short entry that the agent always loads holds each tenet’s rule. The rest of the canon loads when the work needs it. The implementation page shows what each agent and language gets.
