OpenEik.org

Draft OpenEik 0.3.0: draft, not final. From commit 197c2676 of 31 October 2026. Errata: the errata of 0.3. Raw text: /spec/0.3/assets.md. Earlier: OpenEik 0.1, OpenEik 0.2, kept as they were.

On this page

OpenEik 0.3 specification

Part XV. Assets

This part is a part of OpenEik 0.2. The steward asked for it on 18 October 2026: Part XIV keeps fonts, PDF renditions, outside drawings and signed containers as binary files by digest, and no version of 0.1 can hold one. It binds every conformance class it names (section 11; Conformance). OpenEik 0.1 had it as a proposal, which no class of 0.1 required: a reader of 0.1 leaves binary files alone, assets/ among them, and never removes them (Part III, 7, rule 2). The steward decided its six questions on 18 October 2026, as the proposal had them (open questions 30 to 35; section 12). Since 23 October 2026, @openeik/tools keeps assets in its versions, for every model of 0.2, and for a model of 0.1 with the proposal assets (section 11).

1. Status and scope

An asset is a binary file of a model, kept by the SHA-256 of its bytes: a PDF rendition or an outside drawing, a font, a signed container, a photograph attached to a review. Part XIV names its assets at assets/<sha256>.<ext> (Part XIV, 7.3). A later version may add other kinds, such as the large meshes of declared geometry (Part II, 6.6, rule 6).

A version of 0.1 holds records and kept files, each as the canonical form of JSON text (Part VI, 1), and a kept file is UTF-8 text of at most 1 MiB (Part III, 7, rule 2). A binary file is left alone: no version holds it, no store keeps it, and a push, a pull or a clone leaves it behind. So a drawing issued with its fonts and its PDF/A rendition reaches another store without them, and its sign-offs name a file that no one there can fetch.

This part keeps an asset in a version as Git LFS keeps a large file in a git repository: by its digest. In a folder, an asset is the file itself. In a version's tree, it is a small pointer that names the bytes by their SHA-256 and their length. The bytes are kept beside the versions, in the store, by their digest, and travel with a push, a pull and a clone. Since a version names an asset's bytes by their digest, its root hash commits to them (section 3); and since the bytes are not in the version, a store can let go of bytes that have to go without rewriting any version (section 7).

1.1 The parts it extends

In 0.2 its text stays in this part. These are the sections of Parts I to VIII and of the other parts that it extends, where a later version may move it:

  • Part III: assets/ in the folder (1), assets as a file kind of their own beside records and kept files (3 and 7), and what the single-file form leaves out (11, rule 3);
  • Part VI: pointers in trees (2), assets in a diff and a merge (4 and 5), and in a fetch, a push, a pull and a clone (6);
  • Part XIV: 7.3 and 7.4, rule 5 point to this part, whose kinds add the photographs that 13.2 attaches;
  • Conformance: what a reader, a writer, a validator and a version store do with assets;
  • Security and privacy: assets in 2.4, 5.3, 7.1 and 11;
  • the extension registry: assets becomes a folder the standard gives, no longer one it plans.

2. In a folder

  1. An asset is the file assets/<sha256>.<ext>: <sha256> is the SHA-256 of the file's bytes, as 64 lowercase hexadecimal digits, and <ext> the extension of its kind (section 4). assets/ holds assets only, and no folder.
  2. An asset is never changed: its name is its bytes' digest. A writer MUST write an asset's bytes as they are, and MUST NOT write over an asset.
  3. A file in assets/ whose bytes do not give its name, or whose name is not an asset's, is not an asset. A reader MUST NOT read it as one: it reports the file and leaves it alone. A validator reports it as an error.
  4. A writer MUST NOT remove an asset that the model names (section 8). It MAY remove one that the model does not name.
  5. An asset is not a kept file: Part III, 7's limits of size and of text do not hold for it, and section 4's do.

3. In a version

  1. In a version's tree, an asset is the leaf at its path in the folder, assets/<sha256>.<ext>, extension included. Its object is the asset's pointer: the canonical form (Part III, 6) of {"asset": {"bytes": <n>, "sha256": "<sha256>"}}, where bytes is the file's length in bytes and sha256 its name's digest.
  2. A reader of versions MUST refuse a version that holds, under assets, a sub-tree that is not a shard (Part VI, 2.3), or a leaf that is not such a pointer or whose sha256 is not its name's digest, naming the entry.
  3. The bytes are not in the tree. A version store keeps them beside its objects, by their SHA-256 (section 5).
  4. A version's root hash commits to every asset the version holds: two versions with one root hash name the same bytes, by the same digests.
  5. Making a version from a folder makes each asset's pointer, and writing a version into a folder writes each asset's bytes at its path. Neither changes a byte.
  6. A diff reports an asset added or removed, by its path (Part VI, 4). An asset is never changed: other bytes are another asset, at another path.
  7. A merge merges pointers file by file, as it merges kept files (Part VI, 5, rule 5). An asset added on both sides is one asset. A merge that removes an asset which the merged model names MUST be refused, naming the asset and what names it (Part VI, 5, rule 7).

