Everything to put your files on a diet.
onadiet is a local, no-upload CLI and library that shrinks PDFs, images, SVGs, and whole folders under a size limit — on your machine, safe by default, with an honest measured receipt. This is the usage hub: install, every command and flag, the five plans, the four surfaces, and honest exit codes.
npm i -g onadiet
On npm now — pick how you want it.
The CLI ships as the unscoped onadiet package (binary diet, alias onadiet); the engine and adapters are scoped @onadiet/*. Published to npm at v0.1.0 — early (0.x), so the surface may still move. Requires Node >=22.
npm i -g onadiet
npx onadiet report.pdf
--to 5mb
npm i @onadiet/core
Build from source to hack on onadiet itself: clone the repo and run install → lint → typecheck → test → build with no manual setup — see the repository on GitHub.
One hero command, four sub-verbs.
The bare diet <path> is the hero — it slims a file or a folder. The sub-verbs cover everything around it. Every command speaks --json for scripts and agents (a stable object on stdout, logs on stderr).
| Command | What it does |
|---|---|
| diet <file> | Slim a file (the default command) → <name>.diet.<ext>. Default plan balanced. |
| diet <dir> | Slim a folder → <dir>.diet/, structure preserved; unknown files copied through. |
| diet weigh <path> | Step on the scale — what it weighs and what's heavy. No writes. |
| diet plan <path> | Dry-run — the same computation as slim, but writes nothing. |
| diet check <path> | CI gate — pass/fail a --max / --max-total budget with honest exit codes. |
| diet checkup | Is the kitchen stocked? Which local engines are available (a static report today). |
Dry-run is the plan verb — there is no --dry-run flag. There is no --version flag either; diet --help (-h) prints usage.
diet report.pdf
--to 5mb
diet ./photos
--to-each 500kb --out ./slim
diet weigh brochure.pdf
diet plan invoice.pdf
--to 5mb --json
diet check ./public
--max 2mb --max-total 25mb
diet checkup
The options, and exactly what they do.
Targets share one vocabulary — the slim verbs aim toward a size with the --to* family, and check fails a budget with --max*. Sizes accept decimal and binary units (5mb, 500kb, 2.5 MiB, bare bytes), case-insensitive.
| Flag(s) | Value | Means |
|---|---|---|
| --to · --under · --goal | size | Whole-file byte target (single file). On a folder → usage error. |
| --to-each | size | Folder: cap every recognized file at this size (per-file). |
| --to-total | size | Folder: whole-tree budget — sweeps for the gentlest plan that fits (so drop --plan). |
| --plan | cleanse | balanced | lowcarb | keto | crash | Quality plan (default balanced). |
| --format | keep | auto | jpeg | png | webp | avif | Image output format (default keep; ignored for PDFs). |
| --fast | — | Encode once at the plan's nominal quality; skip the size search. Cannot combine with a byte target. |
| --max-input | size | Skip / reject any input larger than this — a stat-based memory guard, before the file is read. |
| --timeout | ms | Abort a run longer than this (one deadline for the whole run); exits 2. |
| --concurrency · --jobs | n | auto | Folder parallelism (0/auto → min(cores−1, 8)). |
| --out | dir | Output directory (default: the sibling .diet path). |
| --force · --allow-signed | — | Proceed on a signed PDF and drop the quality floor (floor = 0). |
| --include · --exclude | globs | Folder: only / skip files matching comma-separated globs (exclude wins). |
| --json | — | Emit a stable JSON object on stdout (logs stay on stderr). |
For the everyday flags in prose see the CLI guide; for the exhaustive table with defaults, the API reference.
Pick how hard to cut — quality is a contract, not a guess.
--plan picks intent, not raw quality knobs. Every plan holds a measured perceptual floor (SSIM), so lowcarb stays visually lossless and only crash accepts visible loss. If a target can't be met above the floor, diet refuses honestly rather than returning garbage.
Honest caveat: cleanse is a no-op for PDFs and images today — lossless re-optimization isn't wired yet, so it keeps the original (only SVG cleanse does real, lossless work). The aggressive plans use only the in-house permissive sharp/mozjpeg path; copyleft engines are never bundled.
The same measured engine, wherever you need it.
onadiet is one honest engine behind four front doors — the CLI you type, an importable library for your hot path, a CI byte-budget gate, and (next) an agent Skill. Same rules everywhere: local, measured, keeps your original.
One command.
Point diet at a file and it writes a sibling .diet file — your original untouched, never a bigger output, written atomically.
diet report.pdf
--to 5mb
An engine for your code.
Import an adapter and slim bytes in / bytes out — no cross-call state, safe per request. The flagship onadiet also re-exports the whole @onadiet/core API, so no separate install is needed.
import { imageAdapter } from '@onadiet/image' // no cross-call state — safe to call per request const { output, outcome } = await imageAdapter.slim(bytes, { plan: 'balanced' }) output // a smaller file (Uint8Array) — measured ? save(output) : keep(outcome) // honest: kept original / infeasible // helpers come straight off the flagship, too: import { resolvePlan, parseSize } from 'onadiet'
Fail the build on bloat.
diet check weighs a path against a budget and writes nothing — exit 0 under budget, 1 over. Add --json so a step reads exactly what's over.
diet check ./assets
--max-total 10mb
The same binary, for agents.
A Claude Code Skill wrapping the CLI — no separate server. It's the next milestone (shipping with distribution: publish · Homebrew · Skill), not shipped yet. The intended loop, all local and deterministic:
# 1 · see the problem (size + causes) diet weigh big-deck.pdf --json # 2 · fix it diet big-deck.pdf --to 10mb --json # 3 · read the receipt → real saving, or honest "infeasible"
Honest codes so scripts and CI can branch.
The bin sets process.exitCode (it never calls process.exit()), so piped output is never truncated. In code, every engine failure is an OnadietError carrying a typed code — branch on the code, never on message strings.
| Exit | Meaning |
|---|---|
| 0 | Success — slim / weigh / plan OK, check PASS, folder budget fit. |
| 1 | Target or gate failed — infeasible target, check FAIL, folder --to-total overran. |
| 2 | Processing error — encrypted/unsupported input, aborted --timeout, read/write failure, --max-input exceeded. |
| 3 | Invalid usage — bad flags, unknown plan, invalid size, folder given a bare --to, check with no budget. |
| 4 | Unsafe operation blocked — signed PDF without --force, would overwrite the original, --out a symlink or inside the input tree. |
| Error code | When |
|---|---|
| INVALID_SIZE | Unparseable size / unknown unit; invalid byte count; bad floor/targetBytes. |
| UNKNOWN_PLAN | Plan name not one of the five diet plans. |
| UNSUPPORTED_INPUT | Not a supported image/PDF/SVG; undecodable bytes; animated/multi-frame image; no candidate format could encode. |
| SIGNED_PDF | PDF is signed and allowSigned isn't set (use --force). |
| ENCRYPTED_PDF | PDF is encrypted / password-protected. |
| TARGET_INFEASIBLE | Can't reach the target above the floor (loosen the floor / use keto/crash) or it's structurally impossible. |
| ABORTED | The signal aborted (cancellation / timeout) mid-slim — nothing written. |
| NOT_IMPLEMENTED | Reserved — declared and handled, but not thrown by any current path. |
Go deeper — the full guides on GitHub.
The reference above is the quick tour. Each guide below goes deep on one topic; the API reference is the canonical, evergreen public surface.
Getting started
Install to first run in 60 seconds, and the everyday commands.
CLI reference
Every command, target, option, exit code, and safety rule in prose.
API reference
The canonical public surface — CLI, library, config schema, error codes.
How PDFs are slimmed, what's touched, and the signed/encrypted guards.
Images
JPEG/PNG/WebP/AVIF re-encode, downscale, and format switching.
Folders
Per-file caps vs. whole-tree budgets, globs, structure, and manifests.
Performance
The --fast path, concurrency, memory, and the worker offload.
Prefer to read it all in one place? Browse the full docs tree on GitHub.
Weigh in.
On npm now — built and proven against real files. Install with
npm i -g onadiet.
npx onadiet report.pdf --to 5mb
