Skip to main content

Moonclip

Stop losing checkpoints. Start training fearlessly.

Moonclip is a checkpoint engine for ML training, written in Rust with Python bindings. It tracks per-tensor deltas, skips unchanged weights entirely, and compresses the rest, so a save blocks the training loop for tens of milliseconds and the checkpoint on disk is about half the size.

Against torch.save on dense pre-training — the least favourable case, where Adam changes every parameter at every step and there is nothing to skip — that is 1.6-3.0× faster and 1.9× smaller. The gap widens on fine-tuning, LoRA and adapters, where most tensors are identical between two checkpoints.

A moonclip is the ring that holds a full circle of rounds so a revolver reloads in one motion, instead of one chamber at a time. That is the idea here: your whole training state goes down and comes back in a single movement, not tensor by tensor.

Three lines in your training loop. That's it.

from moonclip import CheckpointManager

mgr = CheckpointManager("./checkpoints", save_dtype="bf16")
start_step = mgr.resume(model=model, optimizer=optimizer, scheduler=scheduler)

for step in range(start_step, 100_000):
    loss = train_step(model, batch)

    if step % 500 == 0:
        mgr.save(step=step, model=model, optimizer=optimizer,
                 metadata={"loss": f"{loss:.4f}"})

Why

Every ML engineer has lost a training run. The spot instance dies, the node crashes, the disk fills up — and your last checkpoint was 2 hours ago. So you save more often, but now checkpointing is the bottleneck: a 3B model in bf16 is ~5.5 GB per save, and torch.save blocks your training loop every time.

Moonclip fixes this at the storage layer. Instead of dumping the full state dict every time, it diffs against the previous checkpoint at the tensor level: unchanged tensors → zero I/O, changed tensors → XOR delta + zstd compression. The result is saves that are both faster and smaller.

Inspired by DECK (Meta, PVLDB 2025).

Benchmarks

MiniGPT 41.7M params, fp32 model + full AdamW optimizer state (~540 MB per checkpoint), 10 saves, CPU (bench/benchmark_checkpoints.py):

Moonclip safetensors*
Avg save (training loop blocked) 35 ms 316 ms
Total for 10 saves 0.35 s 3.2 s
Load 0.44 s 0.03 s

* safetensors saves the model only — no optimizer state, ~3× less data per checkpoint.

Saves are asynchronous by default: save() returns as soon as the tensor data has been copied, while hashing, delta detection, zstd compression and the disk write run on a background thread and overlap with training. Call flush() when you need the checkpoint on disk — as of 0.0.6 that means fsynced, not merely written; loads and list_snapshots() wait for pending saves automatically. Pass async_save=False for fully synchronous saves.

Resume integrity verified: max weight diff 0.0 after save → load.

Features

  • Async background saves — save() returns in milliseconds; compression and I/O overlap with training (disable with async_save=False)
  • Per-tensor delta tracking — unchanged tensors are skipped entirely (zero I/O), changed tensors use XOR delta compression; a cheap sampled density check bails out early when everything changed
  • Parallel zstd — large tensors are compressed/decompressed as concatenated zstd frames across all cores
  • Rust-native dtype casting — save_dtype="bf16" casts fp32→bf16 in parallel Rust threads before compression, auto-uncasts on load
  • 4KB page-aligned writes — eliminates SSD write amplification, extends drive lifespan
  • Rank-aware distributed saves — each rank saves its own shard independently, auto-detects torchrun env vars
  • Hierarchical delta merging — background thread consolidates deltas to keep load times fast
  • S3 backend — local SSD as primary (fast), batched sync to S3/MinIO/R2 in background
  • xxHash3-128 integrity checks — every tensor verified on read, corruption detected immediately
  • Auto-resume — mgr.resume() loads the latest checkpoint if it exists, returns the next step

Installation

pip install moonclip

Wheels are built for Linux x86_64 (manylinux_2_28), CPython 3.9-3.14 — the platform training actually runs on. No Rust toolchain needed there; the extension is compiled. What changed between versions is in CHANGELOG.md.

