Skip to main content

Reflake

Reflake is a serverless (client-first), object-storage-first data versioning engine.

The design is deliberately opinionated: keep canonical data storage boring and immutable, and put intelligence in metadata and access layers.

Guardrails (Strict)

  • Do not optimize canonical blob storage for ML throughput (no tarball/parquet/sharded blob layer).
  • Do not read blob payloads for metadata-only operations (diff, list, log, status).
  • Do not introduce a server/daemon/central database.
  • Use Blake3 for all content hashing.
  • Prefer JSONL manifests for stream-safe, O(1)-memory behavior.

Core Philosophy

Reflake separates the platform into three layers:

  1. Canonical Layer (blobs/)
    • Content-addressed objects keyed by Blake3 digest.
    • Physical layout is simple and deterministic (<hash[:2]>/<hash[2:]>).
  2. Metadata Layer (manifests/, commits/, refs/)
    • JSONL manifests map logical path -> identity + metadata.
    • Commit objects (JSON) and branch refs provide Git-like lineage semantics.
  3. Access Layer (fsspec)
    • reflake://<dataset>@<branch_or_commit>/<path> resolves metadata, then reads either canonical blob bytes or source URI bytes for metadata-only entries.

MVP Status (Current)

Reflake is intentionally in MVP mode.

Implemented

  • Commit snapshots over a dataset root (reflake commit).
  • Repository URI support via --repo <path|s3://bucket/prefix> and open_repository(...).
  • Repository initialization (reflake init) with local or S3 backend.
  • Remote sync workflow (reflake fetch, reflake pull, reflake push).
  • Operator-facing S3 lock inspection and cleanup (reflake lock list, reflake lock cleanup).
  • Streaming S3 ingress from s3:// objects and prefixes via staged reflake add ... --identity meta --as ... followed by reflake commit --staged.
  • Branch-scoped staging workflow (reflake add, reflake rm, reflake status, reflake commit --staged).
  • Incremental ingress paths that preserve existing manifest entries while adding only new content metadata/blobs.
  • Commit identity modes: blake3 (default) and meta (hash(path+size)).
  • Verify command to promote metadata-only entries to canonical blobs (reflake verify).
  • Zero-copy branch pointers (reflake branch).
  • Fast-forward-only branch merge (reflake merge).
  • Metadata-only diff between refs (reflake diff).
  • Metadata-only manifest mutations for committed refs via the staged flow (reflake rm ..., reflake mv ... ..., then reflake commit --staged).
  • File restoration from refs (reflake restore <ref> [--path ...] [--force]).
  • Disposable analytical index from manifest (reflake index build, DuckDB + optional Parquet export).
  • fsspec provider for reflake:// URI reads.
  • Local + S3 storage backend abstractions available in code.
  • Human-readable output by default; --json flag on all commands for programmatic use.

Technical Stack

  • Python 3.11+
  • blake3 for hashing
  • JSONL manifests + JSON commit objects
  • fsspec for URI access abstraction
  • duckdb for disposable analytical indexing

Install

uv pip install reflake

Developer mode in repo

uv sync
uv run reflake --help

License And Support

Reflake is licensed under the GNU Affero General Public License v3.0 or later.

  • The license keeps copyright and license notices attached to redistributed copies.
  • Modified networked deployments must make their corresponding source available under the AGPL terms.
  • That gives companies a practical reason to fund maintenance if they depend on Reflake while keeping the project genuinely open source.

If your company uses Reflake, sponsor ongoing maintenance at https://github.com/sponsors/londogard.

Quickstart

# Initialize a new repository
mkdir -p /tmp/reflake-demo
uv run reflake init --repo /tmp/reflake-demo
# Or with S3 backend: uv run reflake init --repo /tmp/reflake-demo --backend s3 --s3-bucket my-bucket

echo "hello" > /tmp/reflake-demo/a.txt

uv run reflake commit --repo /tmp/reflake-demo -m "initial"

