Skip to main content

holdings — v0.1 of the placement catalog

A disposable, regenerable catalog answering: which media hold which files? Single file, stdlib only, Python 3.9+. SQLite for placement truth; semantics belong to OntoDAG (see Projection contract below).

Design contract (the important part)

  1. Observer, not authority. holdings only reads filesystems and backup listings. It never writes to your data, never sits in the backup or sync path. Deleting holdings and its database costs nothing but convenience.
  2. Everything is regenerable by re-scanning. The catalog is a cache of facts about the world. The only original data in the whole system is your human OntoDAG categorization — which holdings never touches.
  3. Content hash is identity. sha256:… is the primary key everywhere. Paths, media, snapshots, categories: all attributes of a hash.
  4. Single writer, many readers. Scan on the backup-node laptop. Put the SQLite file in a Syncthing folder; every device then carries the full index of everything — including drives offline in another country.

Quick start

export HOLDINGS_DB=~/Sync/catalog/catalog.sqlite   # put it in a synced folder

# Register your media once:
./holdings.py add-medium laptop-x1       --kind laptop --location "with me"
./holdings.py add-medium drive-budapest  --kind drive --backup --location "safe, Budapest"
./holdings.py add-medium drive-standrews --kind drive --backup --location "office, St Andrews"
./holdings.py add-medium restic-b2       --kind restic-repo --backup

# Scan whenever a medium is mounted (fast on rescan: unchanged files
# are recognized by size+mtime and not rehashed):
./holdings.py scan drive-budapest /media/peter/backup-drive
./holdings.py scan laptop-x1 /home/peter --exclude-file ~/backup/excludes.txt

# Count backup snapshots as copies (approximate matching by name+size;
# for exact hashes, `restic mount` the repo and `scan` it instead):
restic -r b2:bucket:repo ls --json latest | ./holdings.py import-restic restic-b2 -

Queries

./holdings.py whereis holiday.jpg        # every medium+path holding this content
./holdings.py whereis sha256:45887c...   # by hash
./holdings.py redundancy --min-copies 2  # content below 2 backup copies
./holdings.py only-on drive-budapest     # DANGER LIST: exists nowhere else
./holdings.py diff drive-a drive-b       # on A but not B
./holdings.py media                      # media overview
./holdings.py stats                      # totals

redundancy turns your 3-2-1 policy into a checkable report. only-on is the consolidation to-do list for old scattered drives: run it, back those files up via restic, rescan, watch the list empty, then wipe the drive with confidence.

Projection contract (OntoDAG integration)

(2026-08-20: this contract's canonical statement now lives at the meet point — ontodag docs/plans/PROJECTIONS.md — which generalizes it across sources (files here, messages in ucomm) and adds retention classes. The rules below remain the agreed file-side instance and the wire format is unchanged.)

./holdings.py project-ontodag --out placement.jsonl

Emits JSON lines: {"item": "<hash>", "supercategories": ["sys:on:<medium>", "sys:type:<ext>", "sys:backup:<n>"]} — matching OntoDAG's put(item, supercategories) model.

The agreed rules for the ingesting side:

  • everything under the sys: namespace is machine-written, regenerable cache — never hand-edit, never treat as authoritative;
  • ingestion is an idempotent full rebuild: drop all sys: memberships, re-ingest the stream (no incremental diffing — staleness is the only permitted failure mode, drift is not);
  • the projection is rebuilt locally on each device from the synced SQLite, not synced itself; only the human layer of the DAG is persisted and synced (it is the irreplaceable original data — back it up like the KeePass vault);
  • human categories are attached to the same hash-identified items, giving unified queries like get(photo, vienna, sys:on:drive-budapest).

See ontodag_ingest.py for an adaptation template.

Notes & limits (v0.1)

  • import-restic matches listing entries to known content by basename+size and only when unique; ambiguous entries are recorded as unverified: placeholders. Scanning a restic mount gives exact hashes.
  • Symlinks are skipped. Hidden config/caches are excluded by default (.cache, .config, .git, node_modules, Syncthing internals, …); add your own with --exclude-file.
  • Concurrent writes are not supported by design (single-writer model).
  • Roadmap (from the discussion): v0.2 Syncthing REST adapter; v0.3 OntoDAG join live; v0.4 FastAPI localhost UI; v0.5 WASM/PWA read-only viewer for phones off the synced SQLite.

Download files

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

Source Distribution

holdings-0.1.0.tar.gz (11.3 kB view details)

Uploaded Source

Built Distribution

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

holdings-0.1.0-py3-none-any.whl (11.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: holdings-0.1.0.tar.gz
  • Upload date:
  • Size: 11.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for holdings-0.1.0.tar.gz
Algorithm Hash digest
SHA256 678dcba04fe0a57cd682767b2c70d3f789c4a3c03055738e3e778ee25cc75b12
MD5 345e8b37904fe9e6cb7d6c24027b9997
BLAKE2b-256 ae2f9010b933080181a1ed35d35986b17684c06b5fb13c6e2d57cc6c9930bf13

See more details on using hashes here.

File details

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

File metadata

  • Download URL: holdings-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for holdings-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 72e77d16680a83617a86a611521f984bef60de5346f6ad431e60847ebb2feebc
MD5 3d686732218875219cf4faf2070d32e4
BLAKE2b-256 f888d9f22845bc7350d8787c688d7a7da2cf57ce7339354fe64ba68299fb14bc

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page