Skip to content

manifest.json

manifest.json is required, and a reader SHOULD be able to answer three questions from it alone, before touching anything else: can I read this version, what is in the file, and is any of it damaged.

{
"formatVersion": 1,
"generatorApp": "StitchPencil",
"generatorVersion": "0.1",
"created": "2026-07-11T12:00:00Z",
"title": "Koi Pond",
"entries": [
{ "path": "document.json", "sha256": "<hex>", "role": "document", "derived": false },
{ "path": "plan.json", "sha256": "<hex>", "role": "plan", "derived": true },
{ "path": "preview.png", "sha256": "<hex>", "role": "preview", "derived": true },
{ "path": "references/1a2b….jpg", "sha256": "<hex>", "role": "reference", "derived": false }
]
}
FieldTypeRequiredMeaning
formatVersionintegeryesContainer format version. Increases only on breaking changes.
generatorAppstringnoWriting application’s name. Informational.
generatorVersionstringnoWriting application’s version. Informational.
createdISO-8601 stringnoDoubles as the last-saved timestamp: the manifest is rewritten on every save.
titlestringnoMirrors the document title.
entriesarrayyesOne record per archive entry, see below.
FieldTypeRequiredMeaning
pathstringyesEntry name inside the archive.
sha256hex stringyesLowercase hex SHA-256 of the entry’s uncompressed bytes.
rolestringyesWhat the entry is. Open set — see below.
derivedbooleanyesTrue if the entry can be regenerated from document.json.

Defined roles are document, plan, preview and reference. The set is open: readers MUST tolerate roles they do not know, and MUST NOT fail a file because of one.

title duplicates a value that also lives in document.json. That redundancy is deliberate: a gallery listing fifty projects can render name, thumbnail and date from manifest.json plus preview.png, without inflating and parsing fifty documents. If the two disagree, document.json wins — it is the source of truth, and the manifest copy is a cache.

sha256 is computed over the entry’s uncompressed bytes. Verification is not optional, but what a reader does on failure depends on what failed:

Failing entryRequired behaviour
document.jsonThe file is corrupt. Fail the load with a clear error.
A derived entry (plan, preview)Drop the entry, continue. It can be regenerated.
A reference entryDrop the image, keep the project, continue.

This is partial recovery, and it is the point of per-entry checksums rather than one over the whole archive: a truncated preview should cost you a thumbnail, not a design.

Note that ZIP’s own CRC-32 is a separate, weaker check on a different layer. Readers MUST verify both — CRC-32 per entry as the archive is read, SHA-256 per manifest record afterwards.

An archive may contain entries that the manifest does not mention. Readers MUST ignore them rather than treating the mismatch as corruption; this is how future revisions add content without breaking existing readers.

The converse — a manifest record whose entry is missing — is treated exactly like a checksum failure for that role, using the table above.