Skip to main content
Date: 2026-07-17 · For: honest-scholar dataset capability (sub-spec 3). · Status: verified-source digest; migrates to the plugin’s resources/references/.

Bottom line

Thin custom datasets.yml + rclone (private mirror) + pooch (Tier-B fetch) + a ~200-line resolution-chain core. Reject DVC/DataLad/lakeFS/Quilt on dependency-weight grounds. Adopt huggingface_hub opportunistically for HF-hosted/gated data. git-annex is the fallback single-tool option if a Haskell binary is acceptable.

1. Tooling review

2. Private-mirror architecture — rclone

Single dep-free Go binary; Google Drive + S3/B2/R2/MinIO/SFTP/WebDAV/~65 more; remote:path; verifies integrity on transfer; rclone check/hashsum on demand. Registry names a remote + path; the credential-bearing config lives outside the repo:
Keep private while registry stays public: (1) gitignore rclone.conf, point via RCLONE_CONFIG=$PWD/.honest-scholar/rclone.conf, commit rclone.conf.example (name/type only); or (2) env-var remotes (RCLONE_CONFIG_<NAME>_TYPE=drive, _TOKEN=…) from CI secrets — preferred for CI. Caveats: rclone obscure is not encryption (never commit it); env-var remote names use underscores; GDrive service account for CI, MD5 present on all files, 750 GiB/day upload quota. Mirror × tier: A → redundant (skip, or large redistributable blobs); B → primary durability vs link-rot (populate on first fetch); C → essential (only re-fetchable copy after one-time gated acquisition).

3. Resolution chain fetch(name) — verify fixity at every hop

Standardize one hash across hops (MD5 = GDrive+S3 common; use rclone check --download if backends’ hash sets are disjoint). Expected hash lives in the manifest (single source of truth), never trust a backend-reported hash alone. Cache: gitignored; content-addressed on the wire (<alg>/<hash> → dedup, integrity==identity, like HF blobs/), name-addressed for use (symlink/copy).

4. Registry format

Own a thin datasets.yml (YAML: human-editable, comments, pyyaml). Do not adopt DVC’s .dvc/dvc.yaml (bound to DVC’s cache + ~40 deps; lacks multi-source fallback). Keep pooch’s registry.txt (name hash) as an optional export. hash carries an alg: prefix (self-describing). Fixity philosophy from BagIt: an entry is valid only when every listed checksum verifies.

5. Plugin vs repo split

Plugin: manifest schema + loader/validator; resolution-chain + per-hop fixity; rclone integration (subprocess copyto/check/hashsum; config via --config/env); Tier-B fetchers (pooch or minimal http/doi core) + Tier-A git/LFS + Tier-C drop-and-verify; cache policy; rclone.conf.example generator + secret-hygiene docs. Dep contract: rclone (binary subprocess, not a Python dep) + pyyaml + pooch. Consumer: the datasets.yml entries + checksums; the rclone remote config (real creds, untracked/CI); Tier-A blobs; the gitignored cache; any heavy loaders (datasets, pandas).

6. One skill or a set? — one skill, verbs register | fetch | verify | mirror | audit (+ init). Verbs share the schema/tier/cache/chain mental model and are sequential lifecycle steps; fetch = verify + mirror-populate composed; audit = verify across the manifest.

datasets.yml + pooch (Tier-B) + rclone (mirror, any backend) + ~200-line chain core; huggingface_hub opportunistic; reject DVC/DataLad/lakeFS/Quilt.

Sources

Git LFS spec/api; git-annex internals/special_remotes; DataLad (JOSS 10.21105/joss.03262); DVC docs + pyproject; HF Hub docs + setup.py; rclone docs (/s3,/b2,/drive,/docs env-vars); pooch (fatiando.org/pooch) + pyproject; BagIt RFC 8493; Zenodo policies. (URLs verified this session.)

Flags

No maintained rclone-native Git-LFS transfer agent found (LFS-over-rclone needs glue). DVC checksum-on-pull via maintainer forum post; ~40 deps = direct required; no-fallback inferred from docs. rclone env-var behavior partly via forum (standard). Dep lists from current main packaging (sets stable, versions drift).