The missing Swiss Army knife for model checkpoints.
ckptkit inspects, diffs, validates, and merges model checkpoints without loading them into GPU memory. Parse SafeTensors headers in milliseconds, compare checkpoints after fine-tuning, merge LoRA adapters, and validate file integrity — all from the command line or Python.
Working with model weights means dealing with:
- "What layers are in this checkpoint?" →
ckptkit info - "What changed after fine-tuning?" →
ckptkit diff - "Is this download corrupt?" →
ckptkit validate - "Merge this LoRA adapter into the base" →
merge_lora_state_dicts() - "Show me parameter counts per layer" →
ckptkit stats
mergekit handles model merging (TIES, DARE, SLERP), but nobody built the everyday checkpoint utility. ckptkit is that tool.
pip install ckptkitWith SafeTensors support (recommended):
pip install ckptkit[safetensors]With PyTorch support:
pip install ckptkit[torch]Everything:
pip install ckptkit[all]# See what's inside a checkpoint
ckptkit info model.safetensors
# JSON output for scripts
ckptkit info model.safetensors --json | jq '.n_parameters'Compare two checkpoints — see what changed during fine-tuning:
ckptkit diff base_model.safetensors finetuned_model.safetensorsCheck for corruption before a long training run:
ckptkit validate model.safetensors
# ✓ model.safetensors: valid (safetensors)ckptkit stats model.safetensorsfrom ckptkit import inspect
info = inspect("model.safetensors")
print(f"Parameters: {info.n_parameters:,}")
print(f"Tensors: {info.n_tensors}")
print(f"Format: {info.format.value}")
for t in info.tensors[:5]:
print(f" {t.name}: {t.shape} {t.dtype.value} ({t.numel:,} params)")from ckptkit import diff, format_diff
result = diff("base.safetensors", "finetuned.safetensors")
print(f"Changes: {result.n_changes}")
print(f"Identical: {result.n_identical} / {result.n_shared}")
for entry in result.entries:
print(f" {entry.change_type}: {entry.tensor_name} — {entry.details}")import torch
from ckptkit import merge_lora_state_dicts
base = torch.load("base_model.bin", map_location="cpu")
adapter = torch.load("adapter_model.bin", map_location="cpu")
merged = merge_lora_state_dicts(base, adapter, alpha=1.0)
torch.save(merged, "merged_model.bin")from ckptkit import validate
result = validate("model.safetensors")
if not result.valid:
for issue in result.issues:
print(f" {issue.severity}: {issue.message}")from ckptkit import inspect, stats_from_info
info = inspect("model.safetensors")
stats = stats_from_info(info)
print(f"Total size: {stats.total_size_human}")
for dtype, count in stats.dtype_counts.items():
print(f" {dtype}: {count:,} parameters")| Format | Inspect | Diff | Validate | Merge |
|---|---|---|---|---|
| SafeTensors | ✓ (header-only, fast) | ✓ | ✓ (full integrity) | ✓ |
| PyTorch (.bin/.pt) | ✓ (requires torch) | ✓ | basic | ✓ |
SafeTensors inspection is fast because the format puts all tensor metadata (names, shapes, dtypes, offsets) in a JSON header at the start of the file. ckptkit reads only the first few KB, never loading the actual weight data.
LoRA merging performs base_weight += alpha * (lora_B @ lora_A) for each matched layer pair, with automatic key resolution for common adapter formats (PEFT, HuggingFace).
Part of the stef41 LLM toolkit — open-source tools for every stage of the LLM lifecycle:
| Project | What it does |
|---|---|
| tokonomics | Token counting & cost management for LLM APIs |
| datacrux | Training data quality — dedup, PII, contamination |
| castwright | Synthetic instruction data generation |
| datamix | Dataset mixing & curriculum optimization |
| toksight | Tokenizer analysis & comparison |
| trainpulse | Training health monitoring |
| quantbench | Quantization quality analysis |
| infermark | Inference benchmarking |
| modeldiff | Behavioral regression testing |
| vibesafe | AI-generated code safety scanner |
| injectionguard | Prompt injection detection |
Apache-2.0