Skip to content

ADR 0026 — Alistigo Document Format: JSON-LD + schema.org Foundation and Package Standard

ADR 0026 — Alistigo Document Format: JSON-LD + schema.org Foundation and Package Standard

Status: Accepted Date: 2026-08-29

Context

An Alistigo document is the data layer of an artifact — the equivalent of a .doc or .xlsx file. Every artifact reads and edits exactly one document. The base document shape is defined in @alistigo/document and each artifact type defines a specialization (e.g. the list document in @alistigo/list).

Until now, no formal standard existed for:

  • How documents are structured and which vocabulary they use
  • How entities reference each other within a document
  • How document packages are named and what they must contain
  • Where event-replay logic (the CQRS projector) lives
  • How AI-seeded documents via markdown fit into the package contract

This ADR establishes those standards.

IDRequirementPriority
R1Documents must be self-describing — no external schema lookup required to interpret themP1
R2Documents must use a stable, widely-recognised vocabulary to maximise interoperability and AI readabilityP1
R3Cross-entity references must be unambiguous and consistentP1
R4Package names must communicate their role without reading their contentsP2
R5Every document package ships with everything needed to validate, type, and replay its documentsP2
R6Packages that support AI input must provide a canonical markdown parser and examplesP2

Decision

1. JSON-LD as the document wire format

All Alistigo documents are valid JSON-LD documents. They carry a @context object, a @type, and a @id. The JSON-LD keywords (@context, @type, @id, @vocab) are the primary structural mechanism — not custom envelope fields.

2. schema.org as the default vocabulary

The @context always sets:

{
"@vocab": "https://schema.org/",
"alistigo": "https://json-ld.alistigo.com/vocab/"
}

Properties and entity types default to the schema.org namespace. Alistigo-specific terms that have no schema.org equivalent use the alistigo: prefix. When a new property or entity is needed, check schema.org first — only introduce an alistigo: term when nothing equivalent exists.

Entities carry their identifier in @id. References from one entity to another use a JSON-LD node reference object { "@id": "..." } — never a flat string ID property named after the target entity.

// ❌ old pattern — do not use
{ "listId": "lst_..." }
// ✅ new pattern — JSON-LD reference
{ "list": { "@id": "lst_..." } }

alistigo:listId properties in existing schemas are deprecated and will be replaced in a follow-up migration.

4. Package naming convention

All document packages follow the naming scheme @alistigo/<type>-document.

Current packages to rename (tracked as follow-up work):

Current nameNew name
@alistigo/document@alistigo/core-document
@alistigo/list@alistigo/list-document

5. Document package contract

