Skip to main content

darsay

the genesis machine of archives

CI Apache 2.0 Python 3.10+ Version 0.6.0 Manifest schema 1.5.0

Quick start · How it works · A bundle · Commands · Documentation · Contributing


darsay pulls a model or dataset from a source (Hugging Face today) at a pinned revision, hashes every file, cross-checks upstream checksums, captures the license verbatim, extracts metadata from the payload itself, and writes a bundle that any Hugging Face-compatible loader uses as-is.

When you want the archived model to speak:

darsay run vault/qwen--qwen3-0.6b/<rev> "Say hello"

That command hydrates an isolated environment, runs offline, and leaves the payload byte-immutable. Before you commit tens of gigabytes, darsay estimate prices the source from upstream metadata alone.

Estimate first. Price a 50 GB model from Hub metadata. Nothing downloaded.

Archive for keeps. Pinned revision, hashed, license captured, payload immutable.

Resume anything. Budgets, Ctrl-C, USB sticks, collaborators with --shard 1/3.

Run offline. One command. Isolated env. HF_HUB_OFFLINE=1. Payload untouched.

Why it exists

The Hub is a living website, not an archive. Repos get gated, rewritten, and deleted. Datasets vanish faster than weights. Published quants — the official FP8, the community GGUF people actually ran — cannot be regenerated bit-exact from the master. If it matters what the world used, the bytes themselves must be kept, with a manifest that records facts and never fabricates them.

A darsay bundle is that record: immutable payload + machine-readable manifest + derived views + one curator file. The tool is replaceable. The formats are not.

Quick start

Requires Python 3.10+. One pure-Python wheel for every OS. Isolated CLI tools are the intended way to run a release; see docs/DISTRIBUTION.md.

pipx install git+https://github.com/jeremynorris/darsay@v0.6.0
# or, one-shot with no install:
uvx --from git+https://github.com/jeremynorris/darsay@v0.6.0 darsay --help

Then:

darsay estimate Qwen/Qwen3-0.6B
darsay archive  Qwen/Qwen3-0.6B
darsay run      vault/qwen--qwen3-0.6b/<rev> "Say hello"
Development checkout and extras
python3 -m venv .venv
.venv/bin/pip install -e .                      # core: huggingface_hub only
.venv/bin/pip install -e ".[fast-hash,smoke]"   # + blake3, tokenizers
.venv/bin/pip install -e ".[inference]"         # + transformers/torch for in-process smoke
.venv/bin/pip install -e ".[datasets]"          # + pyarrow for measured dataset row counts
.venv/bin/pip install -e ".[dev]"               # pytest
.venv/bin/pytest                                # unit + integration; see docs/TESTING.md

The extras only serve in-process smoke tests. darsay run needs none of them — hydration builds its own isolated env per engine.

The vault root defaults to ./vault (override with --vault or $DARSAY_HOME). Bundles are gitignored — they live on disk or in your backup tier, not in this repo.

How it works

flowchart LR
  S["Source<br/>huggingface:owner/name"] --> E["estimate"]
  E --> A["archive"]
  A --> B["Bundle"]
  B --> V["verify"]
  B --> R["run"]
  B --> X["export .mvb.tar"]
  X --> I["import"]
  1. Estimate — read-only preflight. Exact sizes, parameter counts, disk headroom, quantized ecosystem. Nothing downloaded.
  2. Archive — pin a revision, transfer bytes (resumable, budgeted, cooperative), hash, verify against upstream, write the manifest.
  3. Keep — the payload never changes again. Metadata at the bundle root is mutable by design.
  4. Use — point any HF-compatible loader at <bundle>/model, or darsay run for one-command offline inference. export packs a deterministic .mvb.tar for offsite storage.

A bundle

vault/qwen--qwen3-0.6b/<revision12>/
├── model/              # immutable payload: pristine snapshot of the upstream repo
├── manifest.json       # machine-readable record — the source of truth
├── README.md           # human-readable summary, generated from the manifest
├── VERIFICATION.md     # latest verification report
├── verification.json   # verification history (last 50 runs)
├── curation.md         # curator's notes — the only hand-edited file
├── exports.json        # log of single-file exports (after first export)
├── hydration.json      # runnable-env record + run history (after first hydrate)
├── transfer.json       # disposable resumable-transfer ledger
├── transfer.lock       # transient writer lock (only during archive/assemble)
└── LICENSE             # upstream license text, surfaced at the root