On any other platform (Windows, macOS, aarch64) pip finds no wheel and stops. Build it yourself instead, which needs a Rust toolchain:

pip install git+https://codeberg.org/JHNMACHINE/moonclip.git

# On a cloud instance without Rust (Vast.ai, RunPod, Lambda, …)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source $HOME/.cargo/env
pip install git+https://codeberg.org/JHNMACHINE/moonclip.git

Build from source

git clone https://codeberg.org/JHNMACHINE/moonclip.git
cd moonclip
pip install maturin
maturin develop --release

S3 Backend

Checkpoint to local SSD for speed, sync to S3-compatible storage for durability:

mgr = CheckpointManager(
    "./checkpoints",
    save_dtype="bf16",
    s3_bucket="my-bucket",
    s3_access_key="...",
    s3_secret_key="...",
    s3_endpoint="http://localhost:9000",   # MinIO / R2 / B2
    s3_path_style=True,
    sync_every_n_saves=5,
)

Multi-GPU (FSDP / DDP)

Moonclip auto-detects torchrun environment variables. No configuration needed:

torchrun --nproc_per_node=8 train.py
mgr = CheckpointManager("./checkpoints")
# mgr.rank == 3, mgr.world_size == 8  (auto-detected)
start_step = mgr.resume(model=model, optimizer=optimizer)

Tuning

Three environment variables, none required:

MOONCLIP_THREADS Size of Moonclip's thread pool. Default: cores / LOCAL_WORLD_SIZE.
MOONCLIP_PROFILE=1 Per-phase breakdown of the save path on stderr, plus a line whenever a save had to wait for the previous one to drain.
MOONCLIP_FSYNC=0 Skip the fsync before a pack is renamed into place. Faster, and a machine that loses power mid-save can then come back holding a pack of the right length full of zeros — which the manifest vouches for. Only worth it where the checkpoint is not the thing being protected.

The parallel work runs in a pool of Moonclip's own, not rayon's global one, so it neither claims every core on the machine nor competes with your application's par_iter. On a node running several ranks the default splits the cores between them — LOCAL_WORLD_SIZE is what torchrun sets — so eight ranks on 128 cores take 16 threads each rather than 128 apiece.

Set MOONCLIP_THREADS when that guess is wrong for your box: the machine is Moonclip's alone (give it every core), or the ranks do not all checkpoint at the same time.

Architecture

src/
├── cast.rs          # Rust-native fp32↔bf16/fp16 casting (rayon parallel)
├── coordinator.rs   # Rank-aware snapshot lifecycle
├── tensor.rs        # Per-tensor delta tracking and storage
├── manifest.rs      # Manifest v2: per-rank, per-tensor, lineage
├── compression.rs   # Zstd compression (parallel frames)
├── delta.rs         # XOR delta computation (rayon parallel)
├── shuffle.rs       # Byte-plane transpose before compressing a delta
├── pack.rs          # One pack file per rank, with a recovery descriptor
├── merger.rs        # Background delta merging
├── remote_sync.rs   # Batched S3 sync
├── s3.rs            # S3-compatible storage (AWS SigV4)
├── storage.rs       # StorageBackend trait + LocalStorage (4KB aligned)
├── pool.rs          # The private rayon pool (see Tuning)
├── profile.rs       # Opt-in phase timing (MOONCLIP_PROFILE)
├── hash.rs          # xxHash3-128 integrity
├── python.rs        # PyO3 bindings
└── error.rs         # Error types

Development

cargo test                          # Rust tests
maturin develop --release && pytest tests/ -v   # Python + PyTorch tests

License

Apache-2.0 — Minya AI

Release files for moonclip 0.0.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for moonclip 0.0.7
File Size Uploaded
moonclip-0.0.7.tar.gz 158.2 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for moonclip 0.0.7
File
moonclip-0.0.7-cp314-cp314-manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.28+ x86-64 Details
moonclip-0.0.7-cp313-cp313-manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.28+ x86-64 Details
moonclip-0.0.7-cp312-cp312-manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64 Details
moonclip-0.0.7-cp311-cp311-manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64 Details
moonclip-0.0.7-cp310-cp310-manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.28+ x86-64 Details
moonclip-0.0.7-cp39-cp39-manylinux_2_28_x86_64.whl CPython 3.9 CPython 3.9 Linux glibc 2.28+ x86-64 Details

