Specification 1.0-rc
Version 1.0-rc, candidate. The conformance language of RFC 2119 and RFC 8174 applies: MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described there when, and only when, they appear in capitals.
Candidate status means the information model is believed complete and no further breaking change is planned. Changes may still be made in response to implementation experience, and each will be recorded as an erratum or a new version. This version is suitable for writing an independent implementation against.
It is not yet stable. Stability — the promise that the normative text will not change and that an artifact valid under it stays valid — is what 1.0 will carry, and §13 says exactly what has to happen first.
1. What an AKP is§
An AKP artifact is a single file carrying a set of source documents, the knowledge derived from them, and for every piece of that knowledge a reference back to the exact place it came from.
Three properties define it, and a consumer MUST be able to establish all three from the artifact alone, with no network access and no service:
- Identity — two artifacts with the same canonical content have the same identity.
- Provenance — every knowledge object resolves to a location inside a source asset.
- Integrity — every byte can be checked against a digest recorded in the artifact.
An artifact that cannot satisfy one of these is not conformant, whatever else it contains.
2. Encapsulation§
2.1 Container§
An AKP artifact MUST be a prefixed ZIP: a 16-octet fixed header followed immediately by a ZIP archive (ISO/IEC 21320-1, the interoperable subset of ZIP).
offset size field
0 4 magic 0x41 0x4B 0x50 0x0D ("AKP\r")
4 1 major specification major version, unsigned
5 1 minor specification minor version, unsigned
6 2 flags reserved, MUST be zero, MUST be ignored on read
8 8 reserved MUST be zero
16 ... payload ZIP archive
A reader MUST identify an artifact by these 16 octets and MUST NOT identify it by filename or extension.
The prefix is what makes the format identifiable and versioned without parsing, and it is why the container is not a bare ZIP: an AKP must never be mistaken for an ordinary archive. Because ZIP readers locate the central directory from the end of the file, a prefixed ZIP remains readable by conventional ZIP tooling — the same mechanism a self-extracting archive uses.
Compression MUST be store (0) or deflate (8). Encryption, multi-volume archives and ZIP64
entries above 2^63−1 octets MUST NOT be used.
2.2 Layout is not normative§
The archive layout below is informative. Conformance is defined against the information model in §3–§7, not against paths. An alternative serialisation that preserves the model and the conformance rules is conformant.
/manifest.json the package manifest (§3)
/assets/<asset-id> source documents, byte-identical (§4)
/knowledge/<file>.jsonl knowledge objects, one per line (§5)
/integrity.json digests over everything canonical (§7)
/signatures/<key-id> detached signatures (§7.3)
/derived/... embeddings, indexes; never canonical (§8)
A reader MUST locate objects through manifest.json and MUST NOT infer them from paths.
3. The manifest§
Exactly one manifest per artifact, at the container root, UTF-8 JSON, conforming to
akp-manifest.schema.json. The schema is normative; this section
explains it.
{
"akp": "0.2",
"id": "com.acme.turbines.maintenance",
"version": "3.1.0",
"assets": [{ "id": "a1", "path": "assets/a1", "mediaType": "application/pdf",
"digest": "blake3:9f2b…", "octets": 184320, "name": "Manual.pdf" }],
"knowledge": [{ "path": "knowledge/main.jsonl", "count": 412, "digest": "blake3:0ac1…" }],
"integrity": { "path": "integrity.json", "digest": "blake3:71de…" },
"extensions": {}
}
akpMUST be the specification version the artifact was written against.idMUST be a reverse-DNS identifier, matching^[a-z]([a-z0-9-]*[a-z0-9])?(\.[a-z]([a-z0-9-]*[a-z0-9])?)+$.versionMUST be a semantic version (SemVer 2.0.0).- Every asset and knowledge file listed MUST exist; anything present but unlisted MUST be ignored by a reader and MUST be preserved by a writer that rewrites the artifact.
4. Assets and input formats§
An Asset is one source document, stored byte-identical to what the producer was given. A producer MUST NOT normalise, re-encode, repair or re-compress an asset. The asset is the evidence; a modified asset makes every provenance reference into it a claim about a document nobody else has.
4.1 Input formats a producer must accept§
A conformant producer MUST accept these media types as input and MUST be able to emit at least one knowledge object with a resolvable anchor (§6) for each:
| Media type | Anchor space (§6.2) | Notes |
|---|---|---|
application/pdf |
page, rect |
Text-layer extraction. A page with no text layer is a §4.3 diagnostic, not a failure. |
application/vnd.openxmlformats-officedocument.wordprocessingml.document |
part, para |
DOCX. |
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
sheet, cells |
XLSX. |
text/markdown |
line, char |
CommonMark. |
text/plain |
line, char |
Charset from the manifest; UTF-8 if absent. |
A producer MAY accept others. Any additional format MUST declare its anchor space in the
manifest's extensions under a namespaced key, and MUST NOT reuse an anchor kind from the
table above with different semantics.
Formats deliberately not required at 0.2: HTML, PPTX, CSV, email. Each is straightforward to add and none is settled enough to make mandatory.
4.2 Structured and live sources§
Out of scope at 0.2. A producer MUST NOT represent a live source such as a SQL database or a knowledge graph as a static asset without recording, in an extension, what was captured and when.
4.3 Extraction diagnostics§
Extraction failure and unsupported content MUST be recorded, never silently dropped. Each diagnostic MUST carry a severity, an anchor identifying what was affected, and a code.
{ "severity": "warning", "code": "pdf.no-text-layer",
"anchor": "akp:asset/a1#page=12", "message": "Page has no extractable text layer." }
A consumer MUST treat an artifact with diagnostics as valid. Diagnostics describe the completeness of extraction; they do not describe conformance.
5. Knowledge objects§
A Knowledge Object is a passage of text derived from exactly one asset, small enough to be useful to a model, with a reference back to where it came from.
Knowledge objects are stored as JSON Lines — one object per line, UTF-8, LF-terminated. This is the one place the format optimises for scale: a corpus of a million objects must be streamable without holding it in memory, and a line-delimited file is readable by every language without a parser for the whole file.
{"id":"ko:9f2b1c…","asset":"a1","anchor":"akp:asset/a1#page=12&rect=72,540,468,96",
"text":"Torque the retaining bolts to 45 Nm in a diagonal sequence.",
"role":"procedure","metadata":{"com.acme.governance.classification":"internal"}}
5.1 Required fields§
| Field | Rule |
|---|---|
id |
MUST be ko: followed by the lowercase hex BLAKE3-256 of the identity input in §5.2. |
asset |
MUST be the id of an asset in the manifest. |
anchor |
MUST be a resolvable anchor (§6) into that asset. |
text |
MUST be the extracted text, normalised per §5.3. MUST NOT be empty. |
role and metadata are optional. role SHOULD be one of prose, procedure, table,
heading, warning, definition; a value outside that set MUST be preserved and MUST
NOT cause rejection.
5.2 Identity§
A knowledge object's identity is derived from its content, so that reprocessing the same input produces the same identifier and a diff can tell a moved object from a changed one.
id = "ko:" || hex(BLAKE3-256(
asset_digest || 0x1F ||
canonical_anchor || 0x1F ||
normalised_text
))
asset_digest is the asset's digest as it appears in the manifest, including the algorithm
prefix. canonical_anchor is the anchor in the normal form of §6.3. 0x1F is the ASCII unit
separator, which cannot appear in any of the three inputs.
Consequences, stated so they are chosen rather than discovered. Re-running extraction over an
unchanged asset with unchanged chunking yields identical identifiers. Changing the chunking
changes them, because a differently-bounded passage is a different object — a diff will show
removals and additions, which is the truth. Editing the text of an object changes its identifier;
an editorial history that must survive editing belongs in metadata, not in the identifier.
5.3 Text normalisation§
Before hashing and before storage, text MUST be:
- Unicode NFC.
- Line endings converted to LF.
- Leading and trailing whitespace removed.
- Runs of two or more whitespace characters replaced by a single space, except inside an
object whose
roleistableorprocedure, where internal whitespace is significant and MUST be preserved.
No other transformation. In particular, case, punctuation, ligatures and hyphenation MUST NOT be altered: they are evidence, and a reader comparing an object against its source must find the same words.
6. The reference§
The anchor is the reference from a knowledge object back to its source. It is the single most important construct in this format: without it, an AKP is a pile of text with a provenance claim nobody can check.
6.1 Grammar§
An anchor is a URI in the akp scheme, with an ABNF (RFC 5234) of:
anchor = "akp:asset/" asset-id "#" selector
asset-id = 1*64( ALPHA / DIGIT / "-" / "_" )
selector = pair *( "&" pair )
pair = kind "=" value
kind = 1*32( LOWER )
value = 1*256( unreserved / "," / ":" / pct-encoded )
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
An anchor MUST resolve within the artifact that contains it. An anchor MUST NOT address anything outside its own asset; references between artifacts are out of scope at 0.2.
6.2 Anchor kinds§
Each kind is defined for specific media types. A producer MUST NOT emit a kind against a media type it is not defined for, and a consumer MUST reject an anchor that does so.
| Kind | Value | Defined for | Meaning |
|---|---|---|---|
page |
1-based integer | Page number as the document paginates it. | |
rect |
x,y,w,h in points, origin bottom-left |
PDF (with page) |
Region on the page. |
part |
package-relative part name | DOCX | The OPC part the content came from. |
para |
0-based integer | DOCX (with part) |
Paragraph index within the part. |
sheet |
sheet name, percent-encoded | XLSX | Worksheet. |
cells |
A1 or A1:D20 |
XLSX (with sheet) |
Cell or range, in A1 notation. |
line |
n or n:m, 1-based, inclusive |
Markdown, plain text | Line or line range. |
char |
n:m, 0-based, half-open, in Unicode scalar values |
Markdown, plain text | Character range. |
Counting in Unicode scalar values, not octets is deliberate: an octet offset into a UTF-8 document means a different thing to every language's string type, and an anchor that resolves differently in Python and Rust is not a reference.
6.3 Normal form§
For hashing (§5.2) and comparison, an anchor MUST be canonicalised:
- Pairs sorted by
kind, ascending, byte-wise. - Percent-encoding uppercase (
%2F, not%2f), and only where required by §6.1. - No empty pairs, no trailing
&.
Two anchors are the same anchor if and only if their normal forms are octet-identical.
6.4 What a consumer must be able to do§
Given an artifact and a knowledge object, a consumer MUST be able to determine the asset, the region within it, and to extract the asset's bytes for inspection — using nothing but the artifact. It is not required to render the region, which needs a format-specific renderer and is a tool concern.
7. Integrity and identity§
7.1 Digests§
Every digest in an artifact MUST be blake3: followed by lowercase hex of a BLAKE3-256 hash.
One algorithm, named in every occurrence so a future version can add another without ambiguity.
7.2 Canonical content and package identity§
Canonical content is: the manifest, every asset, every knowledge file, and the integrity record. Derived content is everything else, and by construction that is embeddings, indexes and retrieval state (§8).
Package identity is a Merkle root over the canonical set:
leaf(entry) = BLAKE3-256( entry_path || 0x1F || entry_digest )
root = BLAKE3-256( leaf₁ || leaf₂ || … ) -- leaves sorted by entry_path, byte-wise
integrity.json carries the leaves; the root is the package identity. Sorting by path is what
makes the root independent of archive order, and therefore of the writer. Deleting every derived
artifact MUST NOT change the root.
7.3 Signatures§
A signature is over the canonical root and nothing else. Signing the manifest alone would leave the assets unprotected; signing the whole container would break on any repack that changed compression without changing content.
{ "keyId": "…", "algorithm": "ed25519", "root": "blake3:…", "signature": "base64url…" }
Signatures live in /signatures/ and are not canonical — an artifact signed by two parties
has the same identity as one signed by neither. Verification requires the artifact and a public
key; no service, and no root of trust distributed with any implementation.
8. Derived artifacts§
Embeddings, indexes and retrieval state are a cache. They MUST live under a path the manifest declares as derived, MUST NOT appear in the integrity leaves, and MUST be reconstructible from canonical content plus a declared profile. Deleting all of them MUST leave a valid artifact with an unchanged identity.
The embedding profile itself — the model, dimensionality and parameters — is canonical, because it is a claim about how the derived data was produced. The vectors are not.
9. Extensions and forward compatibility§
Extension keys MUST be reverse-DNS namespaced (com.acme.governance.classification). Keys
without a dot are reserved for this specification. The x- convention MUST NOT be used
(RFC 6648).
A consumer that does not understand an extension MUST preserve it byte-for-byte through any operation that rewrites the artifact. This is the rule that lets the format grow without a flag day, and it is testable: read, write, compare.
An extension MUST NOT change the meaning of anything in §3–§7. A producer needing that
MUST list the key in the manifest's criticalExtensions, and a consumer that does not
understand a listed critical extension MUST refuse the artifact rather than misread it.
10. Reserved for a later version§
Named so that their absence is deliberate rather than an omission a reader has to discover, and reserved rather than merely absent: a later version may define each of these, and until one does, an implementation MUST NOT read meaning into their absence or occupy the vocabulary they would use. Where a producer needs one of them today, the extension mechanism in §9 is the supported route, and an extension that is later replaced by normative vocabulary remains round-trippable under §9's rules.
Each names the open question that governs it, so a reader can follow the argument rather than take this list on trust.
| Reserved | Open question |
|---|---|
| References between artifacts. An anchor addresses its own asset only (§6.1). | Q5, Q22 |
| Evaluation suites. What a package claims to answer, and what counts as answering it. | Q8 |
| Semantic resources. Terminology, taxonomy and relationship vocabularies. | Q30 |
| Governance metadata. Licensing and permission vocabulary beyond free-form extensions. | Q9 |
| Composition. Whether a package may be assembled from, or reference, another. | Q16, Q29–Q34 |
| Delta artifacts. How a partial update identifies its base and resolves conflicts. | Q12 |
| Live sources. A database or knowledge graph, without pretending it is a static document (§4.2). | Q13 |
| Conformance profiles. §11 defines one level and no subsets. | Q10 |
This is the scope decision that makes a candidate possible. Each reserved item is a feature with
no implementation to check a design against, and specifying one from first principles is how a
specification acquires text that no producer emits and no reader honours. The register at
open-questions.md tracks them.
11. Conformance§
A conformant artifact satisfies §2 through §9.
A conformant reader identifies by byte signature, resolves objects through the manifest, verifies the canonical root, resolves anchors, preserves unknown extensions, and refuses an artifact with an unknown critical extension.
A conformant producer emits conformant artifacts, accepts the input formats in §4.1, records diagnostics rather than dropping content, and normalises text per §5.3.
There are no conformance profiles at 1.0-rc, and no conformance suite exists yet — so no implementation, including the reference one, makes a conformance claim. Publishing a suite is a precondition of 1.0 (§13), because a conformance section nothing can test against is a claim about a claim.
12. Licence and patents§
This specification is published under the Open Web Foundation Agreement 1.0 (OWFa 1.0).
Chosen over a Creative Commons licence for one reason, and it is the reason that matters for a file format: CC licences grant copyright permission and say nothing about patents. A format whose text anybody may copy but whose implementation may be enjoined is not an open format, and the neutrality this specification rests on would be a courtesy rather than a commitment. OWFa is purpose-built for specifications and carries both the copyright permission and a patent commitment from contributors in one instrument.
What that means in practice:
- Anyone MAY implement this specification, commercially or otherwise, without permission, licence fee or notification.
- Anyone MAY copy and redistribute this document with attribution.
- Contributors commit not to assert Necessary Claims against a conformant implementation, on the terms OWFa 1.0 sets out.
- No trade mark right is granted. "Stemmar" names the organisation and its tools; "AKP" names the format. Implementing the specification does not license either name (ADR-0010, ADR-0011).
The governing text is OWFa 1.0 itself; this section describes it and does not amend it.
13. What 1.0 requires§
This version is a candidate. It becomes 1.0 when all of the following are true, and the list is published so that the promotion is a checklist rather than a judgement call:
- A conformance suite exists, and the reference implementation passes it. §11 defines what conformance means; nothing yet tests a claim to it, including our own.
- The media type is registered, and the file extension question is settled (Q19, Q20). A format identified by byte signature (§2.1) works without either, but a stable version that left its own registration undecided would be stable in name only.
- At least one independent implementation has been written against this text. A specification validated only by the implementation it was extracted from has not been tested as a specification.
- The errata process is published — how a correction is issued against a stable version without editing it (Q37).
Until then the reserved items in §10 stay reserved, and this document may still change in response to what any of the four turn up. That is the whole point of a candidate: it is the version you are invited to break.
Machine-readable schemas§
The prose above is normative for meaning. These are normative for structure, and they are what an implementation should validate against.
akp-manifest.schema.json— the package manifest (§3).akp-knowledge-object.schema.json— one line of a knowledge file (§5).
Generated from docs/spec/versions/1.0-rc/information-model.md.
Source digest (SHA-256): 061f7a9ceb8544a14b04fd0ef231d7149b25b1722fcfe1db31bbf7441214a178.