Wiki knowledge engine — schema-governed archives, wikilinks, synthesis
The wiki engine gives each archive a three-layer instruction model: hard rules enforced by code, a per-archive schema prompt (advisory editorial guidelines), and structured fields (persona, purpose, scope). Mental model: schemaPrompt is to the wiki what …
The wiki engine gives each archive a three-layer instruction model: hard rules enforced by code, a per-archive schema prompt (advisory editorial guidelines), and structured fields (persona, purpose, scope). Mental model: schemaPrompt is to the wiki what a CLAUDE.md is to a code repo.
Community feature. Operator reference for the Wiki Schema Layer (Phase 187, audited at the v0.25 gate — WIKS-01/02, verified against the live code). Source:docs/WIKI_SCHEMA_LAYER.md(v0.28.1). Provenance rows:FACT-CENSUS.mdF-WIKI-1.
The 3-layer model
| Layer | Nature | Enforcement | Scope |
|---|---|---|---|
| Hard rules | Code-enforced, unconditional | validateWritablePath + the always-injected prompt block | Every archive-bound write path |
| schemaPrompt | Per-archive editorial guidelines | Data + prompt only (never a gate) | Per archive, opt-in (empty = off) |
| Structured fields | Config-injected persona/purpose/scope | The existing synthesis/orchestrator behavior | Per archive, unchanged |
Hard rules (code-enforced)
Two unconditional mechanisms, config-independent:
- The filesystem guard.
validateWritablePath(packages/server/src/utils/archivePath.ts:39-54) rejects any write target outside<archiveBase>/wiki/: the anti-traversal check runs first (validateArchivePath), then thewiki/-prefix check — a target outsidewiki/throwsWrite target outside wiki/ directory: <path>. raw_sources/ is immutable.BothcreatePageandupdatePagecall it before anyfs.writeFile. No API endpoint writes underraw_sources/— it is immutable by design. - The prompt-layer mirror.
HARD_RULE_RAW_SOURCES(archiveConfigService.ts:52-53) is an always-on block appended to every archive-bound prompt: its wording mirrors the guard (raw_sources/ is immutable), so the model never even attempts the way out ofwiki/— and if it did, the code guarantees nothing lands.
schemaPrompt (advisory)
A free-text field persisted inside the archive's config JSON:
- Schema:
schemaPrompt: z.string().max(10000).optional()onarchiveConfigSchema— an additive key, zero migrations. 10000 chars ≈ ~2500 tokens. - Validation: Zod on every write (
PUT /api/archives/:id/config); an over-cap payload →400 { error: "Invalid config", details.schemaPrompt }. - Read contract:
GET /api/archives/:id/configon an archive with no stored row →200with the schema-default config ({ rawSourcesImmutable: true }): the first-save hydration path; archives with a row return the stored blob verbatim. - The injection-time cap: stored legacy blobs over 10000 chars are truncated at injection with the
(truncated at 10000 characters)annotation — legacy rows are never re-validated on read. - Advisory by design: the block enters as DATA with an explicit advisory label, never as a system-prompt privilege grant. No sanitization beyond the length cap; contradictory instructions = an accepted quality risk, mitigated by the UI's helper text and template.
Precedence
hard rules (code) > schemaPrompt (advisory) > structured fields- schemaPrompt can never override the hard rules (the prompt declares it; the code enforces it).
- On conflict with the structured fields, schemaPrompt wins (
On conflict with the structured fields (persona, purpose, scope), these guidelines take precedence over them.). - An archive without schemaPrompt behaves as baseline + the hard rule — zero enhancement, zero degradation (no empty placeholder sections in prompts).
Where the block lands in the prompt
| Seam | Where | Notes |
|---|---|---|
| Chat orchestrator (non-streaming) | orchestrator.ts:295-302 (runAgent) | hard rule ALWAYS + the advisory block when present |
| Chat orchestrator (streaming) | orchestrator.ts:805-812 (runAgentStreaming) | the streaming twin, the same order |
| Synthesis Pass 4 (decision) | synthesisStages.ts:784-788 | the advisory block rides the SYSTEM role; Passes 1/2 and the contradiction judging stay undefined |
Inside the system prompt: after the MANDATORY SEARCH RULE block, before the systemPrompt ternary.
wiki_query and wiki_write
The builtins wiki_query and wiki_write are skills whose execute() paths make no LLM call: the write path generates deterministic previews (wikiWriteService.ts contains zero LLM invocations) — per-skill injection would reach no model; the only LLM-facing surface is the orchestrator system prompt.
rawSourcesImmutable
rawSourcesImmutable: boolean (default true) on archiveConfigSchema is a documentation flag, never an enforcement toggle: the immutability rule applies regardless of the flag (the validateWritablePath guard + the always-on block guarantee it).
This guide covers the operator surface for the wiki knowledge engine; the engineering deep dive lives in the twin post:
Provenance
| Section | Source |
|---|---|
| The 3-layer model / hard rules | docs/WIKI_SCHEMA_LAYER.md (§ The 3-layer model, § Layer 1) — F-WIKI-1 |
| schemaPrompt / precedence / seams | docs/WIKI_SCHEMA_LAYER.md (§ Layer 2, § Precedence chain, § Injection seams) |
| Audit | Phase 187 commits; finalized at the v0.25 gate (WIKS-01/02, Phase 194) |
---
Operator reference — Simmetric Chat v0.28.1 (docs refreshed 2026-10-02, census SHA `aca5b8ff`).