Wiki
Every UrsaMU game project includes a wiki/ directory at the project root.
Files placed here are immediately available to players via in-game commands and
to external tools via the REST API. No database setup is required — the wiki is
file-based Markdown.
Overview
wiki/
├── home.md ← shown for +wiki home
├── lore/
│ ├── index.md ← shown for +wiki lore
│ └── factions.md ← shown for +wiki lore/factions
├── rules.md
└── images/
└── banner.png ← served at GET /api/v1/wiki/images/banner.png
Players read pages with +wiki. Admins and wizards write and edit pages with
@wiki. All write operations require the admin, wizard, or superuser
flag.
Directory Structure
Subdirectories become sections. A directory with an index.md shows that file
when listed; otherwise the directory listing is shown directly.
wiki/lore/index.md → +wiki lore (section overview)
wiki/lore/factions.md → +wiki lore/factions
wiki/rules.md → +wiki rules
README.md files at any level are ignored by the wiki system — they are for
human readers of the repository only.
Frontmatter
Pages support YAML-ish frontmatter for metadata. The parser supports strings,
numbers, booleans, and inline arrays.
---
title: The Iron Pact
author: Storyteller
date: 2026-03-18
tags: [lore, factions, politics]
---
The Iron Pact was forged in the aftermath of the Sundering...
| Field | Type | Purpose |
|---|---|---|
title |
string | Display name shown in listings and page headers |
author |
string | Who wrote the page |
date |
string | Publication date (any format) |
tags |
array | Searchable keywords |
Any additional keys are stored and returned by the API — use them freely for
custom metadata.
In-Game Commands
Reading: +wiki
+wiki list root-level pages and directories
+wiki <path> read a page or list a directory
+wiki/search <query> full-text search (title, body, tags)
Examples:
+wiki → root listing
+wiki lore → lore/index.md or directory listing
+wiki lore/factions → lore/factions.md
+wiki/search iron pact → all pages mentioning "iron pact"
Writing: @wiki (admin/wizard only)
@wiki/create <path>=<title>/<body> create a new page
@wiki/edit <path>=<new body> replace the body of an existing page
@wiki/fetch <url>=<wiki-path> download a remote image into wiki/
Examples:
@wiki/create lore/factions=The Iron Pact/The Iron Pact was forged...
@wiki/edit lore/factions=Updated text about the Iron Pact...
@wiki/fetch https://example.com/banner.png=images/banner.png
@wiki/create sets author and date automatically from the acting player.
@wiki/edit preserves all existing frontmatter and replaces only the body.
@wiki/fetch blocks private/loopback URLs and enforces a 10 MB limit.
REST API
The wiki is exposed at /api/v1/wiki. Write operations (POST, PATCH,
DELETE, PUT) require a valid session token.
List all pages
GET /api/v1/wiki
Returns an array of page stubs:
[
{ "path": "home", "title": "Home", "type": "page" },
{ "path": "lore/factions", "title": "The Iron Pact","type": "page" }
]
Search
GET /api/v1/wiki?q=iron+pact
Returns matching stubs (title, body, and tag matches).
Read a page
GET /api/v1/wiki/<path>
Returns the page’s frontmatter fields merged with a body key:
{
"path": "lore/factions",
"title": "The Iron Pact",
"author": "Storyteller",
"date": "2026-03-18",
"tags": ["lore", "factions"],
"body": "The Iron Pact was forged..."
}
If <path> is a directory, a listing is returned:
{
"path": "lore",
"type": "directory",
"children": [
{ "path": "lore/factions", "title": "The Iron Pact", "type": "page" }
]
}
Create a page
POST /api/v1/wiki
Content-Type: application/json
{
"path": "lore/factions",
"title": "The Iron Pact",
"tags": ["lore", "factions"],
"body": "The Iron Pact was forged..."
}
Returns 201 on success, 409 if the page already exists.
Update a page
PATCH /api/v1/wiki/<path>
Content-Type: application/json
{ "body": "Revised text..." }
Only the fields included in the request are changed. Omit body to update
metadata only.
Delete a page
DELETE /api/v1/wiki/<path>
Removes <path>.md or <path>/index.md. Returns { "deleted": true }.
Static Assets
Images and PDFs can be stored in the wiki directory and served over HTTP.
Upload via API
PUT /api/v1/wiki/images/banner.png
Content-Type: image/png
<binary body>
Maximum upload size is 10 MB. Supported types:
| Extension | MIME type |
|---|---|
.jpg / .jpeg |
image/jpeg |
.png |
image/png |
.gif |
image/gif |
.webp |
image/webp |
.svg |
image/svg+xml |
.pdf |
application/pdf |
Upload via in-game command
@wiki/fetch https://example.com/banner.png=images/banner.png
Fetches the remote URL and saves it at wiki/images/banner.png. Private and
loopback addresses are blocked.
Retrieve
GET /api/v1/wiki/images/banner.png
Returns the raw file with the appropriate Content-Type header and a
Cache-Control: public, max-age=3600 header.
Hooks
Plugins can react to wiki changes by subscribing to wikiHooks:
import { wikiHooks } from "ursamu/plugins/wiki";
wikiHooks.on("wiki:created", (page) => {
console.log(`New page: ${page.path} — "${page.meta.title}"`);
});
wikiHooks.on("wiki:edited", (page) => {
console.log(`Updated: ${page.path}`);
});
wikiHooks.on("wiki:deleted", (page) => {
console.log(`Deleted: ${page.path}`);
});
| Event | Fires when |
|---|---|
wiki:created |
A new page is written (REST or in-game) |
wiki:edited |
A page’s body or metadata is updated |
wiki:deleted |
A page or asset is removed |
Tips
Use subdirectories to organize content
Flat listings become unwieldy quickly. Group pages by topic:
wiki/lore/ world background, factions, history
wiki/rules/ policies, chargen rules, house rules
wiki/staff/ internal notes, plot threads, NPC rosters
wiki/news/ IC announcements, session recaps
Use frontmatter tags for cross-cutting search
Tags are searched alongside title and body, so +wiki/search faction finds
every page tagged factions even if the word doesn’t appear in the body.
Version your wiki with git
Because the wiki is plain files, it is automatically tracked by git. Staff can
edit pages in their editor and push; the changes are live immediately after the
server reloads.
The home.md convention
The file wiki/home.md is created automatically when you scaffold a new
project. Treat it as the entry point — link from it to your major sections so
that +wiki home gives new players an orientation.