Authoring conventions — the contract
Every page in docs/wiki/ follows this contract. ci/wiki_lint.py mechanizes
it; the wiki-page skill loads it before any agent writes here. Agents read
these files raw — the rendered views are for humans only, so the SOURCE is
the product: pure CommonMark, restricted YAML frontmatter, mermaid fences.
Never MDX, never HTML-only content. This directory is also an Obsidian
vault (the owner's main reading surface): open docs/wiki/ in Obsidian; the
committed .obsidian/app.json makes Obsidian generate standard markdown links.
For agents — reading order
Loading context for a design task: (1) index.md — the map; (2) the
target page; (3) its depends-on pages; (4) the corpus decision ledger:
grep -rn "^### D-" docs/wiki/; (5) parking-lot.md for ideas
already filed against the system. The skyblock substrate pages bound every
system above them — include them when designing anything they feed. Do NOT
read the whole corpus.
Frontmatter
Restricted subset only — key: value and key: [a, b] between --- fences:
---
id: skills # required; must equal the filename stem
status: ratified # required: draft | proposed | ratified | shipped
ratified: 2026-07-20 # required once status is ratified/shipped (YYYY-MM-DD)
supersedes: docs/design/PROGRESSION.md # optional; see "Absorbing old docs"
depends-on: [vision, combat-style] # optional; page ids
---
Status flow: draft → proposed → ratified → shipped. Only the owner
ratifies. shipped means an implementing mod exists and links back here.
Page anatomy
One system per page. Sections, in order (omit only what is truly empty):
## Canon — what the system IS: player-facing truth, prose + tables
## Decisions — the decision ledger (below)
## Tuning — links into data/ files + which golden pins each curve
## Implementation — links to the owning mod + spec; never restates either
## Open questions — explicitly UNKNOWN items (UNKNOWN is a valid state)
Size: lint warns over 400 lines, fails over 600. Split before the cap.
The decision ledger
Every design decision is a heading in ## Decisions:
### D-SKILLS-07 — XP curve is RS-exponential (ratified 2026-07-20)
Rationale in a sentence or three.
**Rejected:** linear (flattens the late game); milestone-step (bursty, gameable).
Rules: the ID is D-<PAGEID>-NN (page id uppercased), globally unique, never
reused. A superseding decision gets a NEW number and names the old ID it
replaces. Rejected alternatives are mandatory — they are the
anti-re-litigation device. Before proposing anything, grep the ledger:
grep -rn "^### D-" docs/wiki/.
Numbers live in data/, not prose
Tuning values (XP rates, prices, magnitudes, drop chances) go in
docs/wiki/data/*.json (or .yaml), linked from ## Tuning. Canon prose
explains SHAPE and RATIONALE, never literal values — duplicated numbers drift.
Lint warns on likely tuning values in Canon/Decisions prose; a deliberate
structural number (e.g. "20 skills") can silence the warning with
<!-- numbers-ok --> on the same line. Curves stay code pinned by goldens;
data/ is created with its first file (owner owns all tuning).
Links, callouts, nav, index
- Cross-links are standard relative markdown links; lint fails dead ones.
Never
[[wikilinks]]— they bypass strict validation and resolve vault-globally (silent collisions). - Notes/warnings use Obsidian callout syntax (
> [!note],> [!warning]) — never!!!admonitions; lint bans them (the build converts callouts, so both Obsidian and the site render them). - Every page appears in
mkdocs.ymlnav (format- Title: path.md, one page per line) AND as a one-line entry in index.md.
Absorbing old docs
When a design session redesigns a system, its docs/design/ file is absorbed:
the wiki page sets supersedes: docs/design/<FILE>.md, and the old file is
replaced by a three-line pointer stub containing the literal marker
MOVED-TO-WIKI. Lint enforces both halves. Engineering docs (BUILD, STORAGE,
LIB-STRUCTURE, …) stay in docs/design/ — this wiki is game canon only.
Verification
Before claiming a page done: python ci/wiki_lint.py and python wiki.py build
both green.