compressr
App New
Model conversion and quantization with no Python: reads SafeTensors, GGUF, TCF and PyTorch state dicts, writes SafeTensors, GGUF and TCF, and quantizes to Q2_K through Q8_0 and IQ4 formats, including Q4_K_M mixes. GPTQ, AWQ, NF4, FP8, EXL2 and ONNX input are not implemented.
- Downloads
- 23
- Dependents
- Not applicable
- Stars
- 0
- Forks
- 0
- Contributors
- 1
- Commits
- 63
- Latest release
- 0.2.1 ·
About
GGUF quantization and model conversion for LLM checkpoints, in Rust.
Converts SafeTensors, GGUF, TCF, and PyTorch checkpoints to GGUF, TCF, or SafeTensors, and quantizes to GGUF block formats. It reads one tensor at a time.
Status · Options · Example · Contributing
compressr is a Rust CLI and library. It converts LLM checkpoints between formats, casts their element type, and quantizes them into GGUF block formats. It writes the GGUF header that llama.cpp's convert_hf_to_gguf.py writes, for the architectures listed under GGUF headers.
- Language: the conversion path is Rust. It needs no Python. The optional
pythonfeature builds a PyO3 module that exports__version__only. - Hardware: CPU only. There is no GPU path.
- Built on: boostr holds the kernels and block layouts. compressr handles file I/O, planning, and the command line.
- Used for: models that blazr serves.
- Not supported yet: GPTQ, AWQ, EXL2, NF4, FP8, ONNX input, sharded PyTorch input, and PyTorch F16 and BF16 tensors. See Status.
Status
Implemented:
Read the full README
| Capability | Detail |
|---|---|
| SafeTensors input | Single file, or sharded via model.safetensors.index.json |
| GGUF input | Read back for re-conversion |
| TCF input | Read back, verified and decoded, through boostr's reader. Used for info and for conversion to another format |
| PyTorch input | One .pt, .pth, or .bin state dict with F32, F64, I32, or I64 tensors, as a file or as pytorch_model.bin in a directory. Sharded PyTorch and ONNX input are refused |
| Explicit input format | ConversionConfig::input_format skips auto-detection. compressr checks the input's content against it and errors on a mismatch |
| VoxCPM2 companion | A safetensors directory with architecture voxcpm2 folds its audio VAE into the output under vae.. Float tensors are stored as F32 |
| SafeTensors output | Sharded at --max-shard-size, with a matching index |
| GGUF output | GGUF v3, one self-contained file |
| GGUF header from a HuggingFace checkpoint | Hyperparameters, RoPE keys, and tokenizer metadata under llama.cpp's key names. See GGUF headers |
| TCF output | TCF v1, one self-contained file. Takes every --quantization method and mix |
| dtype cast | F32, F16, BF16, round-to-nearest-even. A block-quantized input tensor is decoded first |
| GGUF quantization | Q4_0, Q4_1, Q8_0, Q2_K, Q3_K, Q4_K, Q5_K, Q6_K, IQ4_NL, IQ4_XS |
| GGUF mixed precision | Q4_K_S, Q4_K_M, Q5_K_S, Q5_K_M, using llama.cpp's per-tensor allocation |
| Measured allocation | --sensitivity ranks mix promotions by measured task damage per element |
| Importance matrix | --imatrix weights quantizer choices by calibration activations. Off by default |
| Lowbit repack | pq2_0 from a PTQ1_0 GGUF, ptq1_0 from a PQ2_0 GGUF. Codes and scales move between layouts. No value rounds |
| GGUF header carry | A GGUF input's key-value pairs are written whole into a GGUF output |
| Sidecar copying | Tokenizer and config files follow the weights |
| Conversion report | The format of every tensor, and the measured bits per weight |
Roadmap. Each capability below has an enum variant. compressr refuses each one before it creates an output file:
| Capability | What is missing |
|---|---|
| GPTQ, AWQ | Calibration, plus the qweight/scales/qzeros/g_idx tensor layout |
| NF4, FP8 | An on-disk home for the side-band scales the packed payload omits |
| EXL2 | The whole format driver |
| ONNX input | The .onnx reader |
| Sharded PyTorch | A pytorch_model.bin.index.json walk. One .bin per model today |
| PyTorch F16, BF16 | boostr's .pt reader decodes F32, F64, I32, and I64 only |
| Python API | The PyO3 module exports __version__ only |
| Triple-buffered I/O | A prefetch, compute, and write pipeline. Reads and writes are serial |
| Parallel shard I/O | Reads and writes are sequential |
| Q2_K/Q3_K and IQ mixes, other I-quants | Mix rules for Q2_K and Q3_K, and boostr writers for IQ2, IQ3, IQ1 formats. The mixes q2_k_s, q3_k_s, q3_k_m, and q3_k_l are refused by name. Flat q2_k and q3_k are written |
The optimize subcommand takes --method only. It always errors and writes no file. Every method it names (GPTQ, AWQ, EXL2, NF4, FP8) is on the roadmap. A flat GGUF method passed to it is refused with the convert command that writes it.
SafeTensors output is never quantized. Block quantization writes GGUF, or TCF with --format tcf.
TCF comes from a full-precision checkpoint only. A GGUF or TCF input is refused for TCF output.
Quick Start
compressr needs a Rust toolchain. Cargo.toml takes boostr from crates.io. A checkout beside unreleased sibling crates needs the local build overrides first. The file is gitignored.
cp .cargo/config.toml.example .cargo/config.toml
cargo install --path .
compressr runs every boostr kernel on the CPU. It has no GPU path.
Convert a checkpoint to a quantized GGUF file:
compressr convert ./llama-3-8b --format gguf --quantization q4_k_m
Cast a checkpoint to BF16 SafeTensors:
compressr convert ./llama-3-8b --format safetensors --dtype bf16
Inspect a checkpoint:
compressr info ./llama-3-8b # format, tensor count, size, metadata
compressr info ./llama-3-8b --verbose # one line per tensor
compressr info ./llama-3-8b --summary # tensor count and size only
Usage
Quantization
--quantization takes these flat formats: q4_0, q4_1, q8_0, q2_k, q3_k, q4_k, q5_k, q6_k, iq4_nl, and iq4_xs. It also takes the lowbit repack names pq2_0 and ptq1_0.
A mixed-precision name assigns different GGUF block formats to different tensors. The mix names are q4_k_s, q4_k_m, q5_k_s, and q5_k_m. The mix reproduces llama.cpp's per-tensor allocation by role and layer.
--quantization and --dtype are mutually exclusive. Quantization already fixes the stored representation.
Measured sensitivity and importance matrices
--sensitivity FILE reads measured task deltas as JSON lines. It requires a mixed-precision --quantization and --format gguf or --format tcf. The promotions of the mix are ranked by measured damage per element. They spend the same bytes that llama.cpp's rules spend on the checkpoint. Tensors whose rows are not a whole number of 256-element super-blocks cannot be promoted. compressr counts and reports them.
--imatrix FILE reads an importance matrix from boostr's imatrix example. It weights each quantizer choice by the mean squared activation of each input column. A conversion without the flag writes the same bytes it always wrote. --imatrix works with --format gguf or --format tcf, and with K-quants, iq4_nl, iq4_xs, and K-quant mixes. A tensor the matrix does not measure is quantized without weights.
compressr convert ./llama-3-8b --format tcf --quantization q4_k_m --sensitivity llama.sens.jsonl
compressr convert ./llama-3-8b --format gguf --quantization q4_k_m --imatrix llama.imatrix
Lowbit repack
compressr convert model-PTQ1_0.gguf --format gguf --quantization pq2_0
compressr convert model-PQ2_0.gguf --format gguf --quantization ptq1_0
PTQ1_0 and PQ2_0 store the same ternary codes in two block layouts. A repack moves the codes and scales of each source tensor, and it rounds nothing. Tensors already in the target format, float norms, and other types pass through. A PQ2_0 block that holds code 3 has no trit, so ptq1_0 refuses it. The error names the tensor and block. Neither format is quantized from float weights. A SafeTensors or F16 input is refused.
Output shards
compressr convert ./llama-3-8b --format safetensors --dtype bf16 --max-shard-size 2GB
compressr convert ./llama-3-8b --format safetensors --dtype bf16 --max-shard-size none
SafeTensors output over the limit becomes model-00001-of-000NN.safetensors shards plus model.safetensors.index.json. Output under the limit stays one model.safetensors with no index. A tensor is never split, so a tensor larger than the limit gets a shard of its own. The flag takes a byte count, a decimal suffix (5GB, 500MB), or a binary suffix (1GiB, 512MiB). The default 5GB matches HuggingFace. GGUF ignores the flag.
Input resolution
A directory with a model.safetensors.index.json loads exactly the shards that index names. Other .safetensors files beside them, such as a LoRA adapter or an earlier conversion's output, are ignored.
A directory with shards and no index loads every .safetensors file in name order.
GGUF headers from HuggingFace checkpoints
For a HuggingFace checkpoint, compressr writes the GGUF header that convert_hf_to_gguf.py writes. The architecture comes from model_type in config.json, then architecture, then the first entry of architectures. Pass --arch when the checkpoint names none.
Architecture (model_type) | general.architecture | Tensor names |
|---|---|---|
llama, mistral, mixtral | llama | llama.cpp's, Q/K rows reordered |
qwen2, qwen3 | as named | llama.cpp's |
qwen2_moe, qwen3_moe, gemma, gemma2, gemma3, phi3 | qwen2moe, qwen3moe, or as named | HuggingFace's |
- Hyperparameters: context length, embedding length, block count, feed-forward length, head counts, and the norm epsilon. It also writes
.rope.*keys with scaling, expert counts, and key and value lengths whenhead_dimis stated. A key whoseconfig.jsonfield is absent is omitted. - RoPE tensors: llama3 scaling writes
rope_freqs.weight. LongRoPE writesrope_factors_long.weightandrope_factors_short.weight. - Tokenizer:
tokenizer.modelgivestokenizer.ggml.model = "llama". A byte-level BPEtokenizer.jsongives"gpt2", with merges and atokenizer.ggml.prename from llama.cpp's fingerprint table. An unknown fingerprint omitspreand logs a warning. Special ids, add-token flags, andtokenizer.chat_templatefollow llama.cpp. - Q/K order: llama.cpp's
llamaarchitecture rotates adjacent pairs. compressr reordersq_projandk_projrows to match. boostr's GGUF loader restores them. - HuggingFace names: the architectures in the last row keep HuggingFace tensor names. llama.cpp's converter changes their values: Gemma norms, Phi-3 fused projections, and merged MoE experts. llama.cpp cannot load those files.
Options
compressr convert <INPUT>
| Flag | Default | Effect |
|---|---|---|
--format | required | gguf, safetensors, or tcf. Other values are roadmap items and fail |
-o, --output | derived from input | Output file, or checkpoint directory. Defaults to <INPUT>.gguf or <INPUT>-<dtype> |
--quantization | none | GGUF block format or mix. Repack name for a lowbit GGUF. Not used with --dtype |
--dtype | none | Cast target: f32, f16, or bf16 |
--max-shard-size | 5GB | Shard limit for SafeTensors output, or none |
--sensitivity | none | Measured sensitivity JSON lines. Needs a mixed-precision quantization |
--imatrix | none | Importance matrix from boostr's imatrix example |
--arch | from config.json | Value written to GGUF general.architecture |
-v, --verbose | off | Log every tensor as it is processed |
compressr info <MODEL>
| Flag | Effect |
|---|---|
-v, --verbose | Print one line per tensor |
-s, --summary | Print tensor count and size only |
Memory
Opening a model reads its headers only. Each tensor is then read into an owned buffer, converted, written, and dropped before the next one starts. Peak resident memory is roughly the largest tensor plus its converted copy. It depends on the widest layer, not on the model size.
The loader copies tensor bytes out of the file. It does not memory-map them.
Architecture
compressr is a thin layer over boostr. Every quantization kernel and block layout lives in boostr, behind its Runtime trait.
| Module | Responsibility |
|---|---|
src/loader/ | Format detection, header reading, one-tensor-at-a-time reads |
src/policy/ | Per-tensor plan: quantize, fall back to F32, or pass through |
src/quantization/ | Dispatch into boostr's kernels |
src/cast/ | Element-type conversion with round-to-nearest-even |
src/formats/ | GGUF, SafeTensors, and TCF writers, sharding, sidecar copying |
src/importance/ | Importance matrix input for the quantizer |
src/python/ | PyO3 module (python feature) |
A tensor that cannot be block-quantized is stored as F32 instead of failing the run. A rank-1 tensor has no row to pack blocks along. A row length that is not a multiple of the block size cannot be packed. llama.cpp makes the same choice. The conversion report counts both cases.
Contributing
Contributions are welcome. See CONTRIBUTING.md for conventions and checks.
Questions and design discussion happen on Discord.
License
Licensed under Apache-2.0. See LICENSE.
Compatibility
- Runs on
- GPU support unknown
What shows it
- no dependency or feature matches a backend row
- Native code
- None found
- No native code found
- Python bindings
- Has Python bindings
- compressr needs Python only with feature python
- License
- Apache-2.0
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
Model conversion and quantization with no Python: reads SafeTensors, GGUF, TCF and PyTorch state dicts, writes SafeTensors, GGUF and TCF, and quantizes to Q2_K through Q8_0 and IQ4 formats, including Q4_K_M mixes. GPTQ, AWQ, NF4, FP8, EXL2 and ONNX input are not implemented. Python bindings |
23 downloads over 30 days | Not applicable | 0 | 0.2.1 | GPU support unknown | No native code found | Apache-2.0 |
|
safetensors Featured
Provides functions to read and write safetensors which aim to be safer than their PyTorch counterpart. |
5,486,837 downloads over 30 days | 531 | 3,943 | 0.8.0 | GPU support unknown | No native code found | Apache-2.0 |
|
onnx-extractor Listed
Minimal ONNX model loader for extracting weights, tensors, operations, and graph structure |
3,975 downloads over 30 days | 4 | 6 | 0.5.2 | GPU support unknown | No native code found | MIT |
|
gguf Listed
GGUF file parser |
2,472 downloads over 30 days | 4 | 25 | 0.1.8 | GPU support unknown | No native code found | MIT |
|
onnx-rs Listed
Zero-dependency ONNX model parser in Rust |
453 downloads over 30 days | 5 | 6 | 0.1.3 | GPU support unknown | No native code found | MIT |
|
One backbone, many specialists. CMF is a self-describing, memory-mappable single-file format and a dependency-free runtime for quantized LLMs — zero-copy execution on CPU or GPU (Vulkan · Metal · DX12) that overlays task-specialized skills onto one shared model, with no per-model duplication. |
24 binary downloads per release | Not applicable | 52 | Not measured | Not measured | Apache-2.0 |
All projects in Datasets and model formatsAll projects in Run and serve models
Why NewIts first release on 1 Nov 2026 is under 180 days old.
The check tests the Featured gates once the first release passes this age limit.
What else the check found
- The last activity is on 6 Nov 2026, 3 days ago. The rules expect an update within 365 days. Dormancy rule
Check notes
- the latest release was packaged from a dirty working tree
Exact rules: New. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: app: E = 365 daysdormancy: last activity 2026-11-06, 3 days ago, E = 365: activenew: new: first release 2026-11-01 is under 180 days old
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: written for the catalogue
- crates.io database dump, fetched
- GitHub releases, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption0 binary downloads per release4 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | Not measured | Yes | ||
| New dependents (365 days) | Not measured | Yes | ||
| Peak active dependents | Not measured | Yes | ||
| Active dependents as a share of the peak | Not measured | Yes | ||
| Binary downloads per release | 0 | GitHub releases | Yes |
MaintenanceLatest human commit: 3 days ago4 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-11-06 | GitHub repository | Yes | |
| Latest release | 2026-11-06 | GitHub releases | Yes | |
| First release | 2026-11-01 | crates.io database dump | Yes | |
| Latest version | 0.2.1 | crates.io database dump | No | |
| Days the oldest outside issue waits for a reply | 0 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 0 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | No | |
| Published docs | Not measured | Yes | ||
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityNot measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | Not measured | Yes | ||
| RustSec unmaintained advisory | Not measured | Yes | ||
| Deprecation notice | Not measured | Yes | ||
| Deprecated requirement | Not measured | Yes |
Distribution2 releases, 23 downloads over 30 days6 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 2 | crates.io database dump | No | |
| Downloads over 30 days | 23 | crates.io database dump | No | |
| Binary downloads over the last 3 releases | 0 | GitHub releases | Yes | |
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | Not measured | Yes | ||
| Crate deleted from crates.io | Not measured | Yes |
Repository0 stars, 0 forks, 1 contributors, 63 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 0 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 0 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 1 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 63 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | Apache-2.0 | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | GPU support unknown | crates.io database dump | No | |
| What shows each backend | no dependency or feature matches a backend row | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | No native code found | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | Has Python bindings: compressr needs Python only with feature python | crates.io database dump | No | |
| Crates that depend on a listed crate directly | Not measured | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.