The goal is substantial code simplification while preserving features. In grown codebases, custom implementations, boilerplate and supporting layers can often be replaced by capabilities already provided by the project's framework, libraries or language. Lesscode aims to help identify those opportunities and check the resulting changes.
The work is to move responsibility into suitable existing capabilities: use a framework shorthand, reuse a library operation, or express the same behavior with clearer idiomatic code. Success means less code and structure to maintain for the same features and public contracts. Moving custom code into another module, hiding it behind a wrapper, or dropping a feature does not establish that result. A replacement's dependencies, configuration and behavioral differences also count when judging whether it simplifies the project.
lesscode-core is one native binary. You give it source files you already
have, and it writes JSON receipts you can read in a review. The four commands
below read your sources without changing them, do not run your tests and make
no network or model requests.
| You want to know | Command | Works on |
|---|---|---|
| Is this rewrite a substantial reduction or a cosmetic one? | deconvolute density |
Rust, Java, TypeScript; Python by line count only |
| Where does this file write state, and does it use dynamic escape hatches? | deconvolute analyze |
Rust, Java, TypeScript |
| Are my Rust files still within their agreed size ceilings? | budgets |
Rust source trees |
| Can a push be stopped when those ceilings are broken? | deconvolute install-hook |
Any Git repository with a budgets file |
Read what is not checked before you rely on a result. The limits there come from running the released binary against this repository.
Releases carry prebuilt binaries for five targets. The scripts below download the archive for your machine from the latest release, verify its SHA-256 digest and copy the binary into a directory you own. They do not use administrator rights.
Linux and macOS:
curl -fsSL https://github.com/norandom/lesscode/releases/latest/download/install.sh | shWindows (PowerShell):
irm https://github.com/norandom/lesscode/releases/latest/download/install.ps1 | iexThen check the installation:
lesscode-core --version| Platform | Release archive | Default install directory |
|---|---|---|
| Linux x86_64 | lesscode-core-x86_64-unknown-linux-gnu.tar.gz |
~/.local/bin |
| Linux aarch64 | lesscode-core-aarch64-unknown-linux-gnu.tar.gz |
~/.local/bin |
| macOS Apple Silicon | lesscode-core-aarch64-apple-darwin.tar.gz |
~/.local/bin |
| macOS Intel | lesscode-core-x86_64-apple-darwin.tar.gz |
~/.local/bin |
| Windows x86_64 | lesscode-core-x86_64-pc-windows-msvc.zip |
%LOCALAPPDATA%\Programs\lesscode-core\bin |
Options, set as environment variables before running the script:
LESSCODE_VERSION=1.0.1installs that release instead of the latest.LESSCODE_INSTALL_DIR=/some/dirchanges the target directory.LESSCODE_ADD_TO_PATH=1(Windows only) appends the directory to your userPATH. Without it the script prints the directory and leavesPATHalone. On Linux and macOS the script never edits shell profiles.
The Linux binaries are built on Ubuntu 24.04 and need glibc 2.39 or newer. On
an older distribution, or on any other platform, build from source. You can
also download an archive and its .sha256 file by hand from the
releases page; each
archive contains the binary, the license and the third-party notices.
The install scripts check the SHA-256 digest of the download. From the release after 1.0.1 on, archives are also signed with the project's Ed25519 key and carry a GitHub provenance attestation; release signing shows how to verify them. Release 1.0.1 itself is not signed.
Use Rust 1.98.1 and a C compiler. native/README.md lists the per-platform prerequisites.
cargo +1.98.1 build --release --locked --manifest-path native/Cargo.tomlThe binary is written to native/target/release/lesscode-core
(lesscode-core.exe on Windows), or under CARGO_TARGET_DIR if you set it.
Pick a rewrite you can already review by hand: the file before and the file after. Keep the receipts outside your source tree.
lesscode-core deconvolute density --lang rust \
--baseline before/lifecycle.rs --candidate after/lifecycle.rs \
--out receipts/density.jsonRun against the lifecycle pair kept in this repository
(native/adapters/rust/baseline_lifecycle.rs and candidate_lifecycle.rs),
the receipt reads:
{
"receipt": "deconvolution-density-v1",
"baseline_lines": 248,
"candidate_lines": 148,
"line_reduction_pct": 40.32,
"baseline_stmts": 83,
"candidate_stmts": 70,
"stmt_reduction_pct": 15.66,
"passed": true,
"verdict": "pass"
}pass needs all four conditions: at least 20% and 50 fewer canonical lines,
and at least 10% and 10 fewer statements. Canonical lines exclude blank lines
and line comments. Anything less is reported as marginal with exit code 1. A
marginal verdict says the change is small; it does not say the change is wrong.
lesscode-core deconvolute analyze --lang typescript \
--source src/session.ts --out receipts/analysis.jsonThe receipt lists each state write as file:line and each dynamic form the
analyzer cannot follow (for example eval, reflection or unsafe) under
gaps. With --frame-spec FILE you supply a JSON file whose
allowed_write_sites lists the sites you allow (the file also needs
permitted_shell_locations and failure_invariants, which may be empty
lists), and any other site is reported under violations. Exit code 0 means no gaps and no
violations; 1 means at least one.
Write a budgets file that names every .rs file under the root you govern:
{
"files": [
{ "path": "lib.rs", "owner": "core team", "allocation": "public arithmetic API" }
]
}lesscode-core budgets --config complexity-budgets.json --root src --out receipts/budgets.jsonPaths are relative to --root. Each file defaults to 400 physical lines, 300
syntax units and 80 lines per function; set max_physical_lines,
max_logical_units or max_fn_lines per file to change that. A .rs file
that is not listed fails the check, as does a listed file that is missing or
over a ceiling. Exit code 0 means every file is within budget. This
repository's own file is native/complexity-budgets.json.
lesscode-core deconvolute install-hookThis writes .git/hooks/pre-push. On each push the hook looks for
complexity-budgets.json with a src directory at the repository root (or
native/complexity-budgets.json with native/src) and runs the budget check.
A violation blocks the push and names the files.
Know these three things before you install it:
- The hook calls
lesscode-coreby name. If the binary is not onPATH, every push fails withlesscode-core: not founduntil you fixPATHor delete.git/hooks/pre-push. LESSCODE_SKIP_HOOK=1 git pushskips the check for one push. It only works when the binary can be found.- In a repository without a budgets file the hook passes without checking anything.
install-hook refuses to replace an existing pre-push hook unless you pass
--force.
These limits were measured with the 1.0.1 binary on this repository and are recorded in R55.
- The commands do not run your tests and do not establish that a rewrite behaves the same. Behavioral evidence is yours to supply and review.
deconvolute analyze --lang pythonis not implemented. It returns an empty receipt with"passed": truefor any Python file. Do not read that as a clean result.deconvolute density --lang pythoncounts lines only; its statement fields repeat the line count.deconvolute mutateapplies operators written for the specimens used in this project's experiments. On other code it usually produces no mutants: it did so for 36 of the 38 Rust files innative/srcand for all 40 Python files tried. The command still exits 0 in that case, so checkmutants_generatedin the receipt. It is not yet a general mutation tool.- The budget check reads the files in your working tree, not the commits being pushed, and it covers Rust only.
- On
refactor/*anddeconvolute/*branches the hook prints a note about uncommitted changes. It performs no additional analysis on those branches. - Receipts written with
--outmay be placed anywhere, including inside your source tree, and an existing file is overwritten.
The research pipeline behind the published experiments (recorded behavior,
bounded finite-domain comparison, mutation scoring against real test suites,
model-driven regeneration) lives in the library and in the prepare, compare,
admission, surface and regenerate commands. Those need frozen manifests,
recorded evidence and per-specimen setup. Start from the
working paired example if you want to
use them; they are not a one-command workflow yet.
Use the first trial to find out whether the receipts help a review you already
do. Choose one module whose owner and regular reviewer are both willing, agree
beforehand what a marginal or failing receipt will mean, and compare the
receipt with the diff. The adoption guide describes that
trial, when to stop, and what to settle before turning a check into a gate.
The project keeps a dated research log with the experiments, the failed attempts and the revisions to its hypotheses.
- Research log: the latest decision first, then the record by date.
- Multi-language synthesis (R53): four specimens in Python, TypeScript, Java and Rust with 24% to 44% fewer lines, 100 compared cases each and no observed divergence.
- Self-application (R54): the native test suite on a clean clone and the pre-push hook tests.
- Released binary on this repository (R55): what an adopter's first session finds, including the gaps listed above.
- Proxy routing trial: a real replacement that removed 23 lines with 1,172 tests passing.
Those results describe specific specimens under finite checks. They are not a claim that the tool will reduce your code by a similar amount, and they are not equivalence proofs.
- Documentation index
- Native core: build, prerequisites, licenses
- Architecture and how to add a language
- CI and release workflows
- Agent skill for deconvolution
Native checks run on Linux x86_64 and aarch64, Windows x86_64, and macOS on
Intel and Apple Silicon. The earlier Python prototype (lesscode-baseline) was
retired at commit fd0b5b9; its guides remain under docs/ and are marked as
archived.
- Slice B, probabilistic turn refinement: wrap model-driven regeneration in
multi-turn
RefineandBestOfNcontrollers and compile prompts offline against a deterministic two-tier reward (StaticAssertionGate, thenRuntimeOracleGate). - Deterministic rewrites and synthesis: extend concolic extraction and bounded synthesis to more language semantics and idiomatic transformations.
Lesscode is licensed under the MIT License. Third-party dependencies and fixtures retain their own licenses and notices; see the native dependency inventory.
Releases are archived on Zenodo; the DOI badge above resolves to the latest archived release. Citation metadata is in CITATION.cff.