The payload under model/ (or data/ for datasets) is immutable after archiving; the bundle hash covers it alone. To use a model, point transformers at <bundle>/model — no unpacking, no conversion.

What the manifest records
Section Contents
identity name, family, publisher, version, release date, bundle id
source provider, address, pinned commit, transfer accounting, mirrors, signatures, popularity + tags at archive time
licensing SPDX id, license files, commercial / redistribution / modification / attribution flags, patent grant, trademark terms
inventory per-file size + SHA-256 (+BLAKE3), upstream checksum match, deterministic bundle hash
model_metadata parameter count by dtype (from safetensors headers — no torch), architecture, context, tokenizer, languages
runtime engines from shipped formats, estimated min RAM/VRAM, measured hardware from darsay run
validation checksum verification, completeness, tokenizer + inference smoke tests
relationships parents, finetunes, known quantizations + GGUF repos (snapshot at archive time)
archive date, host, storage tier, backups, last integrity check
security integrity status, unexpected-change flags, trust level
curation historical significance, capabilities, limitations, notes (via curation.md)

schema_version is recorded in every manifest. Full field-by-field reference: docs/MANIFEST.md.

Commands

darsay estimate Qwen/Qwen3.8-27B --variants          # preflight: size, params, disk, quants
darsay estimate unsloth/Qwen3.8-27B-GGUF --include '*Q4_K_M*'
darsay estimate datasets/saidutta69/fable-5-premium  # Hub dataset address grammar
darsay archive  Qwen/Qwen3-0.6B                      # download + hash + manifest
darsay archive  datasets/saidutta69/fable-5-premium  # dataset bundle: payload under data/
darsay archive  Qwen/Qwen3.8-27B --max-gb 10         # pause cleanly; rerun to resume
darsay archive  Qwen/Qwen3.8-27B --dry-run           # verified / partial / missing plan
darsay archive  Qwen/Qwen3.8-27B --shard 1/3 --max-gb 20
darsay --vault ./combined assemble /usb/alice/<bundle> /usb/bob/<bundle>
darsay verify   vault/qwen--qwen3-0.6b/<rev>
darsay smoke    vault/qwen--qwen3-0.6b/<rev> [--inference]
darsay list
darsay info     vault/qwen--qwen3-0.6b/<rev>
darsay regen    vault/qwen--qwen3-0.6b/<rev>         # rebuild README after editing curation.md
darsay export   vault/qwen--qwen3-0.6b/<rev> -o /backups
darsay import   /backups/qwen--qwen3-0.6b@<rev>.mvb.tar

darsay run      vault/qwen--qwen3-0.6b/<rev> "Say hello"
darsay hydrate  vault/qwen--qwen3-0.6b/<rev> [--dry-run]
darsay envs [--prune]
darsay dehydrate vault/qwen--qwen3-0.6b/<rev>

Source refs are provider-qualified — huggingface:Qwen/Qwen3-0.6B, huggingface:datasets/owner/name. Unprefixed owner/name / datasets/owner/name and huggingface.co URLs are Hugging Face shorthand. Bundle-path commands dispatch on the manifest's artifact_type. Adding another host is a source provider, not a new CLI: docs/SOURCES.md.

Estimate before you archive

A 27B model is a 50+ GB commitment. estimate is a read-only preflight against the Hub API — nothing downloaded, nothing written. It reports the pinned revision's exact inventory, parameter counts by dtype, the engines the payload will support, a completeness check, and a disk verdict. It exits non-zero when free space is insufficient, so it doubles as a guard in scripts. Upstream numbers are facts; derived figures (min RAM, download scratch) are labeled estimates.

$ darsay estimate Qwen/Qwen3.8-27B