A folder holds a PDF rendition of 812 344 bytes at assets/<sha256>.pdf. The version's tree holds, in its sub-tree assets, the entry ["<sha256>.pdf", "b", "<the pointer's hash>"], and the pointer is

{"asset":{"bytes":812344,"sha256":"<sha256>"}}

4. Kinds and limits

ExtensionMedia typeWhatIts bytes begin with
pdfapplication/pdfa PDF rendition, an outside drawing (Part XIV, 8.3 and 15)%PDF-
ttffont/ttfa TrueType font of the drawing profile (Part XIV, 4.1)00 01 00 00 or true
otffont/otfan OpenType font with CFF outlinesOTTO
asiceapplication/vnd.etsi.asic-e+zipa signed container of the legal tier (Part XIV, 14.6)PK 03 04, its first entry mimetype
pngimage/pngan image attached to a review item (Part XIV, 13.2)89 50 4E 47 0D 0A 1A 0A
jpgimage/jpega photograph attached to a review itemFF D8 FF
  1. An asset MUST be of one of these kinds. Its bytes SHOULD begin as its kind's do; a validator warns about one that does not.
  2. An asset MUST be at most 64 MiB (67 108 864 bytes), as an issued drawing is (Part XIV, 7.3). A host MAY set a lower limit, and a quota for a building, and says what they are.
  3. A later version may add kinds. A reader keeps an asset of a kind it does not know: in a folder it leaves the file alone, and in a version it keeps the pointer and writes it back. A writer of 0.2 MUST NOT write one.

5. In a store

  1. A version store keeps the bytes of assets by their SHA-256, beside its objects. When it takes bytes in, it MUST check that their SHA-256 and their length are those of the pointer that names them, and refuse them otherwise.
  2. A store that others fetch from (a host) MUST hold the bytes of every asset that a version on one of its refs names, unless it has withheld the asset (section 7). It MUST NOT move a ref to a version that names an asset whose bytes it neither holds nor has withheld.
  3. A store MAY hold a version without its assets' bytes, and fetch them when they are needed: a partial store, as a clone with Git LFS is. Asked for an asset it lacks, it MUST say that it lacks it, and never answer with other bytes.
  4. A store answers for an asset, with its bytes or with whether it holds them, within one building only: to a caller who may read the building, about the assets its versions name, and to a caller who may push to it, about the assets a push sends. An answer for a digest says that the file exists: a store that keeps one copy of some bytes for several buildings MUST NOT let its answer for one building tell of another's.

6. Push, fetch, pull and clone

  1. A push sends, before it moves the remote ref (Part VI, 6.3), the bytes of every asset that a version it sends names and that the remote lacks. Only bytes the remote lacks are sent. A squashed push (Part VI, 6.3, rule 3) sends one version, and so the assets of the newest tree only.
  2. A fetch reads the objects it needs, pointers among them (Part VI, 6.2). It MAY leave the bytes behind.
  3. A pull or a clone into a folder MUST fetch the bytes of every asset of the version it writes, and check each as section 5, rule 1 says, before it writes anything. An asset that it cannot fetch, or that fails the check, stops it, naming the asset, unless the asset is withheld (section 7).
  4. A store that pulls or clones without writing a folder MAY fetch the bytes later, when an asset is read.

7. Withheld assets

  1. A store MAY withhold an asset: let go of its bytes, keep every pointer to it, and record that it is withheld. It does so when the asset has to go: personal data that a person asks to have erased (Security and privacy, 2.4), a licence that has ended, an order. A withheld asset stays withheld in that store.
  2. A version that names a withheld asset stays readable. A reader reports the asset as withheld, a warning; a checkout writes no file for it; and a validator does not count it as missing (section 8, rule 2).
  3. A push of a version that names an asset withheld at the pushing store says so. The remote MAY then accept the version and record the asset as withheld, or refuse it.
  4. What was signed by the asset's digest stays signed (Part XIV, 14), and can no longer be checked against its file: a reader says so.

