Platform
The structural spine: navigate your wiki by shape, not keywords
Wikantik's structural spine is a small set of first-class APIs, a persistent canonical_id per page, and cluster-hub membership — the machinery that lets agents ask "what does this wiki contain?" and get a structured answer instead of a keyword search guess.
The problem: structural blindness
A wiki with 1,000+ pages and no structural API forces every agent to rediscover the wiki's shape via full-text search. An agent asked "what does this wiki know about retrieval?" must BM25-search for "retrieval", hope the top hit is a hub page, then parse prose to find sub-articles. An agent asked "show me every hub page" has no endpoint to call — it must enumerate all pages and re-parse their frontmatter client-side.
This is expensive in tokens and brittle in practice. The structural spine solves it by exposing the taxonomy as queryable data: clusters, tags, types, canonical IDs, and sitemap — all available as structured API responses, not prose that needs to be parsed.
The full design is documented in Structural Spine Design in the live wiki.
First-class structural APIs
The /api/structure/* REST endpoints expose the structural index:
GET /api/structure/clusters— all clusters with hub page, article count, and last-updated timestampGET /api/structure/clusters/{name}— full cluster detail: hub summary, ordered article list with summaries, tag distributionGET /api/structure/tags?min_pages=N— tag dictionary with counts and representative pagesGET /api/structure/pages?type=hub&cluster=X&tag=Y&updated_since=ISO— filtered, paginated page listingGET /api/structure/sitemap— compact machine-readable sitemap (id, slug, title, type, cluster, tags, summary per viewable page) suitable as an agent prelude payload
The same data is available via the /knowledge-mcp MCP server's structural spine tools (list_clusters, list_tags, list_pages_by_filter, get_page_by_id, plus get_page_neighbors for a page's one-hop wikilink neighborhood), so MCP-native and REST-native agents share one surface.
Canonical IDs: rename-stable page identity
Every page carries a canonical_id: a 26-character ULID assigned at first save by StructuralSpinePageFilter and stored in the page's YAML frontmatter and in the page_canonical_ids database table. The canonical ID is immutable — renaming the page does not change it.
This means external systems that reference pages by canonical ID instead of slug are rename-proof. The endpoint GET /api/pages/by-id/{canonical_id} always resolves to the current page, even through multiple renames. Slug history is tracked in page_slug_history for auditing.
Canonical ID assignment is enforced at save time: if a page lacks a canonical_id, StructuralSpinePageFilter automatically assigns one before the save completes. You cannot accidentally save a page without a stable identity.
Cluster hubs: the entry points agents use
Every page belongs to a cluster declared via cluster: in its frontmatter. Within each cluster, one page is the hub — the entry point that links to all cluster articles. The structural index tracks hub designation per cluster, so list_clusters returns not just cluster names but the hub page's canonical ID, slug, and title.
A cluster's existence is a declaration, not a folder: it exists once exactly one page carries type: hub with a matching cluster: path, and that hub is the single source of truth for the cluster — not just a landing page. Sub-clusters nest one level deep as parent/child paths, and an individual page can belong to more than one cluster at once, with its first listing as the primary that drives breadcrumbs and the article section.
For agents navigating a large wiki, the pattern is: call list_clusters to get a map of the wiki's topic areas; pick the relevant cluster; call list_pages_by_filter with that cluster to get its article list; then read specific articles via read_pages or get_page_by_id. This is three to four tool calls to fully orient an agent in any topic area, versus unbounded keyword search iterations.
Generated Main.md: structure that stays accurate
Wikantik's Main.md — the wiki's homepage — is generated rather than hand-maintained. It is rendered by the GenerateMainPageCli command-line generator in wikantik-extract-cli, so it follows the actual cluster taxonomy. A CI regression test (MainPageRegressionTest) fails the build if the checked-in Main.md diverges from what the generator would produce.
Curators can add editorial pins via docs/wikantik-pages/Main.pins.yaml — featured pages and highlighted sections — without hand-editing Main.md directly. The generator reads both the pages' structural metadata and the pins, merging them into the final page.
Fail-closed behaviour
The structural index follows the same fail-closed principle as hybrid retrieval. If the structural index is unavailable, /api/structure/* returns HTTP 503 rather than silently returning empty data, and get_page_neighbors returns a retry-shortly error while the link index is still scanning at startup. An agent that gets a 503 from a structural endpoint knows to retry — it does not get silently wrong data.
Frequently asked questions
What problem does the structural spine solve?
Without a structural spine, an agent asked "what does this wiki contain?" must run a full-text search and hope for a useful hub page. The structural spine exposes the wiki's taxonomy — clusters, tags, types, canonical IDs — as queryable data. An agent can enumerate clusters, filter pages by type or tag, and resolve canonical IDs without guessing at keywords.
What is a canonical ID and why is it immutable?
A canonical_id is a 26-character ULID assigned to each page at first save by StructuralSpinePageFilter. It is immutable — renaming the page does not change it. External systems that reference a page by canonical ID instead of slug are rename-proof; GET /api/pages/by-id/{canonical_id} always resolves to the current page.
How is Main.md kept in sync with the actual wiki structure?
Main.md is generated rather than hand-maintained. It is rendered by the GenerateMainPageCli command-line generator in wikantik-extract-cli, so it follows the actual cluster taxonomy. A CI regression test fails the build if the checked-in Main.md diverges. Curators add editorial pins via Main.pins.yaml without hand-editing Main.md directly.