Today we’re releasing LimniFS v0.1.0 — a content-addressed, compressed, immutable filesystem image format written in 100% pure Rust.
LimniFS packs directory trees into a single .lim file with BLAKE3 content
addressing, per-content-class compression, and Merkle-rooted integrity. It’s
designed for archival, distribution, and cold storage — and it’s faster than
DwarFS.
Why another filesystem format?
Every existing format makes trade-offs we didn’t like:
- tar.gz / tar.xz: universal but no random access, no content addressing, no integrity beyond per-block CRC.
- SquashFS: mature but requires kernel support or FUSE, uses C code, and isn’t content-addressed.
- DwarFS: excellent ratio and speed but a C++ codebase with complex build dependencies, not suitable for air-gapped or fully-reproducible builds.
- OSTree / casync: designed for different use cases (system updates, incremental sync), not for standalone image distribution.
LimniFS is what we wanted: a format where identity is content (BLAKE3), compression is per-content-class (text gets ZSTD, binary gets LZ4, random gets stored), integrity is Merkle-rooted (one hash verifies everything), and the entire implementation is pure Rust with zero C dependencies.
What’s in v0.1.0
Seven codecs, all pure Rust
| Codec | Encode | Decode | Use case |
|---|---|---|---|
| Store | yes | yes | Incompressible data |
| LZ4 | yes | yes | Fast tier |
| ZSTD | yes (L1) | yes | General purpose |
| Brotli | yes (q11) | yes | Best text ratio |
| DEFLATE | yes (L6) | yes | Universal interop |
| Snappy | yes | yes | Data lake / OLAP |
| XZ/LZMA2 | decode-only | yes | Legacy archive decode |
Adding a codec is one new file + one register() call — the dispatch code
never changes. This is the open/closed principle applied to compression.
Performance vs DwarFS
Benchmarked against DwarFS 0.15.6 on a 440 MB text corpus:
| Operation | LimniFS | DwarFS | Ratio |
|---|---|---|---|
| Create | 0.62s (700 MB/s) | 1.00s | 1.6x faster |
| Extract | 0.59s (8500 files/s) | 1.37s | 2.3x faster |
| Image size | 8% smaller | baseline | — |
The parallel writer (rayon) and the seine content classifier are the key accelerators: chunks are classified and routed to the optimal codec in parallel, with BLAKE3’s rayon feature handling hashing.
Content-addressed drops
Every piece of content — every file chunk — is identified by
DropId = BLAKE3(plaintext). The codec, encryption, and erasure coding
are representations, never part of identity. This means:
- Identical chunks deduplicate automatically across files and images.
- Re-encoding with a different codec doesn’t change identity.
- Content integrity is verified by recomputing BLAKE3, not by trusting metadata.
Merkle-rooted manifest
The manifest’s root hash commits to the entire image. One signature
(Ed25519, behind the signing feature) verifies everything — the drop
store, the metadata tree, the slab index, the feature flags, the history.
Feature-flagged crypto
Each security capability is behind a Cargo feature flag, so the default build stays sovereign:
key-wrap: HPKE X25519 key wrap for sealed master keyssigning: Ed25519 manifest signinghttp: HTTP/S3/IPFS locators for remote slabsfuse: FUSE mount for read-only filesystem access
Erasure coding
Reed-Solomon systematic Vandermonde coding per slab, with offline repair. Lose some slabs? Reconstruct from the parity shards.
Architecture
┌─────────────────────────────────────────────────┐
│ .lim image │
│ ┌───────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Manifest │ │ Metadata │ │ Slabs │ │
│ │ (header, │ │ (Merkle │ │ (compressed │ │
│ │ flags, │ │ B-tree │ │ drops with │ │
│ │ Merkle │ │ directory│ │ BLAKE3 │ │
│ │ root) │ │ tree) │ │ identity) │ │
│ └───────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────┘
Three separately-versioned layers: drop store (content-addressed chunks), metadata (directory tree), manifest (signed root). No layer reaches into another’s bytes.
Pure Rust. Air-gapped safe.
#![forbid(unsafe_code)] workspace-wide. Zero C dependencies. The default
build compiles on any machine with a Rust toolchain — no system libraries,
no pkg-config, no autotools. This makes LimniFS suitable for:
- Air-gapped environments where C toolchains aren’t available
- Reproducible builds where every dependency must be auditable
- Embedded systems where binary size and build simplicity matter
- CI pipelines where cross-compilation targets lack C cross-compilers
Try it
cargo install limni
limni limn my-project/ my-project.lim
limni verify my-project.lim
limni ls my-project.lim
limni extract my-project.lim output/
Or build from source:
git clone https://github.com/limnifs/limnifs.git
cd limnifs && cargo build --release
What’s next
- omnizip-rs integration: replacing
ruzstdandlzma-rswith our own pure-Rust codec ports from omnizip/omnizip-rs. The omnizip-lzma decoder is already integrated; omnizip-zstd follows once the Huffman literals path is complete. - Writable images: epoch chains for content-addressed commits on top of
a base
.limimage. The epoch format is already implemented; replay and commit are next. - Dictionary compression: ZSTD dictionaries for small-file ratio.
- Full Brotli / DEFLATE / bzip2 / PPMd ports: expanding the codec portfolio via omnizip-rs.
Acknowledgments
LimniFS builds on ideas from many projects: DwarFS (content classification), ZSTD (frame format), Git (content addressing), OSTree (Merkle trees), and 7-Zip (LZMA). The omnizip Ruby project provided the algorithmic reference for our pure-Rust codec ports.
The format specification, Python reference reader, and conformance suite live at limnifs/spec and limnifs/limnifs-py.
LimniFS v0.1.0 is available now. 495 tests. CI green. Pure Rust. Try it.