Total release size: 12.6 MB

Release files / moonclip-0.0.7.tar.gz

Download URL moonclip-0.0.7.tar.gz
Size 158.2 kB
Tags Source
SHA-256 checksum
How to use checksums
bd70e2a456110d4004349ad443c6ae26b7d35d3414e505db271ba173fa51e480
BLAKE2b-256 checksum
How to use checksums
3e0e4bf9302cab8a9677739b5d947884e2c2a462f12a0620a28512cb0b352247
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / moonclip-0.0.7-cp314-cp314-manylinux_2_28_x86_64.whl

Download URL moonclip-0.0.7-cp314-cp314-manylinux_2_28_x86_64.whl
Size 2.1 MB
Tags CPython 3.14 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
3840dcbe6d9191dffbdf9ec0f914be4ab482d829714d33cb6987a33f3fb91f61
BLAKE2b-256 checksum
How to use checksums
5a5072c28938e0acfab66ca02c1888485a3a3a0c62ff25c1798c586415be979c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / moonclip-0.0.7-cp313-cp313-manylinux_2_28_x86_64.whl

Download URL moonclip-0.0.7-cp313-cp313-manylinux_2_28_x86_64.whl
Size 2.1 MB
Tags CPython 3.13 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
89d0988d0077807bcad9dfd95eb6b04af26d21cbc86d6335a981e3d7dbc858bd
BLAKE2b-256 checksum
How to use checksums
9d5ca1701299006ee96a52b2e6e96d7b041330e9e5317b05307d3877e2a08c67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / moonclip-0.0.7-cp312-cp312-manylinux_2_28_x86_64.whl

Download URL moonclip-0.0.7-cp312-cp312-manylinux_2_28_x86_64.whl
Size 2.1 MB
Tags CPython 3.12 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
f98f88d30d336ce0849fc13896f83f2d7697d4d107533774fa7a58bc43e54faa
BLAKE2b-256 checksum
How to use checksums
bb788dbdc109bf5dbe00a77f50d7b0dc171f757a954a09b8e22e702d973e4ada
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / moonclip-0.0.7-cp311-cp311-manylinux_2_28_x86_64.whl

Download URL moonclip-0.0.7-cp311-cp311-manylinux_2_28_x86_64.whl
Size 2.1 MB
Tags CPython 3.11 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
7288d47f3af8e48a7daa6ba54ef598b5b57d45aef474feebe7d7fcaba2e78686
BLAKE2b-256 checksum
How to use checksums
e71fe57163db74fd005c23cba7e7254e510f56ed6ff5c16ace5f1b52ddf79aee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / moonclip-0.0.7-cp310-cp310-manylinux_2_28_x86_64.whl

Download URL moonclip-0.0.7-cp310-cp310-manylinux_2_28_x86_64.whl
Size 2.1 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
a02f8d22ca54d16b91e9fde75e07c19ede1cd9620e063e8ecae95d9da81b279d
BLAKE2b-256 checksum
How to use checksums
4f1c347b48696df50edb03ef4b70ffd6b858737cbd95feda1cfe1220d2a39c76
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / moonclip-0.0.7-cp39-cp39-manylinux_2_28_x86_64.whl

Download URL moonclip-0.0.7-cp39-cp39-manylinux_2_28_x86_64.whl
Size 2.1 MB
Tags CPython 3.9 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
fcba3e3091d00cb122287d094d0ca99cb3d181b315ed9507ffa1ea35328c2c77
BLAKE2b-256 checksum
How to use checksums
45250e64937ec7de7b801d1cba43e799fa8f94d1f3e051d21d6226de4d84559a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release history Release notifications | RSS feed

0.1.3

5 release files

0.1.2

5 release files

0.1.1

5 release files

0.1.0

5 release files

0.0.9

5 release files

0.0.8

7 release files

This release

0.0.7 This release

7 release files

0.0.6

7 release files

0.0.4

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page