Configuring UrsaMU
This page documents the v2.6.0 configuration surface — config/config.json and
the environment variables consumed at startup.
Files
config/config.json— runtime configuration, validated at boot.env— secrets (notablyJWT_SECRET), loaded bysrc/main.tsviadotenv/load
ursamu create scaffolds both with sensible defaults and a fresh JWT_SECRET.
Top-Level Shape
{
"server": { /* transport + KV prefixes */ },
"game": { /* world metadata */ },
"theme": { /* web client styling */ },
"plugins": { /* per-plugin scoped config */ }
}
server
Transport ports and Deno-KV collection prefixes.
{
"server": {
"telnet": 4201,
"ws": 4202,
"http": 4203,
"db": "data/ursamu.db",
"counters": "counters",
"chans": "chans",
"mail": "mail",
"wiki": "wiki",
"bboard": "bboard"
}
}
| Key | Type | Default | Purpose |
|---|---|---|---|
telnet |
number | 4201 |
Telnet sidecar port |
ws |
number | 4202 |
Legacy standalone WebSocket port (the hub also accepts WS upgrades on http) |
http |
number | 4203 |
Hub HTTP + REST + WebSocket port |
db |
string | data/ursamu.db |
Fallback Deno KV database path (only used if fallback DenoKvAdapter is enabled) |
counters |
string | counters |
KV prefix for ID counters |
chans |
string | chans |
KV prefix for channels |
mail |
string | mail |
KV prefix for player mail |
wiki |
string | wiki |
KV prefix for wiki pages |
bboard |
string | bboard |
KV prefix for bulletin boards |
game
{
"game": {
"name": "My UrsaMU Game",
"description": "A collaborative-fiction MUSH.",
"version": "1.0.0",
"playerStart": "1",
"timeMultiplier": 1,
"text": {
"connect": "text/default_connect.txt",
"welcome": "text/welcome.txt",
"404": "text/404.txt"
}
}
}
| Key | Type | Purpose |
|---|---|---|
name |
string | Game name (shown in who, REST /api/v1/config) |
description |
string | Free-form description |
version |
string | Reported via @version |
playerStart |
string | DBref of the starting room for new characters |
timeMultiplier |
number | In-game-clock multiplier (u.sys.gameTime()) |
text.connect |
path | Pre-auth banner |
text.welcome |
path | Post-create welcome |
text.404 |
path | Static-route fallback |
layout.header |
mushcode | Template for header() / u.util.header |
layout.divider |
mushcode | Template for divider() / u.util.divider |
layout.footer |
mushcode | Template for footer() / u.util.footer |
game.layout — header / divider / footer mushcode
Override the engine layout helpers with TinyMUX-style templates. When set,
these apply to native header() / divider() / footer(), sandbox
u.util.*, and softcode [header()] / [divider()] / [footer()].
{
"game": {
"layout": {
"header": "[center(%ch%cy%0%cn,%1,%cg=%cn)]",
"divider": "[center(%ch%cy%0%cn,%1,%cg-%cn)]",
"footer": "[repeat(%cg=%cn,%1)]"
}
}
}
| Placeholder | Meaning |
|---|---|
%0 |
Title / label |
%1 |
Width (default 78) |
%2 |
Filler character(s) |
Supported bracket functions inside templates (sync subset):
center, ljust, rjust, repeat, space, cat, lit, strlen.
Color codes (%ch, %cy, …) and %r / %t / %b pass through.
Plugin registerHeader / registerDivider / registerFooter still work
when no config template is set for that slot. A config template for a slot
takes priority over registered plugin layout functions.
theme
Theme tokens read by the bundled web client and /api/v1/config:
{
"theme": {
"primary": "#7f5af0",
"secondary": "#2cb67d",
"accent": "#ff8906",
"background": "#16161a",
"surface": "#242629",
"text": "#fffffe",
"muted": "#94a1b2",
"glass": 0.6,
"backgroundImage": "https://example.com/bg.jpg"
}
}
plugins
Per-plugin scoped config. Plugins read their slice via
PluginConfigManager or getConfig("plugins.<name>.<key>", default).
{
"plugins": {
"discord": { "enabled": true, "token": "...", "channelId": "..." },
"my-game": { "startingGold": 100 }
}
}
Plugin manifests (ursamu.plugin.json) declare their dependencies — see
Plugin development for the manifest format and atomic-install
behavior introduced in v2.6.0.
Environment Variables
| Name | Required | Purpose |
|---|---|---|
JWT_SECRET |
Yes | HMAC secret for JWT signing. Loaded from .env by src/main.ts. If unset, JWT issuance fails — start scripts generate one automatically. |
URSAMU_TYPEGRAPH_DB |
No | Database directory/file path for the primary TypeGraph/PGlite database. Defaults to ${Deno.cwd()}/data/typegraph.db (or memory:// during test runs). |
.env is generated by ursamu create and excluded from git by the scaffold’s
.gitignore. Rotate by replacing the secret and restarting the hub; existing
sessions will be invalidated.
Runtime Configuration API
import { getConfig, setConfig } from "../../services/Config/mod.ts";
const port = getConfig<number>("server.http", 4203);
await setConfig("game.name", "New Name");
u.sys.setConfig(key, value) is the sandbox equivalent — restricted to
admin/wizard at the command layer.
Text Files
The paths in game.text.* resolve relative to the game project root. Files
support the full MUSH color-code set (%ch, %cn, %cr, %cg, %cb, %cy,
%cw, %cc, %cm, plus %xRRGGBB truecolor and %r/%t/%b).
%ch%cy==================================%cn
%ch%cw Welcome %cn
%ch%cy==================================%cn
Type 'connect <name> <password>' to log in.
Type 'create <name> <password>' to make a new character.