Everything is a directory.
The unit of exchange is a bundle: a plain directory containing a manifest and a flat store of content-addressed files. It is not a database, not an archive format, and not a container. This is the single most important decision in the protocol, and every other property falls out of it.
Because a bundle is an ordinary directory of ordinary files, it can be copied by any tool that has ever copied files — cp, rsync, a sync client, a torrent, a file manager, a phone plugged into a laptop. No implementation has to agree with any other about anything but the layout.
bundle/
├── commons.json the manifest
└── blobs/
├── 4c1a9e2f… one file per work, named by hash
├── b70f2213…
└── e0d84a97…
The manifest is UTF-8 JSON. Core keys are fixed; anything else is namespaced and ignorable.
{
"rcp": 1,
"id": "sha256:9f2b6c04…",
"title": "Harbour Road Oral History",
"parent": null,
"works": [
{
"blob": "sha256:4c1a9e2f…",
"media_type": "audio/flac",
"title": "Interview 04 — the strike winter",
"contributors": ["A. Mensah", "recorded by J. Okonkwo"],
"recorded": "2026-02-19",
"rights": "CC BY-SA 4.0",
"duration_s": 3241
}
]
}
Every blob value is the hash of the bytes it names, so a file can be verified by anyone, offline, without asking a server whether it is authentic. A bundle that fails verification is not a trust question. It is a corrupt file.