Ontology Management on Wikantik

Adapted from docs/admin/OntologyManagement.md in the Wikantik repository; current as of release 2.4.56.

This guide is for curators, agent operators and developers who manage the ontology layer. Wikantik is a wiki with an ontology layered over it: the prose pages are also a machine-readable, queryable knowledge model. This guide explains why that exists and how to manage it day to day — as a human curator, as an AI agent, and as a developer evolving the vocabulary itself.

Terminology note: throughout, "ontology" means the wikantik: RDF/OWL model — the classes, properties, and instances projected from the wiki. It is distinct from the Page Graph (page-to-page wikilink edges). See Page Graph vs Knowledge Graph — read it first if those two terms blur together.


Why an ontology over a wiki?

A plain wiki stores prose. Wikantik additionally maintains a formal model of what the pages are about, because that unlocks things prose alone cannot:


Use cases

Two concrete things the ontology makes possible that prose alone does not:

(Two more payoffs fall out of the same model: the wiki is interoperable linked data — schema.org/SKOS/DC/PROV mappings + Turtle/N-Triples dumps consumable by any RDF tool — and its SEO can't drift, because a page's public schema.org @type is re-sourced from the ontology.)


The model: three layers

It helps to see the ontology as three layers, because each is managed differently and by different people.

LayerWhat it isWhere it livesWho manages it
1. T-Box (vocabulary)The class & property definitions — 9 entity classes, 5 content classes, 21 relation predicates, their domain/range, the schema.org/SKOS/DC/PROV mappings, and the SHACL shapeswikantik-ontology/src/main/resources/ontology/wikantik.ttl + shapes.ttl; EntityTypeVocabulary, RelationshipTypeVocabulary, NodeTypeMapping (code)Developers (edit Turtle/Java)
2. Page concepts (A-Box)Each page as a typed concept: its wk: content class, IRI, title/summary, and its tag/cluster SKOS concepts + provenancePage frontmatter; projected by PageProjector + ConceptProjectorAuthors & agents (the structured frontmatter editor)
3. Knowledge Graph (A-Box)The entities mentioned across the wiki (people, technologies, concepts, …) and the typed relations among themkg_nodes / kg_edges; projected by EntityProjector + EdgeProjectorExtractors + curators (the Knowledge tab, admin panel, MCP tools)

The vocabulary (Layer 1) is the closed set everything else conforms to:

You author Layers 2 and 3; you don't author Layer 1 from the wiki — you create instances that conform to it. Changing the vocabulary is a code change (see Evolving the vocabulary below).


How to manage page concepts (Layer 2)

This is what most curation looks like, and it happens in the structured frontmatter editor — the form beside the Markdown body when you edit a page.

Full field reference: see docs/user/Frontmatter.md for every supported frontmatter key, the editor's live-validation / Save-gating model, and the runbook block. This section covers only the ontology-relevant fields.

The editor renders every field from a server-authoritative schema (GET /api/frontmatter-schema) and validates against the same rules the server enforces on save:

AI agents writing via the admin MCP update_page / write_pages tools hit the same validator and receive the same suggestion-bearing messages, so they can self-correct. See docs/superpowers/specs/2026-06-08-structured-page-curation-design.md.


How to manage the Knowledge Graph (Layer 3)

Layer-3 entities and relations come from two sources: automatic extraction and deliberate curation.

Where entities come from

The entity extractors (chunk-level and page-level) read page content and emit candidate entities (one of the 9 classes) and relations into kg_nodes / kg_edges, stamped AI_INFERRED. This is the bulk-population path.

Curating from the page editor (the Knowledge tab)

When you edit a page, the Knowledge tab (beside Frontmatter) shows the entities mentioned on that page and the relations among them, and lets you:

