A narrative of recent development on Wikantik — the six weeks from mid-April to
the end of May 2026. In that span the project crossed from 1.1.x to its 2.0
line (six tagged releases, 2.0.0 through 2.0.5), went live on real
infrastructure, and shifted its center of gravity from "a wiki that an AI can
read" to "a wiki built, operated, and consumed with AI agents as first-class
citizens."
The dominant story of these weeks is making the corpus genuinely useful to retrieval-augmented agents — not as an afterthought, but as a designed surface.
Hybrid retrieval (mid-to-late April). The window opens with hybrid search
landing in earnest: BM25 lexical scoring fused with dense vector similarity via
weighted reciprocal-rank fusion. A QueryEmbedder wraps the embedding client
with a cache, a timeout, and a hand-rolled circuit breaker so a slow or failing
embedding backend degrades to lexical search instead of taking the page down. An
in-memory chunk-vector index served the first dense top-k, and a retrieval
experiment harness with reproducible eval reports let us pick fusion weights
from evidence rather than intuition. This shipped as v1.1.6.
Agent-grade content and the structural spine (late April). From there the
work turned structural. A ContextRetrievalService was extracted as the single
seam through which search, the REST API, and the tool servers all retrieve —
collapsing several near-duplicate read paths into one. On top of it came the
structural spine: rename-stable canonical IDs, cluster/hub membership, and a
machine-queryable /api/structure/* index with matching MCP tools, all enforced
at save time. Pages gained verification metadata — verified_at,
verified_by, a computed confidence (authoritative / provisional / stale), and
an audience flag — backed by a trusted-authors registry, a mark_page_verified
tool, and an operator triage view. The /for-agent projection was born here
too: a token-budgeted view of any page (summary, key facts, headings outline,
recent changes, tool hints, verification state) that an agent can consume without
pulling the full markdown body. To keep all of this honest, a retrieval-quality
CI runner began scoring a curated query set with nDCG, Recall, and MRR across
retrieval modes and persisting the aggregates.
Knowledge-graph inclusion policy (late April). As the LLM-extracted knowledge graph grew, it needed a governance story. A cluster-primary inclusion/exclusion policy arrived with an admin dashboard, a CLI, per-page frontmatter overrides, and an audit trail — defaulting to exclude, so entities are opted in deliberately.
Page Graph vs. Knowledge Graph (early May). A naming and conceptual cleanup
that paid for itself many times over: formally separating the Page Graph
(edges are real page-to-page wikilinks) from the Knowledge Graph (nodes are
extracted entities, edges are co-mention or typed relations). Packages, routes,
admin navigation, and tool descriptions were all disambiguated; the typed
relations: frontmatter experiment was retired; and identity normalization
(NodeSignature / EdgeSignature, NFC + predicate-synonym folding) tightened
entity dedup. A staged machine/human validation tier and a /knowledge-graph
viewer (mirroring the existing /page-graph reader) rounded it out.
Derived agent hints (mid-May). The projection got smarter without adding
author burden: derived prefer_tools and prefer_pages hints ranked across a
page and its cluster hub, a hub-summary synthesizer that overlays a Top-3
highlight when an authored hub summary is generic, a read_pages batch tool to
amortize the per-page read tax, and an agent-grade audit report for weak signals.
Knowledge-graph curation (mid-May). Curators got real tools: edge-curation v0
in the admin UI with an append-only audit table and one-click human-curated
elevation, then a full bulk curation surface on the MCP server (inspect / review /
curate nodes and edges), admin-bypass read paths so curators see freshly created
entities, and a closed node_type / relationship_type vocabulary enforced at
write time.
Subsystem decomposition (early May). A multi-phase architectural campaign
broke wikantik-main into typed subsystem factories, deleted the old
service-locator manager registry on WikiEngine in favor of typed fields,
decomposed the 800-line WikiContext into scoped sub-objects, and finished with
two static-analysis sweeps (SpotBugs + PMD) that split the worst god classes and
cleared real bugs. The result is a codebase where subsystem wiring is explicit
and testable in isolation.
The scaling characterization study (third week of May). Rather than guess at
performance, we ran a deliberate JFR-instrumented load study and let it drive the
fixes. The headline finding: the ceiling was not CPU but a per-request
DB-connection tax and a chain of shared-lock hotspots. The response was a sweep of
targeted surgeries — short-TTL caches for API-key verification, user lookup, and
KG mentions (removing per-request connections); hoisting shared JDK objects
(Collator, DateTimeFormatter, SecureRandom) off the hot path; a read/write
lock on the versioning file provider to kill per-search contention; an
event-manager dispatch-outside-the-lock fix; and a fixed-permit backpressure
semaphore that sheds load with a clean 503 before the thread pool saturates.
Dense retrieval, productionized. The brute-force in-memory vector scan — about
60% of search CPU — was replaced with selectable ANN backends: an in-process
Lucene HNSW index (now the production default, reading metadata via DocValues
rather than stored fields) and a server-side pgvector HNSW option for split-DB
topologies, each gated behind a retrieval-quality parity test so the speed-up
couldn't silently degrade relevance. These landed across 2.0.1 and 2.0.2.
Operations and packaging (early-to-mid May). The project grew the trappings of
something meant to be run by others: a community documentation set (CONTRIBUTING,
SECURITY, code of conduct, a definitive operations handbook), a bin/container.sh
wrapper over Docker Compose, a release-on-tag workflow, and — the big one — a
bin/remote.sh single entry point for deploying and administering Wikantik on a
remote host over SSH (image transfer, pages rsync, health-polled deploys with
auto-rollback). 2.0.0 was cut and the stack went live in Docker on its first
real host.
Observability, handed off. An in-repo Prometheus + Grafana overlay was built
and then deliberately retired in favor of an external monitoring stack
(jakemon) that scrapes the container's /metrics; a k6 load-test harness with a
--verify gate that confirms dashboard panels actually moved was added alongside.
Off-box backup and disaster recovery (third week of May). A 3-2-1 backup
posture arrived as a pull model: a NAS reaches in and pulls read-only snapshots on
a daily timer, with restore drills, per-tier Prometheus metrics, and a
dr-restore.sh that stands a fresh host up from a verified snapshot with a single
command.
SSO and account lifecycle (late May). A dedicated SSO hardening test suite
closed SAML and edge-case gaps — multi-valued claim normalization, fail-closed
identity-collision handling, session rotation against fixation, configurable
identity claims — and Google OIDC went live in production, with SAML support
and self-service account deletion alongside published privacy and terms pages.
This was 2.0.3.
Go-to-market (late May). A static marketing site for www.wikantik.com was
built and shipped — hero, problem framing, comparison table, hosting options, an
"ask your wiki" terminal moment, and a lead-capture form wired to a serverless
backend — together with SEO fixes (correct sitemap domain, per-page titles,
JSON-LD). Releases 2.0.4 and 2.0.5 carried these out.
The last stretch of the window returned to the everyday reader and author experience.
Anchored comments (last week of May). A Google-Docs-style commenting system —
threads anchored to selected text via robust text-quote selectors, a reader-side
drawer with highlights, re-anchoring that survives edits, reply/resolve/reopen,
and admin-only thread deletion — built on new comment_threads / comments
tables and a fresh REST surface, capped by a comment UX overhaul.
Personalization and blogging (29 May). A personalized left-navigation "me zone" with a recently-viewed list that updates live across instances, plus a round of blog read-path and delete-UI fixes.
Page ownership (30 May). A page-ownership admin surface — orphaned-page triage
and reassign-by-user — gained a consistent data model when AI-agent-authored pages
(whose frontmatter author is an agent name, not a login) were given a default
owner: a dedicated agents service account, configurable and backfilled across
the corpus, so ownership is never silently null. The ownership table also began
showing each page's current name beside its canonical ID.
This page is a narrative summary; the authoritative record of every change is the
git history and the per-release CHANGELOG.