# Stage an S3 prefix as metadata-only entries, then commit the staged additions
uv run reflake add --repo /tmp/reflake-demo --identity meta --as imports/bootstrap s3://my-bucket/bootstrap
uv run reflake commit --repo /tmp/reflake-demo --staged -m "metadata import"
uv run reflake verify --repo /tmp/reflake-demo

# branch-scoped staged flow
uv run reflake branch --repo /tmp/reflake-demo feature
uv run reflake checkout --repo /tmp/reflake-demo feature
uv run reflake add --repo /tmp/reflake-demo data/new.csv
uv run reflake add --repo /tmp/reflake-demo --as imports/raw.csv /tmp/outside-repo/raw.csv
uv run reflake add --repo /tmp/reflake-demo --as imports/bundle /tmp/outside-repo/bundle
uv run reflake add --repo /tmp/reflake-demo --identity meta --as imports/bootstrap.csv s3://my-bucket/bootstrap.csv
uv run reflake add --repo /tmp/reflake-demo --identity meta --as imports/bootstrap s3://my-bucket/bootstrap
uv run reflake status --repo /tmp/reflake-demo
uv run reflake commit --repo /tmp/reflake-demo --staged -m "feature updates"
uv run reflake checkout --repo /tmp/reflake-demo main
uv run reflake merge --repo /tmp/reflake-demo feature main

# restore files from a ref
uv run reflake restore --repo /tmp/reflake-demo main
uv run reflake restore --repo /tmp/reflake-demo main --path data/new.csv
uv run reflake restore --repo /tmp/reflake-demo main --force

echo "hello v2" > /tmp/reflake-demo/a.txt
uv run reflake commit --repo /tmp/reflake-demo -m "update"

uv run reflake branch --repo /tmp/reflake-demo experiment
uv run reflake diff --repo /tmp/reflake-demo <from_ref> <to_ref>

# Stage and commit metadata mutations
uv run reflake rm --repo /tmp/reflake-demo old-prefix
uv run reflake mv --repo /tmp/reflake-demo raw/images curated/images
uv run reflake status --repo /tmp/reflake-demo
uv run reflake commit --repo /tmp/reflake-demo -m "clean up old files and rename image prefix"

# Or stage the mutation and commit it with a single message
uv run reflake rm --repo /tmp/reflake-demo logs/2025
uv run reflake mv --repo /tmp/reflake-demo incoming/images curated/images
uv run reflake commit --repo /tmp/reflake-demo --staged -m "remove old logs and rename prefix"

# remote repo metadata operations from the current working tree
uv run reflake branch --repo s3://my-bucket/datasets/demo feature
uv run reflake commit --repo s3://my-bucket/datasets/demo -m "snapshot current working tree"
uv run reflake rm --repo s3://my-bucket/datasets/demo obsolete
uv run reflake mv --repo s3://my-bucket/datasets/demo bootstrap final
uv run reflake commit --repo s3://my-bucket/datasets/demo --staged -m "drop obsolete paths and rename imported prefix"

# JSON output for programmatic use (all commands support --json)
uv run reflake status --repo /tmp/reflake-demo --json
uv run reflake add --repo /tmp/reflake-demo data/new.csv --json
uv run reflake diff --repo /tmp/reflake-demo main feature --json

Analytical Index (Derived, Disposable)

uv run reflake index build --repo /tmp/reflake-demo --parquet

reflake index build writes a DuckDB database (and optional Parquet export) for the current branch's manifest to .reflake/index/<commit_id>.duckdb. Query it with the DuckDB CLI:

duckdb /path/to/<commit>.duckdb "SELECT COUNT(*) FROM files"

If the index is deleted, Reflake remains fully functional from manifests and commits.

fsspec URI Example

from reflake.core import ReflakeFileSystem

fs = ReflakeFileSystem(dataset_roots={"my_data": "/tmp/reflake-demo"})
with fs.open("reflake://my_data@main/a.txt", "rb") as handle:
	 data = handle.read()

# include branch staged (not-yet-committed) changes
with fs.open("reflake://my_data@feature+staged/a.txt", "rb") as handle:
	 staged_data = handle.read()

