Skip to content

RO-Crate export

What ATRIUM can publish as an RO-Crate, the run description every service returns, and how the blocks page-classification and the translator write are carried into a crate.

Scope

The exporter handles every block. The mapping below is for the blocks these two tools write, taken from the exporter's own output. docs/rocrate_export.md is the full guide, including an RO-Crate tutorial from zero.

RO-Crate in one paragraph

An RO-Crate is a folder with one extra file, ro-crate-metadata.json: a JSON-LD description of what is in the folder, who made it, with which software, and under which licence — written in schema.org terms so that repositories and catalogues can read it without knowing anything about ATRIUM. ATRIUM's exporter, atrium_rocrate.py, writes RO-Crate 1.2 with the Process Run Crate 0.5 profile, the pair agreed with AMČR, which stores every archived record as an RO-Crate (atrium-project#71). It turns a document record into such a description, a set of records from one run into a crate of crates, and one run of one tool into a CreateAction.

A crate is what a repository, a catalogue or a reviewer receives: the data files plus a description they can read with generic RO-Crate tooling — who produced what, with which program and version, when, under which licence — without running any ATRIUM code.

What happens to these two tools' blocks

Exporting the worked-example record — page-classification's page_categories and pages, then the translator's translations and derived_from — with each run's paradata gives 22 entities:

In the record In the crate What the crate carries
page_categories: {"1": "TEXT_P"} a DefinedTerm https://w3id.org/atrium/page-category/TEXT_P, in the DefinedTermSet …/scheme/page-category, listed in the root's about the label: a crate says the document is about TEXT_P; the per-page assignment stays in the record
pages[].category, pages[].category_confidence the same DefinedTerm, de-duplicated the label, once; the confidence stays in the record
translations a #block-translations CreativeWork, in the result of the translator's run the block and its date; the language pair, backend and output mode stay in the record
derived_from.translated_xml a File CTX000000003-1_en.alto.xml, encodingFormat: application/alto+xml, in the root's hasPart the translated file, by the name the translator records; with the folder at hand, its contentSize
derived_from.classification (when present) a File in hasPart page-classification's result table for the run
each assembled.blocks stamp a #block-<name> CreativeWork with recordBlock and dateModified the block; the run that wrote it lists it as result
each provenance.contributors[] entry a CreateAction with the run's run_uuid as @id (#run-<program>-<run_id> for a record written before it existed) who ran, when (startTime/endTime), in which image, with what status, and what they produced
each program a SoftwareApplication whose @id is its release page, with version, the repository url and the authors as creator the program, its version and its authors; without paradata the id is the repository and the version reads unrecorded
provenance.license the root's license the record's computed licence label, stated as the crate's licence today. It is not the licence of the crate's contents; the proposal on #6 stops writing it (Licences and paradata)

The root declares the Process Run Crate profile; the project's authors appear as ORCID Person entities, the creator of each tool.

For page-classification's half of that record, the heart of the output reads:

{ "@id": "./", "@type": "Dataset",
  "name": "ATRIUM document record CTX000000003", "identifier": { "@id": "#doc_id" },
  "conformsTo": { "@id": "https://w3id.org/ro/wfrun/process/0.5" },
  "about": [ { "@id": "https://w3id.org/atrium/page-category/TEXT_P" } ],
  "license": { "@id": "https://opensource.org/license/mit/" },
  "datePublished": "2026-09-22",
  "mentions": [ { "@id": "#run-page-classification-260922-220516" }, "…" ] },
{ "@id": "#run-page-classification-260922-220516", "@type": "CreateAction",
  "instrument": { "@id": "https://github.com/ufal/atrium-page-classification/releases/tag/v1.9.0-beta" },
  "containerImage": { "@id": "#image:ghcr.io/ufal/atrium-page-classification:1.9.0-beta" },
  "startTime": "2026-09-22T22:04:58+00:00", "endTime": "2026-09-22T22:05:16+00:00",
  "actionStatus": "http://schema.org/CompletedActionStatus",
  "result": [ { "@id": "#block-page_categories" }, { "@id": "#block-pages" } ] },
{ "@id": "https://github.com/ufal/atrium-page-classification/releases/tag/v1.9.0-beta",
  "@type": "SoftwareApplication", "name": "atrium-page-classification", "version": "1.9.0-beta",
  "url": "https://github.com/ufal/atrium-page-classification",
  "creator": [ { "@id": "https://orcid.org/0009-0002-4773-2797" }, "…" ] }

