meridian
Meridian is an offline, cryptographically verifiable delta synchronization engine for directory trees. It turns any
folder into a content-addressed repository, creates immutable snapshots, and exports compact .mrd bundles containing
only the chunks that changed.
It is useful when normal sync is impossible or undesirable: air-gapped machines, removable media, slow links, reproducible deployments, deterministic backups, or audited file transfer.
What makes it different
Заголовок раздела «What makes it different»- True delta bundles: unchanged chunks are not copied.
- Offline application: move a single
.mrdfile by USB, email, object storage, or any transport. - Merkle-style integrity: every chunk, snapshot, and bundle is SHA-256 verified.
- Atomic updates: a destination is staged and swapped only after successful reconstruction.
- Conflict protection: a delta applies only to the exact base snapshot it was built from.
- Full bundles: optionally produce a self-contained snapshot that can replace an unrelated directory.
- Content deduplication: repeated chunks are stored once in the local object store.
- No runtime dependencies: Python 3.11+ standard library only.
- Library and CLI: automate it from Python or use the
meridiancommand.
Installation
Заголовок раздела «Installation»A prebuilt wheel is included, so installation does not need a compiler or build backend:
python -m venv .venv# Linux/macOSsource .venv/bin/activatepython -m pip install dist/meridian_sync-1.0.0-py3-none-any.whl# Windows PowerShell.venv\Scripts\Activate.ps1python -m pip install dist\meridian_sync-1.0.0-py3-none-any.whlTo install directly from source instead, run python -m pip install ..
Five-minute workflow
Заголовок раздела «Five-minute workflow»Create a source repository and its first snapshot:
mkdir projectcd projectmeridian init# add or copy your filesmeridian snapshot -m v1After changing files, create the next snapshot:
meridian snapshot -m v2meridian diff v1 v2Build a compact delta bundle:
meridian bundle v1 v2 -o ../v1-to-v2.mrdPrepare a replica at v1 once (or use an existing matching directory):
meridian restore v1 ../replicaApply the bundle atomically:
meridian apply ../v1-to-v2.mrd ../replicaValidate a bundle before transferring or applying it:
meridian inspect ../v1-to-v2.mrdFull bundle for unrelated or empty destinations
Заголовок раздела «Full bundle for unrelated or empty destinations»A normal delta omits chunks already present in the base snapshot. For a self-contained bundle:
meridian bundle v1 v2 -o ../v2-full.mrd --fullmeridian apply ../v2-full.mrd ../some-directory --allow-unrelatedThis replaces the destination atomically with the exact target tree.
Ignore rules
Заголовок раздела «Ignore rules»meridian init creates .meridianignore. Rules are intentionally familiar:
*.tmpbuild/.cache/!important.tmpThe .meridian repository directory is always excluded. .meridianignore itself is included so that snapshot semantics
remain visible and reproducible.
CLI reference
Заголовок раздела «CLI reference»meridian init [PATH] [--chunk-size AVERAGE_BYTES]meridian snapshot [PATH] [-m LABEL]meridian snapshots [PATH] [--json]meridian diff OLD NEW [--repo PATH] [--json]meridian bundle BASE TARGET -o FILE [--repo PATH] [--full]meridian inspect BUNDLE [--json]meridian apply BUNDLE DESTINATION [--allow-unrelated]meridian verify SNAPSHOT [--repo PATH]meridian restore SNAPSHOT DESTINATION [--repo PATH] [--overwrite]meridian gc [PATH]Snapshot references may be a full ID, an unambiguous ID prefix, or an exact label.
Python API
Заголовок раздела «Python API»from pathlib import Pathfrom meridian_sync import Repository, create_bundle, apply_bundle
repo = Repository.init(Path("data"))v1 = repo.create_snapshot(label="before")
# mutate files under data/v2 = repo.create_snapshot(label="after")
create_bundle(repo, v1.id, v2.id, Path("update.mrd"))repo.restore(v1.id, Path("replica"))apply_bundle(Path("update.mrd"), Path("replica"))Data model
Заголовок раздела «Data model»A snapshot stores sorted entries for files, directories, and symlinks. File contents are split with deterministic content-defined chunking, so insertions and deletions preserve surrounding chunks instead of shifting every later block. Chunk IDs are SHA-256 hashes of raw bytes. The snapshot root is a canonical hash over paths, types, permissions, sizes, symlink targets, and chunk IDs.
A delta bundle contains:
bundle.json— format metadata and root hashes;base.json— the complete base snapshot manifest;target.json— the complete target snapshot manifest;objects/<sha256>— only target chunks absent from the base snapshot.
During application, Meridian verifies the current destination against base.json, recovers unchanged chunks directly
from the destination, reads changed chunks from the bundle, reconstructs the target in a staging directory, and
atomically swaps it into place.
Operational notes
Заголовок раздела «Operational notes»- Permissions are preserved where the operating system allows it.
- Symlinks are stored as symlinks and are never followed while scanning.
- Sockets, devices, and FIFOs are rejected rather than silently mishandled.
- Files that change during scanning abort the snapshot.
- Bundle archives reject unexpected members and malformed object names.
- Applying a normal delta to the wrong base fails without modifying the destination.
Testing
Заголовок раздела «Testing»python -m unittest discover -s tests -vLicense
Заголовок раздела «License»MIT
Исходный код · MIT