In meta snapshots, Reflake reads from source_uri when no canonical blobs/ object exists.

Identity Modes

Reflake supports two identity modes for manifest entries:

  • blake3 (default)

    • Reads file bytes.
    • Stores canonical blob in .reflake/blobs/.
    • Manifest entry includes identity_mode=blake3, identity_value, and blob_hash.
  • meta

    • Does not read file bytes.
    • Computes identity as blake3("<relative_path>\n<size>").
    • Stores no canonical blob (blob_hash=null) and keeps source_uri for reads.

Set the mode per staged addition with reflake add --identity meta, or set the repository-wide default for reflake commit with reflake config set identity meta.

This is useful for large bootstrap imports where strong content verification can be deferred.

Durability contract for meta

Metadata-only (meta) revisions are unverifiable: the entry's identity is derived from path and size, not from content bytes. Until you run reflake verify, Reflake cannot prove that the content at source_uri matches what was originally imported.

Warnings. The CLI emits a warning to stderr whenever you stage with --identity meta or commit a repository whose identity is configured to meta, and after verify reports how many unverifiable entries remain.

Source-retention policy. Because metadata-only entries have no canonical blob, you must retain the source objects at their original source_uri until the entry has been promoted via reflake verify. If a source object is deleted, overwritten, or moved before verification, the corresponding manifest entry becomes irrecoverable — no content can be read and no hash can be validated.

Promotion to verifiable. Run reflake verify to read every metadata-only entry's source blob, compute a Blake3 content hash, store the canonical blob, and rewrite the manifest entry in blake3 mode. After promotion the source retention requirement is lifted for those entries.

Lifecycle summary:

State identity_mode blob_hash Can read? Can prove integrity? Source required?
Metadata-only meta null ✅ (from source_uri)
Verified blake3 hash ✅ (from blobs/)

Verify Command

reflake verify promotes metadata-only (meta) manifest entries of the current branch into canonical blake3 blob-backed entries:

uv run reflake verify --repo /tmp/reflake-demo
uv run reflake verify --repo /tmp/reflake-demo --path images --path logs/2026
uv run reflake verify --repo /tmp/reflake-demo --dry-run
  • Verifies all entries by default (or selected path prefixes with --path).
  • --dry-run reports how many entries would be promoted without changing blobs/commits.
  • Reads bytes from each entry's source_uri, computes Blake3, and stores canonical blob content.
  • Writes a new commit only when at least one entry is promoted.

Incremental Ingress

Reflake's efficient content-ingress paths are:

uv run reflake add --repo /tmp/reflake-demo local/new.csv
uv run reflake add --repo /tmp/reflake-demo --as imports/new.csv /tmp/random/new.csv
uv run reflake add --repo /tmp/reflake-demo --as imports/new-batch /tmp/random/new-batch
uv run reflake add --repo /tmp/reflake-demo --identity meta --as imports/bootstrap.csv s3://my-bucket/bootstrap.csv
uv run reflake add --repo /tmp/reflake-demo --identity meta --as imports/bootstrap s3://my-bucket/bootstrap
uv run reflake commit --repo /tmp/reflake-demo --staged -m "add one file"
uv run reflake verify --repo /tmp/reflake-demo --path images --path root.txt
  • add + commit --staged preserves the current branch manifest and reads bytes only for staged additions.
  • add accepts repo-relative files, arbitrary local files, local directories, single S3 objects, and S3 prefixes; --as maps a single file/object to one logical path or remaps a directory/prefix under a destination prefix.
  • verify reads bytes only for selected metadata-only entries that still need canonical blobs.
  • Existing manifest entries are preserved without re-uploading unchanged blob content.

S3 Integration Tests

Reflake includes integration-marked tests for real S3-compatible behavior. The preferred target is Ministack.

For the standard local workflow, run a single command from the repository root:

bash scripts/run_s3_integration.sh

That script starts a temporary Ministack container on 127.0.0.1:4566, waits for the health endpoint, resets emulator state, runs tests/test_s3_integration.py, and cleans up the container when the test run finishes.

