Wiki-DB -- Self-Describing MNEME Wiki Databases
Overview
A convention for MNEME databases that makes them self-describing, portable
wiki files. A single .mneme file carries its content, search indexes,
browsing indexes, and presentation style.
Convention version
The current convention version is 1.
A viewer must check the version key in the manifest keyspace before
proceeding. If the database version is greater than the version the viewer
supports, it must refuse to open the database with a clear error.
Manifest keyspace: __wiki
A conforming wiki-db has a keyspace named __wiki containing well-known
keys that describe the rest of the database. Each manifest field is a
separate key.
The __wiki keyspace name is reserved. Applications must not use it for
any other purpose.
Required keys
| Key | Value type | Description |
|---|---|---|
version | integer | Convention version (currently 1) |
title | string | Human-readable wiki title |
content_keyspace | string | Name of the FT keyspace holding readable content |
content_format | string | "markdown" or "plain" |
Optional keys
| Key | Value type | Description |
|---|---|---|
description | string | Short description of the wiki's content |
meta_keyspace | string | Name of the KV keyspace holding entry metadata |
indexes | string (JSON) | Array of browsing index descriptors |
entry_point | string (JSON) | View directive for initial landing |
tss | string (JSON) | TSS stylesheet for rendering content |
collections | string (JSON) | Array of additional content collection descriptors |
Content organization
Content keyspace
The primary content lives in an FT keyspace (full-text indexed). Each
entry is a document keyed by its entry ID. The content format is declared
in the manifest: "markdown" (preferred) or "plain".
local ft = db:ft_keyspace("content")
ft:put("rfc-790", "# RFC 790\n\nAssigned Numbers\n\n...")
Metadata keyspace
An optional KV keyspace holding per-entry metadata as JSON strings. Each key matches the corresponding entry ID in the content keyspace.
local meta = db:keyspace("meta")
meta:set("rfc-790", json.encode({
title = "Assigned Numbers",
authors = {"J. Postel"},
date = "1981-09",
status = "Historic"
}))
The metadata schema is not prescribed by the convention, applications store whatever fields are useful for their domain. The viewer reads available fields and adapts its display accordingly.
Shared key convention
The same key identifies an entry across all keyspaces. Entry rfc-790
in the content FT keyspace corresponds to rfc-790 in the metadata KV
keyspace.
Browsing indexes
Browsing indexes are sorted sets in the metadata keyspace that provide
ordered views over the entries. Each index is described in the indexes
manifest key as a JSON array.
Index descriptor
[
{"keyspace": "meta", "set": "by_date", "label": "By date", "order": "desc"},
{"keyspace": "meta", "set": "by_pages", "label": "By size", "order": "desc"}
]
| Field | Type | Description |
|---|---|---|
keyspace | string | Keyspace containing the sorted set (defaults to collection's meta) |
set | string | Sorted set name |
label | string | Human-readable label for the viewer UI |
order | string | Default display order: "asc" or "desc" |
collection | string | Optional: name of the collection this index belongs to |
Each sorted set maps scores to entry IDs:
local zs = meta:sorted_set("by_date")
zs:add(198109, "rfc-790", 202301, "rfc-9293")
Entry point
The entry_point manifest key is a JSON object that tells the viewer
what to show when a wiki-db is first opened.
Browse entry point
{"mode": "browse", "index": "by_date", "order": "desc"}
Opens the specified browsing index. The index value must match a set
name from the indexes array.
Search entry point
{"mode": "search"}
Presents the user with a search prompt.
If entry_point is absent, the viewer should default to search mode when
no indexes are available, or to the first declared index otherwise.
Collections
A wiki-db may contain additional content collections beyond the primary one. Each collection is a self-contained FT keyspace with its own optional metadata keyspace, enabling a single database to hold different types of content (e.g., dictionary entries and literary quotations).
Collection descriptor
The collections manifest key is a JSON array of collection objects:
[
{
"name": "quotes",
"label": "Quotes",
"content_keyspace": "quotes",
"content_format": "markdown",
"meta_keyspace": "quotes_meta"
}
]
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Unique collection identifier |
label | string | no | Human-readable label (defaults to name) |
content_keyspace | string | yes | FT keyspace holding collection content |
content_format | string | no | "markdown" or "plain" (defaults to primary) |
meta_keyspace | string | no | KV keyspace for collection metadata |
The primary collection is always defined by the top-level content_keyspace,
content_format, and meta_keyspace fields. The collections field
defines additional collections only.
Collection-aware indexes
Index descriptors gain an optional collection field that binds the
index to a specific collection:
[
{"set": "by_alpha", "label": "Alphabetical", "order": "asc"},
{"set": "by_author", "label": "By author", "order": "asc", "collection": "quotes"}
]
When collection is absent, the index belongs to the primary collection.
When present, the viewer uses the named collection's meta keyspace for
the sorted set and title lookups, and the collection's FT keyspace for
content retrieval.
Viewer behavior
Browsing an index sets the viewer's current collection. Subsequent
view and search commands operate on the current collection. The
search -c <name> flag explicitly targets a collection.
Presentation
TSS stylesheet
The optional tss manifest key holds a TSS stylesheet serialized as
JSON. The viewer deserializes it to a Lua table and passes it to the
pager for rendering.
local wiki = db:keyspace("__wiki")
local tss_json = wiki:get("tss")
if tss_json then
local rss = json.decode(tss_json)
local style = tss.new(rss)
pager:set_style(style)
end
If tss is absent, the viewer uses its default stylesheet.
Viewers
A wiki-db viewer is any application that opens a conforming .mneme
file, reads the __wiki manifest, and presents the content to the user.
Graceful degradation
A conforming viewer should adapt to what the manifest advertises rather than requiring every optional feature to be present:
| Condition | Expected viewer behavior |
|---|---|
No indexes | Browse unavailable; search-only mode |
No tss | Viewer's default stylesheet used for rendering |
No meta_keyspace | Search results show entry IDs only, no enrichment |
No entry_point | Default to first index if available, else search |
No collections | Only the primary collection is available |
Lilush Shell Wiki mode
The Lilush Shell includes a built-in wiki-db viewer as one of its shell modes, activated with F3.
It provides a command-driven interface with tab completion, renders
content through the shell's pager (with markdown support and optional
custom TSS from the database), and searches entries with BM25 full-text
ranking. Type help inside wiki mode for a quick command reference.
Database selection
The wiki command selects which database to view:
| Invocation | Behavior |
|---|---|
wiki | List available databases under ~/.local/share/lilush/wiki/ |
wiki <name> | Open/switch to a named database from the default directory |
wiki /path/to/db.mneme | Open/switch to a database at an arbitrary path |
Database names support tab completion over .mneme files in the
default directory.
Commands
| Command | Description |
|---|---|
search [-n N] [-c coll] <query> | Full-text search; -c targets a collection |
browse [index] [-o N] [-n N] | Browse entries from a sorted-set index with pagination |
view <key> | Render an entry in the pager with the wiki's TSS style |
info | Show wiki metadata: title, description, available features |
help | Show command usage summary |
Example: creating a conforming wiki-db
local mneme = require("mneme")
local json = require("std.json")
local db = mneme.open("my_wiki.mneme")
-- Set up manifest
local wiki = db:keyspace("__wiki")
wiki:set_integer("version", 1)
wiki:set("title", "My Knowledge Base")
wiki:set("description", "Personal notes and references")
wiki:set("content_keyspace", "content")
wiki:set("content_format", "markdown")
wiki:set("meta_keyspace", "meta")
wiki:set("indexes", json.encode({
{keyspace = "meta", set = "by_date", label = "By date", order = "desc"}
}))
wiki:set("entry_point", json.encode({mode = "browse", index = "by_date"}))
-- Populate content
local ft = db:ft_keyspace("content")
ft:put("hello-world", "# Hello World\n\nThis is the first entry.")
-- Populate metadata
local meta = db:keyspace("meta")
meta:set("hello-world", json.encode({
title = "Hello World",
date = "2026-04-01"
}))
-- Create browsing index
local by_date = meta:sorted_set("by_date")
by_date:add(20260401, "hello-world")
db:close()
Reserved names
| Name | Scope | Purpose |
|---|---|---|
__wiki | Keyspace | Manifest keyspace; must not be used for other purposes |