{"slug": "ratchets-a-rust-tool-that-polices-style-violations-with-a-flexible-budget", "title": "Ratchets: a Rust tool that polices style violations with a flexible budget", "summary": "Imbue AI released Ratchets, a Rust-based progressive lint enforcement tool that allows codebases to contain existing violations while preventing new ones through a budgeted, ratcheting mechanism. The tool supports region-based budgets, regex and AST rules, and agent-friendly JSONL output, aiming to monotonically decrease technical debt.", "body_md": "Ratchets is a progressive lint enforcement tool that allows codebases to contain existing violations while preventing new ones. Unlike traditional linters that enforce binary pass/fail, Ratchets permits a budgeted number of violations per rule per region. These budgets can only decrease over time (the \"ratchet\" mechanism), ensuring technical debt monotonically decreases.\n\n**Progressive enforcement**: Allow existing violations while preventing new ones** Region-based budgets**: Set different limits for different parts of your codebase** Regex and AST rules**: Match patterns via text or tree-sitter queries** Agent-friendly**: JSONL output, deterministic results, clear exit codes** Fast**: Parallel execution, lazy parser loading, Rust performance\n\nInstall from source using the installation script:\n\n```\ncurl -sSf https://raw.githubusercontent.com/imbue-ai/ratchets/main/install.sh | sh\n```\n\nThis will automatically build and install ratchets to `~/.cargo/bin/`\n\n. Requires Rust/Cargo to be installed.\n\nInitialize Ratchets in your repository:\n\n```\nratchets init\n```\n\nThis creates:\n\n`ratchets.toml`\n\n— Configuration file`ratchet-counts.toml`\n\n— Violation budgets`ratchets/`\n\n— Directory for custom rules\n\nOptionally, drop a `.ratchetignore`\n\nfile at any depth in the tree to exclude paths from ratchet enforcement. Syntax matches `.gitignore`\n\n(per-directory, nested files compose, negation supported with `!`\n\n); these files are checked in alongside source.\n\nRun checks:\n\n```\nratchets check\n```\n\nVerify that violations are within budget:\n\n```\nratchets check                    # Check all files\nratchets check --format jsonl     # Machine-readable output\nratchets check src/               # Check specific path\nratchets check --since main       # Only files changed since the `main` ref\n```\n\n`--since <REF>`\n\nshells out to `git diff <REF> --name-only`\n\nand intersects the\nresult with the file walker's output. Include/exclude/gitignore filters still\napply, and files deleted relative to `<REF>`\n\nare skipped silently. The command\nexits with code 2 if `<REF>`\n\nis unknown or the current directory is not inside\na git repository.\n\nIncrease the violation budget (requires justification in commit message):\n\n```\nratchets bump no-unwrap --region src/legacy --count 20\nratchets bump no-unwrap --region src/legacy  # Auto-detect current count\n```\n\nReduce budgets to match current violation counts:\n\n```\nratchets tighten                    # Tighten all rules\nratchets tighten no-unwrap          # Tighten specific rule\nratchets tighten --region src/      # Tighten specific region\n```\n\nList all enabled rules and their status:\n\n```\nratchets list\nratchets list --format jsonl\n```\n\nRatchets uses an explicit opt-in model: rules only fire when listed in\n`enabled_ratchets`\n\n(directly or via a `$set-name`\n\nreference). Anything in\n`disabled_ratchets`\n\nis subtracted from the resolved enabled set — disabled\nalways wins.\n\n```\nenabled_ratchets = [\"$common-starter\", \"no-unwrap\"]\ndisabled_ratchets = [\"no-fixme-comments\"]\n\n[ratchets]\nversion = \"2\"\nlanguages = [\"rust\", \"typescript\"]\ninclude = [\"src/**\", \"tests/**\"]\nexclude = [\"**/generated/**\"]\n\n# Optional per-rule settings (severity, regions). Entries here do NOT\n# enable rules; enablement is governed by enabled_ratchets above.\n[rules]\nno-todo-comments = { severity = \"warning\" }\n\n[output]\nformat = \"human\"\n```\n\n`\"rule-id\"`\n\n— enables (or disables) a single rule by ID.`\"$set-name\"`\n\n— references a**ratchet-set**: a curated bundle of rule IDs. Sets can compose other sets via`$other-set`\n\ninside their own`rules`\n\narray; cycle-aware resolution catches accidental loops.- The\n`@`\n\nsigil is unchanged — it still refers to entries in the existing`[patterns]`\n\ntable for glob references.\n\nThis binary ships a single starter set:\n\n— the language-agnostic curated default. Today's members:`$common-starter`\n\n`no-todo-comments`\n\n,`no-fixme-comments`\n\n. Membership criterion (\"stable, broadly applicable, no framework-specific opinions\") is documented at the top of`builtin-ratchets/sets/common-starter.toml`\n\n.\n\nPer-language starter sets (`$python-starter`\n\n, `$rust-starter`\n\n,\n`$typescript-starter`\n\n) will land in follow-up MRs — their curation is\nits own review topic.\n\nDrop your own set files under `ratchets/sets/*.toml`\n\n. User-defined sets\noverride embedded sets with the same ID, mirroring how `ratchets/regex/`\n\nand `ratchets/ast/`\n\noverride embedded rules. A set file looks like:\n\n```\n[set]\nid = \"house-style\"\ndescription = \"Rules that match our coding conventions\"\nrules = [\"$common-starter\", \"no-unwrap\"]\n```\n\n`enabled_ratchets = [\"$house-style\"]`\n\nthen enables the union.\n\n```\n[no-unwrap]\n\".\" = 0\n\"src/legacy\" = 15\n\"tests\" = 50\n\n[no-todo-comments]\n\"src\" = 23\n```\n\nRegions are explicitly configured directory paths. Files in unconfigured subdirectories count toward their nearest configured parent region. Regions are scoped per-rule.\n\nCounts for rules no longer in the resolved enabled set are kept dormant\n(no cleanup). `ratchets tighten`\n\nemits a stderr warning naming each\norphan so you can re-enable the rule later without losing the count.\n\nRatchets provides a merge driver that resolves conflicts by taking the minimum count:\n\n```\n# .gitattributes\nratchet-counts.toml merge=ratchets\n\n# .git/config\n[merge \"ratchets\"]\n    name = Ratchets counts merge driver (minimum wins)\n    driver = ratchets merge-driver %O %A %B\nbash\n#!/bin/sh\nratchets check || exit 1\n```\n\n| Code | Meaning |\n|---|---|\n| 0 | All rules within budget |\n| 1 | At least one rule exceeded budget |\n| 2 | Configuration or usage error |\n| 3 | Parse error in source file |\n\n[DESIGN.md](/imbue-ai/ratchets/blob/main/DESIGN.md)— Design specification and rationale[ARCHITECTURE.md](/imbue-ai/ratchets/blob/main/ARCHITECTURE.md)— Implementation architecture\n\nThe ratchet concept was originally described by qntm: [https://qntm.org/ratchet](https://qntm.org/ratchet)", "url": "https://wpnews.pro/news/ratchets-a-rust-tool-that-polices-style-violations-with-a-flexible-budget", "canonical_source": "https://github.com/imbue-ai/ratchets", "published_at": "2026-06-16 00:35:01+00:00", "updated_at": "2026-06-16 00:49:10.181173+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Ratchets", "Imbue AI", "Rust", "Cargo"], "alternates": {"html": "https://wpnews.pro/news/ratchets-a-rust-tool-that-polices-style-violations-with-a-flexible-budget", "markdown": "https://wpnews.pro/news/ratchets-a-rust-tool-that-polices-style-violations-with-a-flexible-budget.md", "text": "https://wpnews.pro/news/ratchets-a-rust-tool-that-polices-style-violations-with-a-flexible-budget.txt", "jsonld": "https://wpnews.pro/news/ratchets-a-rust-tool-that-polices-style-violations-with-a-flexible-budget.jsonld"}}