Writes go through /api/page-knowledge/*, gated by your edit permission on the page, and route through the same curation facade as everything else — so the SHACL gate, provenance stamping, and audit log all apply. A relation that violates a shape is refused inline (HTTP 422) with the reason.

Curation only surfaces on KG-included pages. Inclusion is cluster-primary and default-exclude; use kg_include: true in frontmatter to opt a page in. An entity curated on an excluded page won't appear in the slice. See KG Inclusion Policy.

Curating at scale (admin + agents)

The SHACL write-time gate

Relations are validated against the SHACL shapes before they're written. The gate is deliberately narrow today — implements requires a technology subject and a concept object; located_in requires a place object — and a non-conformant edge is refused (REST/MCP) or skipped-and-logged (the machine materialization path), citing the violated shape. Predicates without a shape are unconstrained. This is how the vocabulary's rules are enforced as the A-Box grows under both human and AI hands.


Consuming the ontology (the read surface)

The materialized model is queryable and dereferenceable, read-only and public (behind an ACL split so restricted pages/entities never materialize publicly):


How it stays in sync (the materialization pipeline)

The RDF model is projected from PostgreSQL into a Jena TDB2 store with RDFS subClassOf inference:

Config: wikantik.ontology.enabled (default true), wikantik.ontology.tdb2.dir (blank by default, which means <wikantik.workDir>/ontology-tdb2), wikantik.ontology.rebuild.interval.hours (default 24, 0 = disabled), wikantik.ontology.compaction.interval.hours (default 168, 0 = disabled; the TDB2 store only grows between compactions, so keep this on), wikantik.ontology.incremental.enabled (default true — event-incremental entity sync; false restores nightly-only behavior), and wikantik.ontology.incremental.coalesce.ms (default 500). Full design: docs/superpowers/specs/2026-06-08-wiki-ontology-design.md.


Evolving the vocabulary (Layer 1)

When you genuinely need a new class, predicate, or constraint — a developer task, not a wiki edit:

  1. Add/adjust the T-Box in wikantik.ttl (the class/property, its rdfs:domain/rdfs:range, and any rdfs:subClassOf mapping to schema.org/SKOS/DC/PROV). A class entry reads like:

    wk:Technology  rdfs:subClassOf  wk:Entity ;
                   rdfs:subClassOf  schema:SoftwareApplication .
    
    wk:implements  a            owl:ObjectProperty ;
                   rdfs:domain  wk:Technology ;
                   rdfs:range   wk:Concept .
    
  2. Update the code vocabularies so the extractors, validators, and UI agree: EntityTypeVocabulary (the 9 entity classes), RelationshipTypeVocabulary (the 21 predicates), and NodeTypeMapping (free-text type → wk: class + schema.org type). Drift guards (e.g. EntityTypeVocabularyDriftTest) tie these together — keep them green.

  3. Tighten constraints by adding a shapes.ttl SHACL shape, which the write-time gate will then enforce.

  4. Surface the new value in the UIs that hardcode the vocab (the structured editor's enums, the Knowledge panel's type/predicate pickers).

The page-concept enums (type, status) are curated-open: new values are tolerated (with a stern, suggestion-bearing warning) until the corpus is normalized, then escalatable to hard errors via wikantik.frontmatter.enum.nonCanonical.severity. This is the lever for evolving the page vocabulary gradually under shared human/AI control.


Measuring drift (the burn-down dashboard)

Advisory warnings only matter if someone can see them in aggregate. The drift dashboard (/admin/drift) makes vocabulary drift measurable:

The screen itself is described in Drift Dashboard. Endpoints: GET /admin/drift/summary, GET /admin/drift/trend?days=N, GET /admin/drift/pages?family=F&code=C, GET /admin/drift/status (live sweep progress for the dashboard's progress bar), POST /admin/drift/sweep.


Curation in practice: burning down a SHACL violation

The drift dashboard surfaces non-conformant edges under family shacl. Here is the end-to-end loop to clear them — the same one used to take the corpus to zero.

  1. See them. /admin/drift shows the shacl node-scoped count. Expand it (or GET /admin/drift/pages?family=shacl&code=node-scoped) for the per-edge list; each row names the focus node and the violated shape, e.g. "wk:implements domain must be a wk:Technology."

  2. Triage each one. A violation has two honest fixes — the call is per-entity:

    • Retype the node — if the subject genuinely is the required class (a real technology mis-typed as concept), change its node_type to match; the edge then conforms.
    • Fix or remove the edge — if the edge is wrong or backwards (a concept that doesn't "implement" anything, or an implements pointing the wrong way), delete it or re-predicate it.

    The question to ask is: is the subject really a technology, or is the implements edge bogus?

  3. Apply it through a curation surface — the admin panel (/admin/knowledge-graph/*), the admin-MCP curate_nodes / curate_edges tools, or, for a one-shot legacy cleanup of many rows, a direct SQL fixup (data correction, not a versioned migration). Each surface keeps the SHACL gate, provenance, and audit log in force for future writes.

  4. Re-project. KG entity/edge edits fire a KgChangeEvent, which OntologyEntitySync picks up and re-projects (coalesced, async — typically settling within wikantik.ontology.incremental.coalesce.ms, default 500ms), so most curation fixes reach the materialized model without a manual step. If you want to force it (or the incremental sync is disabled via wikantik.ontology.incremental.enabled=false), rebuild explicitly: POST /admin/ontology/rebuild (or wait for the nightly reconcile). A drift sweep fires automatically once a rebuild completes.

  5. Re-sweep & confirm. If you didn't trigger a rebuild, run POST /admin/drift/sweep and confirm the shacl count dropped to zero.

Preventing recurrence. The common cause was the entity extractor labelling a real technology with an off-vocabulary type (database, framework, library, tool, service, …) that fell back to concept — landing it under the implements shape. The chunk and page extractors now resolve those synonyms to the right class via EntityTypeVocabulary.TYPE_ALIASES, so freshly-extracted technologies are typed correctly at the source.


Quick reference

Surfaces

PurposeEndpoint / tool
Field schema for the editorGET /api/frontmatter-schema
Dry-run frontmatter validationPOST /api/frontmatter/validate
Page-scoped KG read + curation/api/page-knowledge/{name} (view read, edit-gated writes)
KG admin (nodes/edges/proposals)/admin/knowledge-graph/*
Ontology rebuild + status/admin/ontology/*
Drift burn-down (sweep + counts)/admin/drift/*
Public SPARQL/sparql (GET or POST)
Resource dereferencingGET /id/{type}/{id} (JSON-LD / Turtle)
RDF dumpsGET /export/ontology.ttl, /export/graph.nt
Agent toolsknowledge-mcp (get_ontology, sparql_query, retrieval); admin MCP (curate_nodes, curate_edges)

Where the code lives

Related docs


Cluster Hub: Wikantik Platform Development Hub: Architecture, MCP Protocols, and Agent Briefings (wikantik-development)