Qwen/Qwen3.8-27B @ main -> 1d4bf0f2ff60
  image-text-to-text | license apache-2.0
  parameters:   27.78B BF16  [upstream safetensors metadata]
  payload:      32 files, 51.8 GiB
                weights 51.7 GiB in 18 files (largest 3.7 GiB: model-00004-of-00018.safetensors)
                support 22.0 MiB in 14 files
  engines:      transformers
  completeness: complete
  estimated:    download scratch +3.7 GiB (largest file in flight), min RAM/VRAM 62.1 GB (weight bytes x1.2)
  bundle:       vault/qwen--qwen3.8-27b/1d4bf0f2ff60  (new)
  disk:         needs ~55.5 GiB, free 1022.6 GiB — OK

To archive: darsay archive Qwen/Qwen3.8-27B

--variants lists the quantized ecosystem (Hub base_model:quantized relation), with query caps recorded in the output. --include GLOB prices a subset of a repo — e.g. one Q4_K_M file inside a 439.7 GiB GGUF pack. --json emits the full machine-readable estimate.

Incremental, relocatable, cooperative transfers

The first archive pins one immutable commit and writes the expected file set to transfer.json. Every later run reconciles that set against local bytes, trusts already verified files, hashes and adopts unrecorded complete files, resumes bundle-local .incomplete files with HTTP Range, and only registers manifest.json after every expected file is verified.

--max-gb, --max-bytes, and --max-minutes stop cleanly with exit code 10. --jobs controls the small-file pool. --rehash rechecks trusted ledger entries.

Partial bundles are self-contained and relocatable. Copy the entire <repo-slug>/<revision12>/ directory — including the payload .cache — under a different vault and rerun the same archive command. The pin is unchanged; completed files are adopted; the longest Range partial continues.

Collaborators use --shard N/T: 1/3, 2/3, and 3/3 deterministically prioritize different byte-balanced whole-file lanes, but each can still finish the identical bundle alone. darsay --vault DEST assemble PARTIAL... merges matching partials offline.

Full design, ledger shape, and failure semantics: docs/INCREMENTAL.md.

Quantized models: fidelity first

The canonical bundle is the highest-fidelity upstream release, archived byte-exact — the master is the negative, quants are prints. Published quants that matter historically (the official FP8, the community-standard GGUF) are archived as ordinary satellite bundles: most are calibration-based and can never be regenerated bit-exact from the master.

Everything else — running the model smaller on your own hardware — is disposable hydration-time derivation, never archival. Full policy: docs/QUANTIZATION.md.

Dataset bundles

Datasets are the vault's second artifact type. Models are functions of data, and datasets are more endangered than weights. One sentence covers the difference: datasets are addressed as datasets/owner/name and their payload lives in data/; everything else is identical.

Bundle directories take a datasets-- prefix. The manifest carries dataset_metadata (formats from the inventory; configs, splits, and example counts as declared upstream claims; measured parquet row counts only when pyarrow is installed). Dataset bundles record models_trained_on; model bundles record training_datasets.

hydrate / run do not apply — a dataset has no engine. Any reader points at data/ directly:

import pyarrow.parquet as pq

path = "vault/datasets--cornell-movie-review-data--rotten_tomatoes/aa13bc287fa6/data"
table = pq.read_table(f"{path}/train.parquet")     # 8,530 rows, offline

Design and rationale: docs/DATASETS.md.

Verification

  • At archive time every file is checked against upstream expectations: LFS files against their upstream SHA-256, small files against their git blob SHA-1. Result: verified-against-upstream.
  • darsay verify re-hashes the payload and diffs it against the manifest. Modified, missing, and extra files flip integrity to compromised and the command exits non-zero — suitable for cron.
  • The bundle hash (SHA-256 over the sorted per-file hash lines) fingerprints the entire payload.

import fully re-hashes a payload before a bundle enters the vault. Failures register nothing and exit non-zero.

Single-file exports (.mvb.tar)

darsay export packs a whole bundle into one deterministic tar: entries sorted (a .mvb.json marker first), tar metadata normalized, no compression — weights are incompressible and a plain tar stays inspectable with standard tools. The same bundle state always exports byte-identically, so the file has one stable SHA-256 for an offsite catalog.

