.format · §5
Manifest.
The manifest is the small signed head of a .lim image. 16-byte header, nine sections, Merkle root. The ManifestRoot it produces is the image's identity — every URL, container ID, content hash, and IPFS CID that references the image resolves to it.
§5.1 · MAGIC + FORMAT HEADER
The 16-byte header.
The first 16 bytes of every .lim manifest. Three independent per-layer version numbers (u16 LE each) and 4 reserved bytes that MUST be zero. The magic LMFS(0x4C 0x4D 0x46 0x53) lets readers reject misidentified bytes before parsing anything else.
Byte offset → 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
┌────┴────┬────┴────┬────┴────┬────┴────┬────┴────┬────┴────┬────┴────┬────┴────┐
Field │ magic ("LMFS") │ drop_store_ │ metadata_ │ manifest_ │ reserved │
│ │ version │ version │ version │ (4 bytes) │
│ │ (u16 LE) │ (u16 LE) │ (u16 LE) │ MUST be 0 │
└─────────────────────┴──────────────┴─────────────┴─────────────┴────────────────┘
Bytes 4 2 2 2 4
Total: 16 bytes (128 bits).
| Offset | Size (B) | Field | Meaning |
|---|---|---|---|
| 0 | 4 | magic | The bytes 0x4C 0x4D 0x46 0x53 ("LMFS"). Lets readers reject misidentified bytes before parsing the rest. |
| 4 | 2 | drop_store_version | u16 LE. Drop store layer version. Bumped on wire-format-breaking changes to §3 (slabs, drop records, solid windows, EC shards). |
| 6 | 2 | metadata_version | u16 LE. Metadata layer version. Bumped on wire-format-breaking changes to §4 (inodes, Merkle B-tree nodes, slice maps). |
| 8 | 2 | manifest_version | u16 LE. Manifest layer version. Bumped on changes to the section layout or the Merkle root construction. |
| 10 | 4 | reserved | 4 bytes, MUST be zero. Reserved for future header fields. Readers MUST reject non-zero reserved bytes. |
Compatibility rule
A reader declaring spec vX.Y MUST accept any image whose drop_store_version,metadata_version, and manifest_version are each ≤ the reader's declared maximum for that layer. If any version exceeds the reader's limit, the reader returns UnsupportedVersion { layer, version, max }.
§5.2 – §5.10 · THE NINE SECTIONS
After the header.
Sections appear in the order they're hashed into the Merkle root (see below). Optional sections are FlatBuffers-equivalent tables that may be absent — readers detect presence by section ID. Each section is independently versioned by the manifest header's per-layer versions.
Feature flags
List of (flag_id: u16, required: bool). Each flag references the feature-flag registry. Required-unknown ⇒ UnsupportedFeature; optional-unknown ⇒ ignore.
Metadata reference
BLAKE3(metadata blob) + locator. Merkle root commits to this hash directly so an attacker cannot swap the metadata blob.
Slab index
Every slab referenced by the image, with mirror lists of locator entries. Slabs in the index MUST be referenced by ≥1 drop.
Crypto params
image_key_id (0x00 = plaintext; else AEAD id) + image_key + recipients[] (HPKE envelopes) + optional sigstore signature_bundle.
EC params
k, m, polynomial (default 0x011D for GF(2^8)), per_slab_overrides. Absent ⇒ no EC.
DMS policy
Dead Man's Switch / key escrow. v0.1 supports Shamir k-of-n only (time-lock deferred). Absent ⇒ no escrow.
Delta linkage
base_root (parent image's ManifestRoot) + tree_ops[]. Absent for non-delta images; readers detect deltas by section presence.
History
Append-only log of operations: build, delta, flatten, turnover, deepen. Each entry: op, timestamp, inputs[], params.
Merkle root
BLAKE3 of the Merkle hash list (see below). The image's identity.
§5.10 · MERKLE ROOT CONSTRUCTION
How identity is computed.
The Merkle root is a flat construction (not a deep tree) over the metadata blob hash and the section hashes. A flat construction lets each section be verified individually without loading siblings — important for HTTP range streaming and partial verification.
ManifestRoot = BLAKE3(
"limnifs/v1" // domain separator; prevents cross-protocol confusion
|| H(metadata) // the layer-2 metadata blob's BLAKE3
|| H(format_header) // the 16-byte header
|| H(feature_flags)
|| H(metadata_reference)
|| H(slab_index)
|| H(crypto_params)
|| H(ec_params) // empty hash if section absent
|| H(dms_policy) // empty hash if section absent
|| H(delta_linkage) // empty hash if section absent (non-delta image)
|| H(history)
)
The domain separator "limnifs/v1" prevents cross-protocol confusion — the same bytes hashed under a different prefix produce a different root, so LimniFS roots can never be confused with another system's hashes. The metadata hash appears directly in the hash list so an attacker cannot swap the metadata blob without invalidating the root.
Why flat, not deep?
A deep Merkle tree over sections would require loading sibling hashes to verify any one section. A flat construction (hash of section hashes) lets each section be verified with just its own bytes plus the root. The trade-off is that updating one section invalidates the root — but LimniFS images are immutable, so that's not a cost we pay.
FULL LAYOUT
The whole manifest, ASCII.
┌──────────────────────────────────────────────────────────────────────────────┐
│ .lim image — manifest section │
│ │
│ ┌────────────────────────────────────────┐ ← offset 0 │
│ │ §5.1 MagicHeader (16 B) │ │
│ │ "LMFS" │ drop_store_v │ metadata_v │ manifest_v │ reserved │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ ← offset 16 │
│ │ §5.2 Feature flags section │ │
│ │ flag_count: u32 LE │ │
│ │ flags[]: (flag_id: u16, req: u8)[] │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ §5.3 Metadata reference section │ │
│ │ H(metadata): 32 B │ │
│ │ locator_scheme: u8 │ │
│ │ locator_data: varint-length string │ │
│ │ inline_blob: varint-length bytes │ (when scheme = inline) │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ §5.4 Slab index section │ │
│ │ slab_count: u32 LE │ │
│ │ slabs[]: (slab_id: 40 B, locators[]) │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ §5.5 Crypto params section │ │
│ │ image_key_id: u8 │ │
│ │ image_key: 32 B (iff key_id != 0) │ │
│ │ recipients[]: HPKEEnvelope[] │ │
│ │ signature_bundle: SignatureBundle? │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ (optional — present iff EC) │
│ │ §5.6 EC params │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ (optional — present iff DMS) │
│ │ §5.7 DMS policy │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ (optional — present iff delta)│
│ │ §5.8 Delta linkage │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ §5.9 History │ │
│ │ entry_count: u32 LE │ │
│ │ entries[]: HistoryEntry[] │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ §5.10 ManifestRoot (32 B) │ │
│ │ BLAKE3 of the Merkle hash list above │ │
│ └────────────────────────────────────────┘ │
│ │
│ Optionally: sigstore signature bundle over ManifestRoot (§15.3) │
└──────────────────────────────────────────────────────────────────────────────┘
See limnifs/specfor the full multi-file spec (concepts → wire-format → bit-level → algorithms → conformance → adapters).