If you prefer task-runner aliases, the repo also provides:

make test-s3-integration

GitHub Actions runs the same script in the dedicated S3 integration job.

Start Ministack locally:

docker run --rm -p 4566:4566 nahuelnucera/ministack

If you also want MiniStack features that launch real sidecar containers such as RDS, ECS, or Docker-backed Lambda runtimes, mount the Docker socket:

docker run --rm -p 4566:4566 -v /var/run/docker.sock:/var/run/docker.sock nahuelnucera/ministack

Verify the emulator is ready:

curl http://127.0.0.1:4566/_ministack/health

Then set these environment variables before running the suite:

export REFLAKE_MINISTACK_ENDPOINT=http://127.0.0.1:4566
export REFLAKE_MINISTACK_ACCESS_KEY=test
export REFLAKE_MINISTACK_SECRET_KEY=test
export REFLAKE_MINISTACK_REGION=us-east-1

Reflake's integration fixture already uses path-style boto3 S3 addressing, so no extra S3 client flags are needed.

Then run:

uv run pytest tests/test_s3_integration.py -m integration

If REFLAKE_MINISTACK_ENDPOINT is unset or the endpoint is unreachable, the integration tests skip automatically.

To wipe the local emulator state between runs without restarting the container:

curl -X POST http://127.0.0.1:4566/_ministack/reset

Merge Command

reflake merge updates a target branch by fast-forward only:

uv run reflake merge --repo /tmp/reflake-demo feature main
  • The source ref can be a branch or commit.
  • The target ref must be a branch.
  • The merge succeeds only when the target branch head is an ancestor of the source ref.
  • Non-fast-forward merges are rejected.

Metadata-Only Remove And Move

reflake rm and reflake mv stage metadata-only mutations; reflake commit --staged writes a new manifest and commit:

uv run reflake rm --repo /tmp/reflake-demo logs/2025
uv run reflake mv --repo /tmp/reflake-demo incoming/images curated/images
uv run reflake commit --repo /tmp/reflake-demo --staged -m "remove old logs and rename prefix"
  • These operations read manifest metadata only; they do not download unchanged blob payloads.
  • rm accepts file paths or path prefixes and removes all matching logical entries.
  • mv accepts a file path or prefix and rewrites matching logical paths in the manifest.
  • reflake status shows staged removals and renames before reflake commit --staged.

Repository Layout

Reflake creates .reflake/ under each dataset root:

  • blobs/ - canonical content-addressed object store
  • manifests/ - JSONL path->hash snapshots
  • commits/ - commit metadata objects
  • refs/heads/ - branch pointers
  • refs/HEAD - symbolic active branch reference (default main)

Mandatory Validation Coverage

Current tests cover required invariants:

  • Metadata-only diff reads no blob payloads.
  • Manifest generation for 100k entries stays under RAM cap.
  • reflake://my_data@main/test.csv resolves and returns expected bytes.

Run test suite:

uv run pytest tests

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

reflake-0.1.0.tar.gz (105.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

reflake-0.1.0-py3-none-any.whl (114.4 kB view details)

Uploaded Python 3

File details

Details for the file reflake-0.1.0.tar.gz.

File metadata

  • Download URL: reflake-0.1.0.tar.gz
  • Upload date:
  • Size: 105.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.6

File hashes

Hashes for reflake-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cd40d384662f7d6379420b118342211b99266e1e5f7a36074a31978a53577da2
MD5 279a0c51cf23f255f1af38b365913aa4
BLAKE2b-256 13914d0544b5246f82f61b93e07e86c9bbb08a721e7d9232f9590d3ea1e699ce

See more details on using hashes here.

File details

Details for the file reflake-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: reflake-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 114.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.6

File hashes

Hashes for reflake-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5b8a0b3b5e3f94e293bd7b5de9bbe8e30fd1337ff31d46720c0e424289233aa7
MD5 ff8399414af9049a1d340ee6334c908b
BLAKE2b-256 28b1572d063ead1d18449115de846da838f7d68bce8f50b242eba18ff0596237

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page