What every service returns: the run

Each service answers a successful call with its run as paradata: one Process Run Crate CreateAction for that call, built by atrium_rocrate.create_action(). Its @id is the run_uuid the call stamped into the record it returned; its instrument is the tool at its release; its containerImage is the image it ran as; its object is the upload (by content hash) and the record it was handed; its result is the blocks it wrote; its agent is the operating organisation when ATRIUM_RUN_AGENT is set; and paradataRecord carries the run's whole paradata record. It is what AMČR stores as the run's paradata file.

A fragment is the same kind of entities without a descriptor or a root, for a crate someone else owns: atrium_rocrate.py --document … --fragment for a record, action_fragment() for one service's action. The host keeps its own root ./, lists the actions in its mentions and declares the profile.

Properties of a crate

  • It is deterministic. Entities are merged by @id, the descriptor and the root come first, everything else is sorted by @id, and the JSON is written with sorted keys. The same record always produces byte-identical output, so a crate can be diffed and committed.
  • datePublished is derived, not stamped. It is the newest of the record's block stamps and contributor times, cut to a date — never the export clock.
  • Identifiers are stable. A run is its run_uuid, a tool its release page, an uploaded file its content; the exporter mints none of them.
  • Granularity survives. Each block keeps its own entity and each run lists the blocks it wrote, so "who produced the page categories" and "who produced the translation" have separate answers.
  • Controlled values become resolvable terms, under the SKOS URIs.
  • It is validated. The hub's CI runs the RO-Crate validator on the module's sample crates and on the end-to-end run's record, once for RO-Crate 1.2 and once for Process Run Crate 0.5.

Running the exporter

The exporter is vendored into every tool as atrium_rocrate.py and runs as a separate step, over records that already exist — a tool run writes records, and a crate is made from them when they are to be published:

python atrium_rocrate.py --document CTX000000003.document.json --paradata run1.json --paradata run2.json --out-dir crate/
python atrium_rocrate.py --document CTX000000003.document.json --fragment
python atrium_rocrate.py --run 1.document.json 2.document.json --paradata run.json --out-dir crate/
python atrium_rocrate.py --selftest

--document writes one document's crate (--data-dir adds the files' sizes); --fragment its entities only (--wrap puts them under a stub root); --run writes a run crate whose hasPart holds one sub-crate per document. The write is atomic.

A crate describes; it does not replace the record. Per-page detail — which page carries which category, with what confidence, and the language pair of a translation — stays in the record, which can itself be shipped inside the crate as one of its files. rocrate_export.md §8 lists what the export leaves for later work.

Where RO-Crate sits among the standards

RO-Crate is one of the standards the project's data management plan names, alongside CIDOC-CRM, SKOS, PeriodO, Getty AAT, TEI, DataCite and IIIF. The ecosystem deliberately does not apply heavyweight ontologies — W3C PROV-O, CIDOC-CRM — during raw extraction over a corpus of more than a million pages: the record stays a plain JSON document, and the crate is the view that a catalogue reads. rocrate_export.md §3 is the reasoning in full.

Sources

This table records provenance: what this page was written from, not a build instruction.

Source What was taken from it
atrium-project/docs/templates/shared/atrium_rocrate.py — run on the worked-example record with its paradata the mapping table and the JSON excerpt
atrium-project/docs/rocrate_export.md §§3, 4.1, 5, 7, 8, 9 the design and the reasoning