Every @alistigo/*-document package must provide:

DeliverableDetails
JSON Schemasrc/schemas/<type>.json; use schema-org-json-schemas to reference schema.org definitions rather than rewriting them
TypeScript typesExtend schema-dts; exported from the package index
Examplesexamples/simple.json at minimum; validated by CI
READMEContext, usage, and the minimal example inline
Package type marker"alistigo": { "type": "document" } in package.json
Test targetproject.json test target runs every example through the JSON Schema validator
Event projectorSee decision 6
Markdown parser (if applicable)See decision 7

Biome formats and lints JSON files in this repo — no separate formatter needed.

6. Event projectors and application service live in the document package

All Alistigo documents are event-sourced: the alistigo:eventLog array is the source of truth, and replaying it deterministically recreates the current document state. The projector function (the pure reducer that does this replay) belongs in the document package, not in a separate editor package.

The full @alistigo/list-document-editor package is absorbed into @alistigo/list-document. This includes:

  • projectList / ListProjector — the pure event-replay projector
  • ListApplicationService — orchestrates domain commands through the List aggregate and persists via AlistigoListStore
  • AlistigoListStore — the repository interface (extends ListRepository with loadDocument / saveDocument)
  • Result<T, E> / ok / err — the lightweight result type used by the service

@alistigo/list-document-editor is deleted. All consumers import the above symbols from @alistigo/list-document instead.

All future document packages ship their projector (and application service, if applicable) from day one.

7. Markdown input: canonical parser in the document package

Some documents can be seeded from a simplified markdown format written by AI (established in ADR 0021). For these document types, the document package must export:

  • parseMarkdown(source: string): Document — converts markdown to a valid document
  • validateMarkdown(source: string): ValidationResult — validates the markdown grammar without producing a full document

The canonical format for the list document (from ADR 0021):

List title:
- First element
- Second element
Key: value metadata attached to the preceding element
1. Ordered element

Currently, parseMarkdownToDocument and validateAsListDocument live in @alistigo/artifact-list. They will move into @alistigo/list-document as part of the package-contract migration.

examples/ must include at least one .md fixture demonstrating the supported grammar.

The cli/document-validator exposes a validate-markdown <file> --schema <type> command that uses the parser exported by the target document package, in addition to the existing JSON document validation path.

Future (out of scope)

JSON schemas, examples, and the JSON-LD context will be published at https://json-ld.alistigo.com:

  • https://json-ld.alistigo.com/json-schemas/list.schema.json
  • https://json-ld.alistigo.com/examples/list/simple.json
  • https://json-ld.alistigo.com/vocab/

A separate ADR will be written when publishing is ready.

Rationale

JSON-LD vs plain JSON

CriterionPlain JSONJSON-LD (chosen)
Self-describingNo — requires out-of-band schemaYes — @context embeds vocabulary
AI readabilityLow — property names are opaqueHigh — schema.org terms are in AI training data
Graph toolingNoneFull JSON-LD / RDF toolchain
Runtime costNoneNone — @context is metadata only

schema.org vs custom vocabulary

schema.org covers the vast majority of properties needed for list documents (ItemList, ListItem, name, position, startTime, agent, …). Using it avoids reinventing semantics, makes documents interpretable by external tools without documentation, and aligns with AI training data. Custom alistigo: terms are additive, not competing.

@id + node reference vs flat ID string

CriterionentityId: "..."entity: { "@id": "..." } (chosen)
JSON-LD validityNo — requires custom mappingYes — native node reference
Graph toolsRequires mappingWorks out-of-the-box
Semantic clarityImplicitExplicit — the link target is typed

Projector in document package vs separate package

The projector is a pure function of the document schema: it knows event types, their shapes, and how they mutate document state. Keeping it in a separate package creates a split between “what the document looks like” and “how to reconstruct it from events” — a split with no benefit and significant friction when schemas evolve. Co-locating them means a single import provides everything needed to work with a document.

Consequences

Positive:

  • Documents are self-describing, interoperable, and AI-friendly out of the box
  • Uniform package contract — every *-document package delivers the same set of artifacts
  • Projectors travel with schemas — no version skew between format and replay logic
  • Markdown examples and parsers are co-located with the JSON-LD schema in a single package

Negative / tradeoffs accepted:

  • Renaming @alistigo/core-document → @alistigo/core-document and @alistigo/list → @alistigo/list-document is a breaking change affecting ~8 packages; migration is tracked as follow-up work
  • Absorbing @alistigo/list-document-editor entirely into @alistigo/list-document is a breaking change; consumers (artifact-list, list-components-react) update their import source from @alistigo/list-document-editor to @alistigo/list-document — symbol names are unchanged
  • Moving parseMarkdownToDocument and validateAsListDocument out of @alistigo/artifact-list is a breaking change for that package; migration is tracked alongside the rename
  • The alistigo:listId flat-string reference in the current list schema is deprecated but not yet removed — it will persist until the schema migration is applied

Alternatives considered

  • Plain JSON with a custom schema — rejected: no semantic layer; reinvents vocabulary that schema.org already provides at no cost
  • entityNameId flat string pattern — rejected: loses explicit link semantics; incompatible with JSON-LD node references; makes graph tooling require custom mapping
  • Keep projector in a separate *-document-editor package — rejected: creates coupling between schema and replay logic that breaks silently when the schema evolves
  • Keep markdown parser in the artifact package — rejected: the markdown format is part of the document contract, not the artifact implementation

References

  • ADR 0016 — Composable Artifact Plugin System
  • ADR 0021 — AI Input Action: Markdown as Document Source Format (markdown grammar, boot flow; current location of parseMarkdownToDocument / validateAsListDocument)
  • ADR 0023 — Entity IDs: TypeID as the Preferred Format (format of @id values)
  • ADR 0024 — Shared-List View: Actor Registry in Document
  • schema.org, JSON-LD spec
  • npm: schema-dts, schema-org-json-schemas