8. References

  1. Part XIV names assets by path, assets/<sha256>.<ext>: an unlinked drawing's file.asset (8.1 and 8.3), the drawing profile's fonts[].file (4.1), a review item's attachments[].asset (13.2), and a sign-off's legal.asset and its statement's subject (14.1, 14.2 and 14.6). Its register names them by digest (11.1). A sha256 given beside a path MUST be the path's digest.
  2. In a model, an asset named by path MUST be in it: in a folder, its file; in a version, its pointer. A validator reports one that is not as an error, and one that is withheld as a warning.
  3. An asset that no member of the model names is unused. A validator MAY warn about it, and a writer MAY remove it (section 2, rule 4); the versions before keep it.
  4. A digest without a path names a file the model need not hold: a font that the project may not store (Part XIV, 4.3, rule 4), or a rendition that was not kept (Part XIV, 15.2, rule 5).

9. The single-file form, git and hosts

  1. The single-file form (Part III, 11) carries no asset. Its members name assets by path, and the assets travel beside it, in a folder assets/ next to the file. Reading a folder into one file and writing it back loses no asset only when the assets travel so; Part III, 11, rule 3 counts them among what the single-file form may lose.
  2. A folder kept in git keeps its assets as files. A tool SHOULD mark assets/** as binary (-text), as Part XIV, 1.5 says, and MAY keep them with Git LFS, whose pointer names the same SHA-256 as this part's.
  3. A host whose store takes only JSON text keeps no asset until it keeps bytes beside its objects. Until then it MUST NOT move a ref to a version that names an asset (section 5, rule 2).

10. Security and privacy

  1. No asset is code (Security and privacy, 11). A reader that shows an asset MUST NOT run anything it holds: a PDF's scripts, actions and launch links, or a program in a container. It reads a rendition's attachments as data, to check them against the issued files (Part XIV, 15).
  2. Fonts. A reader that draws with a font from a model SHOULD pass it through a font sanitiser first, as browsers do with fonts from the web: font files have carried attacks on the programs that draw them.
  3. Containers. A reader that opens a container MUST bound the number and the size of its entries, and refuse an entry whose path leaves the container.
  4. Bounds. A reader of a model from a source it does not control SHOULD bound how many assets, and how many bytes in all, it fetches and keeps (Security and privacy, 7.2).
  5. Integrity. An asset is checked by its SHA-256 wherever it arrives (section 5, rule 1). A store that answers other bytes for a digest is refused (section 6, rule 3).
  6. Photographs are personal data. A photograph shows people, places and things, and its metadata may say where and when it was taken, and with which camera. A writer SHOULD take that metadata out of a photograph before it becomes an asset: once named by its digest, its bytes are fixed. A store withholds a photograph that a person asks to have erased (section 7).
  7. Confidential files. An outside drawing or a rendition is as confidential as the model it is in. A host gives an asset only to those who may read a version that names it (section 5, rule 4). A host that narrows what a member reads by folder treats assets/ as a folder like any other.
  8. Serving a file. A host that serves an asset over the web SHOULD send it with its kind's media type and as a download, never as a page of its own site: a file that a browser takes for a page could run there.

11. Conformance

A validator of 0.2 checks section 2's names against the bytes, section 4's kinds and limits, section 3's pointers in a version, and section 8's references. A version store of 0.2 keeps bytes as section 5 says, and moves them as section 6 says.

  • checks a folder's assets as sections 2 and 4 say;
  • makes each asset's pointer in a version, and reads and checks the pointers of a version it reads (section 3);
  • sends the bytes a store lacks before a push moves its ref, and fetches and checks every asset of the version a clone or a pull writes before it writes anything (section 6);
  • merges a pull's assets file by file, refusing a merge that removes an asset the merged model names (section 3, rule 7);
  • keeps the pointers of assets a store has withheld (section 7).

It talks to a store through the three assets calls of the store API it speaks, which the guide Reading and saving models describes (section 5.2), and has 8 conformance cases for a folder's rules, in the suite of 0.2 (conformance/). Since 30 October 2026 it keeps an asset of a kind it does not know as section 4, rule 3 says: a clone or a pull keeps its pointer and writes no file of it, and the folder's next push writes the pointer back unchanged.

The reference implementation keeps the PDFs it publishes as files of its project, outside the model, and its issued SVGs as kept files (Part XIV, 1.5). A store that takes objects as JSON text, and checks each object's hash against its text, cannot hold an asset as an object.

12. The decisions

The steward decided open questions 30 to 35 on 18 October 2026, each as this part proposed it.

QuestionDecisionDecided
30How a version holds an asseta pointer leaf of JSON text, with the bytes beside the version (section 3)
31The kinds of 0.2pdf, ttf, otf, asice, png and jpg; meshes later (section 4)
32The size of an assetat most 64 MiB, and a host's own limit and quota below it (section 4)
33Whether a fetch may leave bytes behindyes; a pull or a clone into a folder fetches what it writes (section 6)
34Whether a store may withhold an assetyes, keeping every pointer to it (section 7)
35Who may remove an unused assetany writer; the versions before keep it (sections 2 and 8)