Spec version gami-submit-1.0 · full specification in SPEC.md
This repository describes how to hand us the hashes and metadata for the material you want anchored, and contains the templates and the validator you need to do it. It is meant to be a one-time setup at your end: once your export produces this shape, every later delivery works the same way.
We never receive your files. You compute a hash of each file in your own environment, and only that hash leaves your systems.
A folder with two files:
example-2026-08-01-001/
manifest.json who is sending, when, and how the hashes were computed
records.xlsx one row per digital object (or records.csv)
The records table needs two columns to be usable: your own record identifier and the file hash. Everything else is optional.
| localId | file_hash | title | collection | dateCreated |
|---|---|---|---|---|
| EMA-00451 | sha256:4d9e8174b7ecc… | Gate photograph | Photograph Collection | 1945-04-29 |
Both are fully supported and produce identical results. Choose by how the file is produced:
- A person fills it in by hand → use
templates/records.xlsx. Every column in it is pre-formatted as Text, which prevents Excel from silently rewriting your values. Don't change the formatting, and format any columns you add as Text too. - A system exports it → use
records.csvand keep Excel out of the path.
The one combination to avoid is exporting a CSV and then opening and re-saving it in Excel. That gets you Excel's value rewriting and its encoding and delimiter quirks at the same time.
Why the formatting matters. In a normal Excel column, 00451 becomes 451,
PC/03/2024 becomes a date, and an 18-digit identifier loses its last digits.
None of those can be undone afterwards. The validator tells you when it has
happened, but the template stops it happening at all.
-
Copy
templates/to a new folder named after your submission. -
Delete whichever records file you are not using.
-
Fill in
manifest.json(contact details, how you computed the hashes), and setrecords_fileto the one you kept. -
Replace the three example rows with your own records.
-
Check it:
node scripts/validate-submission.mjs ./example-2026-08-01-001 --fix-manifestThe validator needs Node.js 20 or newer, nothing else. No installation, no network access — it reads
.xlsxfiles without any external library. It reports every problem with a row and column reference and a suggested fix, and it fills in the two manifest fields that are tedious to compute by hand. -
When it prints
PASS, send the folder as a.zip.
A clean validator run means the delivery imports on our side without anyone touching it by hand.
| Path | Purpose |
|---|---|
SPEC.md |
The full specification. Read §1.1 (Excel), §2 (three design rules) and §4.2 (the column list); the rest is reference. |
templates/records.xlsx |
Excel template — columns pre-formatted as Text, with an Instructions sheet. Start here if a person is filling it in. |
templates/records.csv |
Same three example records as CSV. Start here if a system produces the file. |
templates/manifest.json |
Manifest to fill in. |
scripts/validate-submission.mjs |
Validator and converter. Run before every delivery. |
scripts/metadata-hash.mjs |
Only needed for records whose metadata cannot be published (SPEC.md §5). |
scripts/lib/xlsx-read.mjs |
Dependency-free .xlsx reader used by the validator. Nothing to run directly. |
scripts/make-xlsx-template.mjs |
Regenerates templates/records.xlsx. For our use, not yours. |
Hashes must be SHA-256. If your preservation system only holds MD5 or SHA-1, tell us before building the export so we can agree on an approach.
localId must be stable forever. Use the identifier your system already
treats as the identity of the record. It is what lets a later correction be
matched to the record it corrects, so do not invent a new numbering scheme and do
not use a row number from the export. See SPEC.md §4.4.
Leave unknown fields empty. Not N/A, -, or unknown. Those become
literal metadata values that get signed and published.
In Excel, keep every column formatted as Text. Including columns you add. This is the single most common way deliveries get damaged before they reach us.
Your own fields are welcome. Prefix them x_ (x_inventarnummer,
x_signatur_alt) and send as many as you like. Nothing is discarded.
Approximate dates go in x_dateText. dateCreated holds machine-readable
dates only. "um 1943" belongs in x_dateText, with dateCreated left empty.
Sensitive metadata can stay with you. You can anchor a hash with no metadata
at all, or commit to metadata you keep private. See SPEC.md §5.
If something about your holdings does not fit this format, tell us rather than forcing it. The format is meant to accommodate how your catalogue already looks, and a field we have not anticipated is useful for us to hear about.
CC0 1.0 Universal — public domain. Implement, adapt, or build on this format freely, with or without attribution.