# lessloc > lessloc keeps AI coding agents such as Claude Code, Codex, GitHub Copilot, Gemini CLI and Cursor to the least code that does the job and still works. It runs inside your AI coding agent through the agent tool's hooks. It is free and open source (Apache-2.0), needs no account, and makes no network calls. Source code: [https://github.com/rextail-ai/lessloc](https://github.com/rextail-ai/lessloc). To install it, tell your coding agent: "Install lessloc for this project by following https://lessloc.org/install.md" Every page below is plain Markdown. The whole documentation, condensed for an AI coding agent (54 KB): https://lessloc.org/agents.md. The docs in one file (331 KB): https://lessloc.org/llms-full.txt. The pattern pages in one file (91 KB): https://lessloc.org/llms-patterns.txt ## Start - [For AI agents: read this first](https://lessloc.org/agents.md) (54 KB): lessloc keeps coding agents to the least code that does the job and still works. It runs inside your agent tool's hooks: you never call it, and nothing it tells you names it. It needs no account and no API key, installs no packages (it needs only Node and git), and is open source under Apache-2.0. - [Install lessloc (steps for an agent)](https://lessloc.org/install.md): These steps are for an AI coding agent whose user asked it to install lessloc. Follow them in order and run each command yourself. The user only approves your commands. Where a step says to stop, stop and tell the user why. - [Remove lessloc (steps for an agent)](https://lessloc.org/remove.md): These steps are for an AI coding agent whose user asked it to remove lessloc. Follow them in order and run each command yourself. The user only approves your commands. - [lessloc: overview](https://lessloc.org/index.md): lessloc keeps AI coding agents such as Claude Code, Codex, GitHub Copilot, Gemini CLI and Cursor to the least code that does the job and still works. - [Start here (for people)](https://lessloc.org/start.md): Install lessloc by telling your AI coding agent one sentence. What you will notice, how to check that it works, and how to remove it the same way. ## Docs - [Getting started: install lessloc for your AI coding agent](https://lessloc.org/guide/getting-started.md) (41 KB): lessloc is a free, open-source (Apache-2.0) tool that keeps AI coding agents to the least code that does the job and still works. It runs inside your AI coding agent through the agent tool's hooks. You install it once for your agent tools. Each repository then gets a commit gate. The agent never sees lessloc: there is no command for it to learn and no file for it to read. - [Custom agents and SDKs: the lessloc hook protocol](https://lessloc.org/guide/any-agent.md): An agent you build yourself can use lessloc through one command: your code sends it one JSON object per event and applies the JSON answer. This page is that protocol, version 1. The agent tools in Getting started need none of it. - [How lessloc works: hooks from session start to handoff](https://lessloc.org/guide/how-it-works.md) (23 KB): lessloc runs inside your agent tool as hooks, small programs the tool starts at set moments, and steps in only where acting is cheapest. - [Configure lessloc: every .lessloc.json key and its default](https://lessloc.org/guide/configuration.md) (21 KB): lessloc works without any configuration. When a project needs its own rules, its owner writes them in .lessloc.json at the root of the repository. This page lists every key with its default, how to accept or suppress a finding, and the switches that turn lessloc off. - [Commits and CI with lessloc: check, commit gate, ratchet](https://lessloc.org/guide/ci.md): lessloc for commits and CI: check, the commit gate, test evidence, ci, the ratchet and trailers. CI, a required check on every pull request, is what binds. - [lessloc FAQ: install, tokens, speed and supported agents](https://lessloc.org/guide/faq.md): lessloc keeps AI coding agents to the least code that does the job and still works. Answers on install, tokens, speed, privacy and supported agents. - [lessloc CLI reference: commands, flags and finding kinds](https://lessloc.org/guide/reference.md) (48 KB): Every command and flag, every finding kind, every file lessloc writes, and the environment variables it reads. Here lessloc stands for node ~/.lessloc/lessloc.mjs (Getting started). Run it with no command to print the usage. ## Guides - [Writing good functions with AI coding agents](https://lessloc.org/guides/functions.md): Shapes to avoid and shapes to prefer when AI coding agents write functions, each with a short Python example, and what lessloc does about it. - [Why your AI coding agent bill grows](https://lessloc.org/guides/costs.md): Where the money goes in an AI coding agent session, why every extra turn costs more than it looks, what lessloc itself costs, and which levers work. - [Making AI coding agents verify their work](https://lessloc.org/guides/verification.md): What counts as evidence that an AI coding agent's work is done, how agents run tests and how lessloc reads each way, and why it holds a turn at most once. - [Why less code: unneeded size does more harm than good](https://lessloc.org/why-less-code.md): AI coding agents bloat software in recurring, documented ways. Why unneeded size does more harm than good, and why agents need this more than people do. ## Patterns - [How AI coding agents bloat code: the pattern catalog](https://lessloc.org/patterns/index.md) (22 KB): Every way lessloc knows that coding agents bloat code, comments, files, folders, dependencies and tests, why each is a bad practice and what lessloc does. ## Code that already exists - [Reimplementing a helper the project already has](https://lessloc.org/patterns/reuse-helper.md): Reimplements a helper the project already has, under the same or another name. lessloc gives every session the rule: take what is already in the codebase before new code. Hints name existing code before the task and inside each subagent's prompt. lessloc catches it as "copy", "near-copy" and "similar-name". Why it is a bad practice: DRY (Hunt & Thomas, The Pragmatic Programmer). - [Copying a rule another function owns](https://lessloc.org/patterns/copied-rule.md): Copies a rule another function owns: a format, regex, SQL or date pattern. lessloc catches it as "repeated-literal". Why it is a bad practice: DRY. - [Keeping old and new versions side by side](https://lessloc.org/patterns/side-by-side.md): Keeps old and new versions side by side (parse_date_v2, fooFixed, legacyFoo, app_new.py). lessloc gives every session the rule: one implementation per rule. lessloc catches it as "versioned-copy", and as "junk-file" for files. Why it is a bad practice: DRY. - [Rebuilding what the standard library or framework has](https://lessloc.org/patterns/rebuilt-library.md): Rebuilding what the standard library or framework has. lessloc gives every session a rule against it and catches it as "simpler" and "reinvented". The working standard puts the standard library and the platform before new code. "simpler" catches hand-built counters, flag loops and range(len()). "reinvented" catches deep clone, UUID, debounce, slugify, CSV and flag parsing written by hand, and retry loops where the project already retries. Why it is a bad practice: Bloch, Effective Java Item 59: Know and use the libraries. - [Copy-pasted test cases instead of one parametrized test](https://lessloc.org/patterns/copied-tests.md): Copy-pasted test cases instead of one parametrized test. lessloc catches it as "copied-tests". Why it is a bad practice: Meszaros, xUnit Test Patterns: Test Code Duplication. - [A second library for a job an installed one already does](https://lessloc.org/patterns/second-library.md): Adds a second library for a job an installed one already does (dayjs beside moment). What lessloc does: "new-dependency" names the library that is already installed. Why it is a bad practice: One obvious way to do it (PEP 20). - [The same data shape in several layers (DTO, model, entity)](https://lessloc.org/patterns/duplicate-shapes.md): The same data shape in several layers (DTO, model, entity). What lessloc does: "copy" catches identical type bodies. Why it is a bad practice: DRY. - [The same CSS declarations under another selector](https://lessloc.org/patterns/css-copy.md): The same CSS declarations under another selector; the same long utility-class string again and again. lessloc catches it as "style-copy". Why it is a bad practice: DRY. ## Code nobody needs - [Options, flags, parameters or config for needs nobody named](https://lessloc.org/patterns/speculative-options.md): Options, flags, parameters or config for needs nobody named. lessloc gives every session a rule against it and catches it as "mode-flag". Why it is a bad practice: YAGNI (Extreme Programming). - [An interface or abstract class with one implementation](https://lessloc.org/patterns/single-impl.md): An interface, trait, protocol or abstract class with one implementation. lessloc catches it as "single-impl". Why it is a bad practice: Fowler: Speculative Generality (Collapse Hierarchy). - [Wrappers that only forward; barrel files that only re-export](https://lessloc.org/patterns/wrappers.md): Wrappers that only forward; barrel files that only re-export. lessloc catches it as "wrapper". Why it is a bad practice: Fowler: Middle Man, Lazy Element. - [A new function or import that nothing calls or tests](https://lessloc.org/patterns/unused.md): A new function or import that nothing calls or tests. lessloc catches it as "unused" (ruff adds unused variables). Why it is a bad practice: CWE-561 Dead Code. - [Obsolete code kept behind a guard or flag instead of deleted](https://lessloc.org/patterns/guarded-dead-code.md): Obsolete code kept behind a guard or flag instead of deleted. lessloc gives every session the rule: delete what the change makes dead. Why it is a bad practice: CWE-561. - [Tombstones](https://lessloc.org/patterns/tombstones.md): Tombstones: // removed X, "kept for backward compatibility", comments citing the task. lessloc catches it as "history". Why it is a bad practice: Clean Code C1 Inappropriate Information. - [Stubs and fake success](https://lessloc.org/patterns/stubs.md): Stubs and fake success. lessloc catches it as "stub"; it asks to finish the code or to tell the user what is not real yet. Why it is a bad practice: CWE-546 Suspicious Comment. - [Placeholders: # ... existing code ..., "your code here"](https://lessloc.org/patterns/placeholders.md): Placeholders: # ... existing code ..., "your code here". lessloc catches it as "placeholder" and refuses it before it lands. Why it is a bad practice: CWE-546. - [Commented-out code](https://lessloc.org/patterns/commented-out.md): Commented-out code. lessloc catches it as "commented-out" and refuses it before it lands. Why it is a bad practice: CWE-1085. - [Debug leftovers](https://lessloc.org/patterns/debug-leftovers.md): Debug leftovers: debugger, breakpoint(), print("here"), print(f"{x=}"), dbg!. lessloc catches it as "debug-leftover". It is judged at turn end, because mid-work the print may still be in use. Why it is a bad practice: CWE-489 Active Debug Code. - [A demo __main__ block or demo folder nobody asked for](https://lessloc.org/patterns/demo-code.md): A demo __main__ block or demo folder nobody asked for. lessloc catches it as "demo-code" and "new-folder". Why it is a bad practice: YAGNI. - [Hand-written boilerplate a language feature writes](https://lessloc.org/patterns/boilerplate.md): Hand-written boilerplate a language feature writes (an __init__ that only stores its parameters). lessloc catches it as "simpler". Why it is a bad practice: PEP 557 (dataclasses). - [A one-line helper used once](https://lessloc.org/patterns/single-use.md): A one-line helper used once. lessloc catches it as "single-use". Why it is a bad practice: Fowler: Inline Function. - [TODO and FIXME left behind](https://lessloc.org/patterns/todo.md): TODO and FIXME left behind: work the agent did not finish and did not mention. lessloc catches it as "todo"; it asks to finish the work, or to record known debt as shortcut: and tell the user. Why it is a bad practice: CWE-546 Suspicious Comment. ## Code longer than it needs to be - [Brute-force idioms](https://lessloc.org/patterns/brute-force.md): Brute-force idioms. lessloc catches it as "simpler", built in for Python, JS/TS, Go, Rust, Java and C#. ruff (in every hook) and clippy (in ci) go deeper. Why it is a bad practice: Sonar S1125, S1126, S1066, S1155. - [Hand-built counters and flag loops](https://lessloc.org/patterns/counters-and-flags.md): Hand-built counters and flag loops. lessloc catches it as "simpler". Why it is a bad practice: Fowler: Replace Loop with Pipeline. - [A catch that only rethrows](https://lessloc.org/patterns/catch-rethrow.md): A catch that only rethrows; logging an error and rethrowing it. lessloc catches it as "simpler". Why it is a bad practice: ESLint no-useless-catch. - [A promise wrapped in new Promise](https://lessloc.org/patterns/promise-wrap.md): A promise wrapped in new Promise. lessloc catches it as "simpler". Why it is a bad practice: Bluebird: the explicit-construction anti-pattern. - [Annotating types the compiler infers](https://lessloc.org/patterns/inferred-types.md): Annotating types the compiler infers. lessloc catches it as "simpler". Why it is a bad practice: typescript-eslint no-inferrable-types. - [A React Effect that only sets state from other values](https://lessloc.org/patterns/derived-effect.md): A React Effect that only sets state from other values. lessloc catches it as "simpler". Why it is a bad practice: React docs: "You Might Not Need an Effect". - [Functions with many parameters (8 or more)](https://lessloc.org/patterns/long-params.md): Functions with many parameters (8 or more). lessloc catches it as "long-params". Why it is a bad practice: CWE-1064 (ISO/IEC 5055 maintainability). - [Deep nesting](https://lessloc.org/patterns/deep-nesting.md): Deep nesting. lessloc catches it as "deep-nesting". Why it is a bad practice: CWE-1124 Excessively Deep Nesting. - [Long functions](https://lessloc.org/patterns/long-function.md): Long functions. lessloc catches it as "long-function". Why it is a bad practice: Fowler: Long Function. - [If-chains on literal values](https://lessloc.org/patterns/if-chain.md): If-chains on literal values. lessloc catches it as "if-chain". Why it is a bad practice: Fowler: Repeated Switches. - [A file that keeps growing](https://lessloc.org/patterns/swollen-file.md): A file that keeps growing. lessloc catches it as "swollen-file". Why it is a bad practice: CWE-1080 Source Code File with Excessive Number of Lines of Code. - [Reformatting lines the task did not change](https://lessloc.org/patterns/churn.md): Reformatting lines the task did not change. lessloc gives every session a rule against it and catches it as "churn". Why it is a bad practice: Google engineering practices: small, focused changes. - [Net growth past a budget](https://lessloc.org/patterns/net-growth.md): Net growth past a budget. lessloc catches it as "net-growth". Why it is a bad practice: Lehman's law of increasing complexity. - [Golfed code](https://lessloc.org/patterns/golfed-code.md): Golfed code: nested ternaries, comprehensions with several for clauses, lines over 160 characters. lessloc catches it as "clever" and "dense-lines". The counterweight to simpler, so shorter never means cryptic. Why it is a bad practice: Google Python Style Guide: "Optimize for readability, not conciseness". ## Errors and checks hidden - [Swallowed errors](https://lessloc.org/patterns/swallowed-error.md): Swallowed errors. lessloc catches it as "swallowed-error". Why it is a bad practice: CWE-390 Detection of Error Condition Without Action. - [Silenced checks](https://lessloc.org/patterns/silenced-checks.md): Silenced checks. lessloc catches it as "suppression". Why it is a bad practice: Clean Code G4 Overridden Safeties. - [Checks, fallbacks and catches for cases that cannot happen](https://lessloc.org/patterns/defensive.md): Checks, fallbacks and catches for cases that cannot happen. What lessloc does: "defensive" catches a null check of a value just created, a type re-checked inside private code and ?. on a fresh object. Why it is a bad practice: Meyer, "Applying Design by Contract" (IEEE Computer, 1992): "never in both… avoid redundant tests". - [Removing validation or error handling to shrink code](https://lessloc.org/patterns/removed-safeguard.md): Removing validation, error handling, logging or stated rules to shrink code. lessloc catches it as "removed-safeguard". Why it is a bad practice: lessloc's own "Never cut" list. ## Shortcuts that trade away safety - [SQL built from values instead of query parameters](https://lessloc.org/patterns/sql-from-values.md): SQL built from values with f-strings, concatenation or template strings. lessloc catches it as "unsafe": pass values as query parameters. Why it is a bad practice: CWE-89 SQL Injection. - [HTML built or escaped by hand](https://lessloc.org/patterns/html-by-hand.md): HTML built or escaped by hand: innerHTML from values, .replace('<', '<'). lessloc catches it as "unsafe": use textContent or the framework's rendering. Why it is a bad practice: CWE-79 Cross-site Scripting. - [Math.random() or random for tokens and passwords](https://lessloc.org/patterns/weak-randomness.md): Math.random() or random for tokens, passwords and session ids. lessloc catches it as "unsafe": crypto.randomUUID(), getRandomValues() or the secrets module. Why it is a bad practice: CWE-338 Use of Cryptographically Weak Pseudo-Random Number Generator. - [Fast hashes (MD5, SHA-1, SHA-256) for passwords](https://lessloc.org/patterns/password-hash.md): Fast hashes (MD5, SHA-1, SHA-256) for passwords. lessloc catches it as "unsafe": bcrypt, scrypt or argon2. Why it is a bad practice: CWE-916 Use of Password Hash With Insufficient Computational Effort. - [Certificate checks turned off](https://lessloc.org/patterns/tls-off.md): Certificate checks turned off: verify=False, rejectUnauthorized: false, InsecureSkipVerify: true. lessloc catches it as "unsafe". Why it is a bad practice: CWE-295 Improper Certificate Validation. - [Running text as code: eval, exec, new Function](https://lessloc.org/patterns/eval.md): Running text as code: eval, exec, new Function. lessloc catches it as "unsafe": parse the input instead. Why it is a bad practice: CWE-95 Eval Injection. ## Calls and packages that do not exist - [Another language's API](https://lessloc.org/patterns/wrong-language-api.md): Another language's API: null or === in Python, .strip(), None or len() in JavaScript, null in Go. lessloc catches it as "made-up-api". Why it is a bad practice: Sonar's quality profile for agent-written code targets "hallucinated APIs". - [Imports of packages no manifest declares](https://lessloc.org/patterns/undeclared-import.md): Imports of packages no manifest declares: a made-up name, or one never installed. lessloc catches it as "made-up-api": checked against every package.json, Python manifest, the standard library and the project's own modules. Why it is a bad practice: Spracklen et al., USENIX Security 2025 (5.2–21.7% of recommended packages do not exist). ## Comments and text - [Comments that narrate what the code does](https://lessloc.org/patterns/narration.md): Comments that narrate what the code does ("Loop through the users"). lessloc catches it as "narration". Comments that give a reason are kept. Why it is a bad practice: Clean Code C3 Redundant Comment and Noise Comments. - [Banners, dividers, closing-brace comments, emoji decoration](https://lessloc.org/patterns/decoration.md): Banners, dividers, closing-brace comments, emoji decoration. lessloc catches it as "narration". Why it is a bad practice: Clean Code: Position Markers, Closing Brace Comments. - [Docs that restate the name](https://lessloc.org/patterns/restating-docs.md): Docs that restate the name ("""Get the user.""", name: The name., @returns The result.). lessloc catches it as "narration". Why it is a bad practice: Clean Code: Mandated Comments. - [History and messages to the requester](https://lessloc.org/patterns/history.md): History and messages to the requester. lessloc catches it as "history". Why it is a bad practice: Clean Code C1 and Journal Comments: history belongs in source control. - [Comment blocks and comment-heavy changes](https://lessloc.org/patterns/comment-weight.md): Comment blocks and comment-heavy changes. lessloc catches it as "comment-block" and "comment-density". Why it is a bad practice: Clean Code: Too Much Information. - [Log lines that narrate each step](https://lessloc.org/patterns/log-chatter.md): Log lines that narrate each step ("Starting...", "Successfully saved"). lessloc catches it as "narration" (three or more in a file). Why it is a bad practice: Raymond, The Art of Unix Programming, Rule of Silence: "When a program has nothing surprising to say, it should say nothing". - [Docs that still name what a change removed](https://lessloc.org/patterns/stale-doc.md): Docs that still name what a change removed. lessloc catches it as "stale-doc". Why it is a bad practice: CWE-1116 Inaccurate Source Code Comments. - [Doc files and README growth nobody asked for](https://lessloc.org/patterns/unrequested-docs.md): Doc files nobody asked for, and READMEs that grow by 40 or more lines nobody asked for. lessloc catches it as "unrequested-doc". Why it is a bad practice: YAGNI. - [Docs deleted wholesale to shrink a change](https://lessloc.org/patterns/doc-removed.md): Docs deleted wholesale to shrink a change. lessloc catches it as "doc-removed". Why it is a bad practice: lessloc's own "Never cut" list. - [Always-loaded instructions that grow](https://lessloc.org/patterns/long-instructions.md): Always-loaded instructions that grow, or that include a directory tour. lessloc catches it as "long-instructions". Why it is a bad practice: arXiv:2602.11988 (context files with overviews raised cost by more than 20% and did not help). - [Commit messages that recap the diff file by file](https://lessloc.org/patterns/commit-recaps.md): Commit messages that recap the diff file by file. What lessloc does: The commit hook warns when a message lists the files the diff shows. Why it is a bad practice: DRY: the diff already lists every file. ## Files and folders - [CI workflows and Dockerfiles nobody asked for](https://lessloc.org/patterns/scaffolding.md): Dockerfiles, compose files, CI workflows and deploy configs nobody asked for. lessloc catches it as "unrequested-file". Why it is a bad practice: YAGNI. - [Tiny one-function files; file-per-concern splits](https://lessloc.org/patterns/tiny-files.md): Tiny one-function files; file-per-concern splits. lessloc catches it as "tiny-file" and "new-files". Why it is a bad practice: Ousterhout: Shallow Module. - [New folders for one or two files; layer trees for small apps](https://lessloc.org/patterns/one-file-folders.md): New folders for one or two files; layer trees for small apps. lessloc catches it as "new-folder". Framework route folders (Next.js, SvelteKit, Expo) are exempt. Why it is a bad practice: Ousterhout: shallow modules. - [Junk-drawer utils and helpers modules and folders](https://lessloc.org/patterns/junk-drawer.md): Junk-drawer utils and helpers modules and folders. lessloc catches it as "junk-drawer". Why it is a bad practice: Fowler: Mysterious Name. - [Vague names (process_data, handle)](https://lessloc.org/patterns/vague-name.md): Vague names (process_data, handle). lessloc catches it as "vague-name". Why it is a bad practice: Fowler: Mysterious Name. - [Moving or renaming files without a reason](https://lessloc.org/patterns/moved-files.md): Moving or renaming files without a reason. lessloc catches it as "moved-files". Why it is a bad practice: Google engineering practices: separate refactoring changes. - [Secrets: a committed .env, API keys, private keys](https://lessloc.org/patterns/secrets.md): Secrets: a committed .env, API keys, private keys. lessloc catches it as "secret". Why it is a bad practice: CWE-798 Use of Hard-coded Credentials. ## Tests and verification - [Behavior added with no test changed in the same change](https://lessloc.org/patterns/untested.md): Behavior added with no test changed in the same change. lessloc gives every session the rule: new behavior gets one focused test. lessloc catches it as "untested". It is not raised for refactors, for fixes that do not grow the code, or for projects without tests. Why it is a bad practice: Google engineering practices: tests ship with the change they test. - [Tests that assert nothing, or assert a constant](https://lessloc.org/patterns/empty-test.md): Tests that assert nothing, or assert a constant. lessloc catches it as "empty-test". Why it is a bad practice: Carr, TDD anti-patterns: The Liar. - [Deleted, skipped or force-passed tests](https://lessloc.org/patterns/weakened-tests.md): Deleted, skipped, focused (.only), exited (sys.exit(0)) or force-passed tests. lessloc catches it as "weakened-tests". Skips that depend on the environment are allowed. Why it is a bad practice: Clean Code T4 (an ignored test is a question). - [Test-only branches in production code](https://lessloc.org/patterns/test-logic.md): Test-only branches in production code; code shaped to pass a test. lessloc catches it as "test-logic". Why it is a bad practice: Meszaros: Test Logic in Production. - [Tests that mock the code they test](https://lessloc.org/patterns/mocked-subject.md): Tests that mock the code they test. lessloc catches it as "empty-test". Why it is a bad practice: Carr, TDD anti-patterns: The Mockery. - [Production code that branches on a value from the tests](https://lessloc.org/patterns/test-shaped.md): Production code that branches on a value copied from the tests. lessloc catches it as "test-logic". Why it is a bad practice: Anthropic system cards: special-casing tests. - [Stopping short: a requested function never written](https://lessloc.org/patterns/unaddressed.md): Stopping short: a function, option or flag the request asked for is never written. lessloc catches it as "unaddressed": names a request asks to exist ("add a --status flag", "implement export_csv()") are looked for in the final repository; one that appears nowhere holds the turn. A name the request only mentions, a test or a private helper the agent names itself never counts, and names joined by "or" are alternatives. Why it is a bad practice: ISO/IEC 25010 functional completeness. - [Stopping short: part of the problem left failing](https://lessloc.org/patterns/unfinished.md): Stopping short: leaving part of the reported problem failing, and saying so. lessloc catches it as "unfinished": in a turn that changed code, the agent's last reply is read sentence by sentence, with headings and lead-ins speaking for what is under them. An explicit marker that something is left broken ("Not fixed:", "Known limitation:") with a failure stated now, a neutral scope note ("Not changed:", "I left it alone") with a present-tense defect tied to the request (a name from its code, or the report's own example), the report's own example still failing, or the same problem suspected elsewhere and unchecked, holds the turn once, quoting the sentence. A fixed state, a cause, a condition, an offer, a tool's report or housekeeping never counts. Why it is a bad practice: ISO/IEC 25010 functional completeness. - [A refactor that changes existing tests](https://lessloc.org/patterns/refactor-tests.md): A refactor that changes existing tests. lessloc catches it as "refactor-tests". Why it is a bad practice: Fowler: refactoring preserves behavior. ## Benchmarks - [lessloc benchmarks on real projects](https://lessloc.org/benchmarks.md) (23 KB): lessloc against no tool on 117 real changes to three open-source projects, each judged by tests the agent never sees: up to 36% less code and 26% lower cost per task, with the same results.