Appearance
Primary Metadata System
FreshThe primary metadata system provides immediate document identity without requiring a full parse of all quads. It extracts the four most important facts about a document during parsing: subject, type, label, and comment.
The Dual-Layer Architecture
MD-LD's parse result exposes document identity at two levels:
| Layer | Field | Purpose | Use Cases |
|---|---|---|---|
| Canonical Identity | primarySubject | Append routing, storage, synchronization | append(), file placement, authority validation |
| Semantic Surface | primary | UI, indexing, navigation, agent orientation | Dashboards, search, previews, timelines |
These two layers serve different needs in different parts of a system.
primarySubject
result.primarySubject is the string IRI of the first non-fragment subject declaration in the document.
markdown
[my] <tag:you@example.com,2026:>
# Alice {=my:alice .prov:Person label}In this document, result.primarySubject is "tag:you@example.com,2026:alice".
Fragment subjects are excluded:
markdown
# Document {=my:doc .my:Doc label}
## Section {=#section}primarySubject is my:doc, not my:doc#section. The fragment is a structural subdivision, not the canonical identity.
Why primarySubject Matters
The primarySubject is the canonical address for the document's main entity. It tells you:
- Which IRI to use when storing this document in a content-addressed system
- Which IRI to check for conflicts when appending to a knowledge base
- Which authority (email address or domain) produced this document
Applications that route documents by their primary entity (e.g., "store all documents about my:alice in the same shard") use primarySubject directly.
primary Object
result.primary is an object with four fields extracted from the first occurrence of each type during parsing:
javascript
primary: {
subject: string | null, // First non-fragment subject declaration
type: string | null, // First rdf:type declaration
label: string | null, // First rdfs:label literal
comment: string | null // First rdfs:comment literal
}Extraction Rules
Each field is set by the first occurrence of the relevant construct:
subject— set by the first{=IRI}that is not a fragmenttype— set by the first.Classannotation in the documentlabel— set by the first{label}or{rdfs:label}literalcomment— set by the first{comment}or{rdfs:comment}literal
Once set, none of these fields change, regardless of how many subjects, types, or labels appear later in the document.
Example
markdown
[my] <tag:you@example.com,2026:>
# Alice {=my:alice .prov:Person label}
> The best engineer in the team. {comment}
[alice@example.com] {my:email}Result:
javascript
{
primarySubject: 'tag:you@example.com,2026:alice',
primary: {
subject: 'tag:you@example.com,2026:alice',
type: 'http://www.w3.org/ns/prov#Person',
label: 'Alice',
comment: 'The best engineer in the team.'
}
}Use Cases
Quick UI Rendering
Without iterating all quads, you can immediately display a document's title, type badge, and description:
javascript
const { primary } = parse({ text: document });
// Render a document card
const card = {
title: primary.label || primary.subject || 'Unnamed',
type: primary.type || 'Unknown type',
description: primary.comment || ''
};Search Indexing
Index documents by their primary metadata for full-text search:
javascript
const results = documents.map(text => {
const { primary } = parse({ text });
return {
iri: primary.subject,
title: primary.label,
type: primary.type,
summary: primary.comment
};
});Agent Orientation
For LLM agents processing a knowledge base, primary provides immediate orientation without requiring quad traversal:
javascript
const { primary } = parse({ text: knowledgeDocument });
const systemMessage = `
This document is about: ${primary.label}
Type: ${primary.type}
Description: ${primary.comment}
IRI: ${primary.subject}
`;Stream Routing
When documents arrive in a stream, route them by type using primary.type:
javascript
documents.forEach(text => {
const { primary } = parse({ text });
switch (primary.type) {
case 'http://www.w3.org/ns/prov#Activity':
activityQueue.push(text);
break;
case 'http://www.w3.org/ns/prov#Person':
personStore.upsert(primary.subject, text);
break;
default:
generalQueue.push(text);
}
});Merge Behavior
When merging multiple documents, primary becomes an array (one object per document):
javascript
const merged = merge([doc1, doc2, doc3]);
// Array of primary objects in merge order
console.log(merged.primary);
// [ { subject: ..., type: ..., label: ..., comment: ... }, ... ]
// Array of canonical IRIs in merge order
console.log(merged.primarySubjects);
// [ 'tag:...alice', 'tag:...bob', ... ]Relationship to the Full Quad Graph
primary is a shortcut, not a substitute. It extracts the first occurrence of each field for convenience. For complete document identity — including all types, all labels, all comments — iterate result.quads directly.
primary answers the question: "What is this document fundamentally about?" The full quad graph answers: "What does this document say in detail?"