darsay import streams the marker, checks format compatibility, unpacks to staging, re-hashes against the embedded manifest, and only then registers. Manual recovery without the tool is documented: docs/MVB-FORMAT.md.

Running archived models

darsay run <bundle> ["prompt"] goes from bundle to generated tokens in one command (macOS and Linux). It hydrates first: picks an engine from what the payload ships (safetensors → transformers, GGUF → llama-cpp), builds a dedicated virtualenv outside the bundle under <vault>/.runtime/envs/ — content-keyed, so matching bundles share one env — and probes it against the payload.

Inference then runs fully offline (HF_HUB_OFFLINE=1). A passing run is evidence the archived payload alone is sufficient. Envs are disposable: darsay envs --prune reclaims the disk; the next run rebuilds.

Design details: docs/HYDRATION.md.

Extending

New artifact types go in the ARTIFACT_TYPES registry (src/darsay/schema.py) — add an entry with its payload root and completeness rules, and verify / export / report work unchanged. The dataset type was added exactly this way.

New inference runtimes go in ENGINES (src/darsay/hydrate.py) — a detection glob, pip requirements, and a standalone runner script. MLX, vLLM, or ONNX is a registry entry, not a special case.

New acquisition hosts go in SourceProvider (src/darsay/providers/). Hugging Face is the first plugin, not the product: docs/SOURCES.md.

Documentation

Documentation home Map of every document, versions, reading order
Manifest schema Field-by-field manifest.json reference (v1.5.0)
MVB format Deterministic .mvb.tar + manual recovery
Hydration Bundle → runnable env → offline inference
Incremental transfer Pin, reconcile, budget, shard, assemble
Datasets Second artifact type: payload under data/
Sources Provider grammar; Hugging Face as a plugin
Quantization What is archival vs derived
Design Why Python; why longevity lives in the formats
Distribution Wheels, pipx/uvx, and why not frozen binaries
Testing Unit / integration / opt-in Hub e2e

Design

darsay is deliberately Python: hydration runners live inside the torch / transformers ecosystem, the Hugging Face provider uses huggingface_hub as the reference client for that host's snapshot semantics, and the workload is IO-bound glue. A compiled rewrite would buy seconds on a tens-of-minutes job.

Longevity is carried by the formats, not the tool — plain-JSON manifests and plain-tar exports, each documented for recovery without darsay — so the bundles outlive whatever software reads them next.

Full rationale: docs/DESIGN.md.

License

Apache License 2.0. See LICENSE. Bundles record upstream model and dataset licenses separately in manifest.json; those do not change the license of this tool.

Download files

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

Source Distribution

darsay-0.6.0.tar.gz (977.7 kB view details)

Uploaded Source

Built Distribution

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

darsay-0.6.0-py3-none-any.whl (87.3 kB view details)

Uploaded Python 3

File details

Details for the file darsay-0.6.0.tar.gz.

File metadata

  • Download URL: darsay-0.6.0.tar.gz
  • Upload date:
  • Size: 977.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for darsay-0.6.0.tar.gz
Algorithm Hash digest
SHA256 029b488d415b82af7e2d1886e149faa5206b9a165bb30e5e522d86f710cbe129
MD5 da762a3e9ebff80217a50e11f3f820be
BLAKE2b-256 a72d9e589be44f545e5cccabda5317cc8f6f8a6cd7dab0385e5a0ba981458ab5

See more details on using hashes here.

Provenance

The following attestation bundles were made for darsay-0.6.0.tar.gz:

Publisher: release.yml on jeremynorris/darsay

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file darsay-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: darsay-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 87.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for darsay-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 34effbf97bc8488882480af0d9182fbede1d7d686dc78b22d38388c143f7b567
MD5 a5ece5751544dbf849d298e2af0207a4
BLAKE2b-256 7b69c44cdec8a771f9ba3a4c820b1e0cd45994ad9bc93ee5cb99f005964e2315

See more details on using hashes here.

Provenance

The following attestation bundles were made for darsay-0.6.0-py3-none-any.whl:

Publisher: release.yml on jeremynorris/darsay

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 files

Supported by

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