Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Version datasets with checksums, manifests, and semantic versioning. Covers DVC integration, provenance tracking, release tagging, and reproducible dataset lifecycles.
.claude/skills/mkurman-dataset-versioning/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 23% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 88% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 139% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 65% | 0% |
Datasets are artifacts that evolve. Versioning turns "which version did we use?" from a forensic investigation into a one-line answer. Every released dataset gets a checksum, a manifest, and a semantic version tag.
Use this skill when:
Do not use for:
mlflow or wandb skills.bash# DVC (Data Version Control) — recommended for datasets > 10 MB pip install dvc dvc init git commit -m "Initialize DVC"
Or minimal filesystem-based versioning:
pythonimport hashlib import json from pathlib import Path from datetime import datetime, timezone DATASET_ROOT = Path("datasets") VERSION_REGISTRY = DATASET_ROOT / "versions.jsonl" def compute_checksum(filepath: Path, algo: str = "sha256") -> str: h = hashlib.new(algo) with open(filepath, "rb") as f: for chunk in iter(lambda: f.read(8192), b""): h.update(chunk) return h.hexdigest()
Every dataset release needs a manifest.json:
json{ "name": "customer-churn-prediction", "version": "1.0.0", "created_at": "2026-05-11T17:29:51Z", "description": "Cleaned customer churn dataset for binary classification", "files": { "train.parquet": { "checksum_sha256": "a1b2c3d4...", "rows": 80000, "columns": 24, "size_bytes": 5242880 }, "val.parquet": { "checksum_sha256": "e5f6g7h8...", "rows": 10000, "columns": 24, "size_bytes": 655360 }, "test.parquet": { "checksum_sha256": "i9j0k1l2...", "rows": 10000, "columns": 24, "size_bytes": 655360 }, "schema.json": { "checksum_sha256": "m3n4o5p6...", "size_bytes": 2048 }, "cleaning_audit.json": { "checksum_sha256": "q7r8s9t0...", "size_bytes": 4096 } }, "provenance": { "source": "https://data.example.com/customers/export/2026-Q1", "query_timestamp": "2026-05-10T08:00:00Z", "cleaning_script": "scripts/clean_churn.py", "cleaning_script_sha256": "u1v2w3x4...", "split_seed": 42, "transformations_applied": [ "median_imputation_age", "dedup_on_user_id", "cap_age_0_to_120", "one_hot_encode_region" ] }, "schema": { "target_column": "churned", "protected_attributes": ["gender", "age_group"], "train_val_test_split": [0.70, 0.15, 0.15] }, "license": "CC-BY-4.0", "limitations": [ "Data from Q1 2026 only; seasonal patterns not captured", "Region X undersampled (3% vs 15% in production)" ] }
bash# Track dataset files with DVC dvc add datasets/customer-churn-v1.0.0/ # Commit the .dvc file to git git add datasets/customer-churn-v1.0.0.dvc datasets/.gitignore git commit -m "dataset: customer-churn v1.0.0 — initial release" # Push data to remote storage dvc remote add -d myremote s3://my-bucket/datasets dvc push # Tag the release git tag -a "dataset/customer-churn/v1.0.0" -m "Customer churn dataset v1.0.0" git push --tags
| Bump | When | ||--------| | Major (v2.0.0) | Schema change, new/dropped columns, target definition changed, new source data | | Minor (v1.1.0) | New rows added from same source, additional features derived from existing data, improved cleaning | | Patch (v1.0.1) | Bugfix in cleaning without schema changes, metadata/card updates, reprocessing with same logic |
bash# Checkout a tagged dataset version git checkout dataset/customer-churn/v1.0.0 dvc checkout # restore data files # In Python — verify checksums before loading manifest = json.loads(Path("datasets/customer-churn-v1.0.0/manifest.json").read_text()) for fname, finfo in manifest["files"].items(): actual = compute_checksum(Path("datasets/customer-churn-v1.0.0") / fname) assert actual == finfo["checksum_sha256"], f"Checksum mismatch: {fname}"
Append to a global registry for discoverability:
pythondef register_version(manifest: dict): entry = { "name": manifest["name"], "version": manifest["version"], "released_at": manifest["created_at"], "checksum": compute_checksum(Path(f"datasets/{manifest['name']}-v{manifest['version']}/manifest.json")), "num_files": len(manifest["files"]), "predecessor": manifest.get("predecessor_version"), } with open(VERSION_REGISTRY, "a") as f: f.write(json.dumps(entry) + "\n")
A dataset version is complete when:
manifest.json exists with all file checksums.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 17,135 | 12,475 | -27% | 1 | 1 | 0% | 3,523 | 4,343 | +23% | 0 | 0 | — |
case-02 | fail→pass | 13,497 | 10,631 | -21% | 1 | 1 | 0% | 2,569 | 4,063 | +58% | 0 | 0 | — |
case-03 | fail→fail | 18,595 | 17,563 | -6% | 1 | 1 | 0% | 3,774 | 5,754 | +52% | 0 | 0 | — |
case-04 | pass→pass | 13,327 | 11,001 | -17% | 1 | 1 | 0% | 2,183 | 3,711 | +70% | 0 | 0 | — |
case-05 | pass→pass | 7,548 | 3,518 | -53% | 1 | 1 | 0% | 1,217 | 2,423 | +99% | 0 | 0 | — |
case-06 | pass→pass | 13,258 | 5,728 | -57% | 1 | 1 | 0% | 2,087 | 2,794 | +34% | 0 | 0 | — |
case-07 | pass→pass | 6,594 | 4,201 | -36% | 1 | 1 | 0% | 1,124 | 2,590 | +130% | 0 | 0 | — |
case-08 | pass→pass | 8,188 | 3,804 | -54% | 1 | 1 | 0% | 1,402 | 2,574 | +84% | 0 | 0 | — |
case-09 | fail→pass | 7,087 | 2,993 | -58% | 1 | 1 | 0% | 1,292 | 2,429 | +88% | 0 | 0 | — |
case-10 | fail→fail | 14,878 | 9,158 | -38% | 1 | 1 | 0% | 2,749 | 3,388 | +23% | 0 | 0 | — |
case-11 | fail→pass | 5,436 | 1,968 | -64% | 1 | 1 | 0% | 920 | 2,196 | +139% | 0 | 0 | — |
case-12 | fail→pass | 8,662 | 3,285 | -62% | 1 | 1 | 0% | 1,488 | 2,457 | +65% | 0 | 0 | — |
case-13 | fail→pass | 13,461 | 7,386 | -45% | 1 | 1 | 0% | 2,371 | 3,136 | +32% | 0 | 0 | — |
case-14 | fail→pass | 13,596 | 8,151 | -40% | 1 | 1 | 0% | 2,918 | 3,623 | +24% | 0 | 0 | — |
case-15 | fail→pass | 15,949 | 4,303 | -73% | 1 | 1 | 0% | 2,877 | 2,799 | -3% | 0 | 0 | — |
case-16 | pass→pass | 8,974 | 5,057 | -44% | 1 | 1 | 0% | 1,399 | 2,669 | +91% | 0 | 0 | — |
case-17 | fail→pass | 5,979 | 3,218 | -46% | 1 | 1 | 0% | 1,148 | 2,393 | +108% | 0 | 0 | — |
case-18 | pass→pass | 9,649 | 2,732 | -72% | 1 | 1 | 0% | 1,672 | 2,188 | +31% | 0 | 0 | — |
case-19 | pass→pass | 5,481 | 3,332 | -39% | 1 | 1 | 0% | 1,001 | 2,430 | +143% | 0 | 0 | — |
case-20 | pass→pass | 4,381 | 3,107 | -29% | 1 | 1 | 0% | 673 | 2,301 | +242% | 0 | 0 | — |
case-21 | fail→fail | 3,918 | 3,346 | -15% | 1 | 1 | 0% | 670 | 2,418 | +261% | 0 | 0 | — |
case-22 | fail→pass | 13,606 | 5,564 | -59% | 1 | 1 | 0% | 2,364 | 2,964 | +25% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +45 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.