1 Overview
A classic wiki has one page per subject and one server that decides what the page says. This NIP removes both limits. It defines kind:30818, an addressable event (see NIP-01) that holds one encyclopedia article. Many authors write articles about the same subject. Each author keeps an independent version. Variations can be small or complete rewrites.
A subject is identified by its d tag. The d tag value is a lowercase, normalized form of the article name. Because every author normalizes the same way, articles about the same subject share the same d tag across all pubkeys.
The NIP also defines two support kinds. kind:818 is a merge request: it asks an author to accept changes from a fork. kind:30819 is a redirect: it points one article name at another. On top of these, fork and defer tag markers record where an article came from and which version its author now endorses.
There is no "the" article for a subject. There is one article per subject per author. The client decides which author's version to show. Section 8 lists ranking strategies.
2 Articles: Kind 30818
An article is a kind:30818 addressable event. The relay keeps only the latest event per pubkey + kind + d value, so an author edits an article by publishing it again. The content holds the article body. The d tag holds the normalized article name.
{
"kind": 30818,
"content": "A wiki is a hypertext publication collaboratively edited and managed by its own audience.",
"tags": [
["d", "wiki"],
["title", "Wiki"]
]
}
Four optional tags refine the article:
| Tag | Purpose |
|---|---|
| title | Display title, for when it should differ from the d tag value. |
| summary | Short description for display in article lists. |
| a | Reference to the original addressable article this one was forked from. |
| e | Reference to the exact original event version this one was forked from. |
3 D-Tag Normalization
Every client must derive the d tag from the article name with the same rules. Apply them in order:
| Rule | Level |
|---|---|
| Convert every letter that has case variants to lowercase. | MUST |
Convert whitespace to -. | MUST |
| Remove punctuation and symbols. | SHOULD |
Collapse multiple consecutive - into a single -. | SHOULD |
Remove leading and trailing -. | SHOULD |
| Preserve non-ASCII letters (Japanese, Chinese, Arabic, Cyrillic, ...) as UTF-8. | MUST |
| Preserve numbers. | MUST |
d tag. Non-ASCII letters and numbers pass through unchanged.| Input | d tag value | Note |
|---|---|---|
"Wiki Article" | "wiki-article" | lowercase, space to dash |
"What's Up?" | "whats-up" | punctuation removed |
" Hello World " | "hello-world" | dashes collapsed and trimmed |
"Article 1" | "article-1" | numbers preserved |
"ウィキペディア" | "ウィキペディア" | Japanese, no case change |
"Ñoño" | "ñoño" | Spanish, lowercased |
"Москва" | "москва" | Russian, lowercased |
"日本語 Article" | "日本語-article" | mixed scripts |
Three of the seven rules are only SHOULD: strip punctuation, collapse dashes, trim dashes. Two conforming clients can therefore compute different d tags for the same name, such as "whats-up" versus "what's-up?". The spec does not say how to resolve such splits.
4 Content Format: Djot
The content should be Djot markup, with two extra behaviors on top of standard Djot:
- A link target may be a NIP-21 URI, like
[Bob](nostr:npub1...). - A reference-style link with no matching reference becomes a wikilink. It links to the wiki article with that name. Normalize the target with the rules from section 3.
Bitcoin is a [cryptocurrency][] invented by [Satoshi Nakamoto][]. See also: [proof of work][] and [lightning network][Lightning Network]. [Satoshi Nakamoto]: nostr:npub1satoshi...
| Link | Resolves to |
|---|---|
[cryptocurrency][] | Article with d tag "cryptocurrency". No reference defined, so it is a wikilink. |
[Satoshi Nakamoto][] | The npub. A reference is defined at the bottom. |
[proof of work][] | Article with d tag "proof-of-work". |
[lightning network][Lightning Network] | Article "lightning-network"; displays as "lightning network". |
Wikilinks also work with non-Latin scripts, with the same normalization rules:
[ビットコイン][]links to the article withdtag"ビットコイン".[Japanese Article][日本語 記事]links to"日本語-記事"; displays as "Japanese Article".[Биткойн][]links to the article withdtag"биткойн"(Cyrillic, lowercased).
NIP-21 nostr: links can also point to profiles or arbitrary events. Do not link to a specific version of an article. Prefer the wikilink syntax. The reader and their client decide which version of an article to read.
Why Djot? Djot is a markup language by John MacFarlane, the author of Pandoc and a co-author of CommonMark. The NIP picked it for five reasons:
- Well-defined spec. Markdown has many incompatible dialects. The Asciidoc spec is tied to a Ruby implementation. Djot has one clear, standalone specification.
- Native implementations in JavaScript, Lua, Rust, Go, and other languages, without transpilation.
- Rich features: superscript, subscript, footnotes, tables, definition lists, and math. All useful for encyclopedic content.
- Familiar syntax, similar to basic Markdown. Easy to learn.
- Fast parsing, designed for linear-time parsers.
5 Merge Requests: Kind 818
An editor who improved a fork can ask the original author to adopt the changes. A kind:818 event is that request. It is directed to a pubkey. It references the target article and the modified event.
{
"kind": 818,
"content": "I added information about the block size limit",
"tags": [
["a", "30818:<destination-pubkey>:bitcoin", "<relay-url>"],
["e", "<version-against-which-the-modification-was-made>", "<relay-url>"],
["p", "<destination-pubkey>"],
["e", "<version-to-be-merged>", "<relay-url>", "source"]
]
}
| Field | Rule |
|---|---|
| content | Optional explanation of why this merge is requested. |
| a | The article that should be modified: the target of the merge request. |
| e | Optional: the version of the article this modification is based on. |
| e + source | The e tag with the source marker holds the ID of the event to be merged. That event MUST be a kind:30818 as defined in this NIP. |
| p | The destination pubkey: the author who is asked to merge. |
The destination pubkey answers with a NIP-25 reaction that tags the kind:818 event. A + reaction accepts the merge request. A - reaction rejects it.
6 Redirects: Kind 30819
A redirect maps one article name to another. If "BTC" should lead to "Bitcoin", publish a kind:30819 event instead of copying the content. The d tag holds the source name. The a tag points at the target article.
{
"kind": 30819,
"tags": [
["d", "btc"],
["a", "30818:<pubkey>:bitcoin", "<relay-url>"]
],
"content": ""
}
Clients use redirects in two ways. They can redirect automatically from one article to another. They can also collect many redirects for one name and generate a crowdsourced "disambiguation" page, like the ones on Wikipedia.
7 Forks and Deference
Two tag markers let wiki events point at other wiki events:
| Marker | Meaning |
|---|---|
| fork | This event came from a different version. Both an a tag and an e tag SHOULD be used, each with the fork marker, to identify the exact version it was forked from. |
| defer | The author considers someone else's entry a better version of their own. Both an a tag and an e tag SHOULD be used with the defer marker. |
A defer marker is a stronger trust signal than a + reaction. It is useful after a merge. If the original author includes the editor's changes, and the editor does not want to maintain an independent version, the editor publishes a deferring event. Clients can treat that as a deletion of the editor's version. The editor's web-of-trust weight then backs the original author's version.
8 How to Decide What Article to Display
Many articles can exist for one name. The client must rank them. The criteria vary between users and clients. The NIP describes four usable signals:
- Reactions. NIP-25 reactions build a simple web of trust between wiki authors. A raw "like" count is unproductive. But a
+on a wiki article is a recommendation of that article, and a partial recommendation of its author. Follow recommendations 2 or 3 levels deep, and a big part of all articles gains some form of tagging. - Relays. NIP-51 relay lists of
kind:10102tell a wiki client where to query articles first, and how to rank those articles against events from other relays. - Contact lists. NIP-02 contact lists seed a recommendation system, expanded with relay lists and reaction lists through nested queries. They are a good starting point only because they are so widespread.
- Wiki-related contact lists. NIP-51 lists can also hold users trusted only in the context of wiki authorship or wiki curationship.
9 Worked Example
The session below shows a full wiki cycle. Alice publishes an article. Carol adds a redirect. Bob forks, edits, and requests a merge. Alice accepts. Orange lines go to the relay. Blue lines come from the relay.
-- Alice publishes the article "Bitcoin" (d tag normalized to "bitcoin") -- → ["EVENT", {"kind":30818,"pubkey":"a11ce…","content":"Bitcoin is a [cryptocurrency][] invented by [Satoshi Nakamoto][].\n\n[Satoshi Nakamoto]: nostr:npub1s4t0sh1…", "tags":[["d","bitcoin"],["title","Bitcoin"],["summary","The first cryptocurrency."]], …}] ← ["OK", "77aa01…", true, ""] -- Carol redirects "BTC" to Alice's article -- → ["EVENT", {"kind":30819,"pubkey":"c4a01…","content":"", "tags":[["d","btc"],["a","30818:a11ce…:bitcoin","wss://wiki.relay.example"]], …}] ← ["OK", "88bb02…", true, ""] -- Bob forks Alice's article and publishes his own version -- → ["EVENT", {"kind":30818,"pubkey":"b0b00…","content":"… plus the block size limit …", "tags":[["d","bitcoin"],["title","Bitcoin"], ["a","30818:a11ce…:bitcoin","wss://wiki.relay.example","fork"], ["e","77aa01…","wss://wiki.relay.example","fork"]], …}] ← ["OK", "99cc03…", true, ""] -- Bob asks Alice to merge his changes -- → ["EVENT", {"kind":818,"pubkey":"b0b00…", "content":"I added information about the block size limit", "tags":[["a","30818:a11ce…:bitcoin","wss://wiki.relay.example"], ["e","77aa01…","wss://wiki.relay.example"],["p","a11ce…"], ["e","99cc03…","wss://wiki.relay.example","source"]], …}] ← ["OK", "aadd04…", true, ""] -- Alice accepts with a NIP-25 "+" reaction on the merge request -- → ["EVENT", {"kind":7,"pubkey":"a11ce…","content":"+", "tags":[["e","aadd04…"],["p","b0b00…"]], …}] ← ["OK", "bbee05…", true, ""]
10 Version History
fiatjaf proposed decentralized wikis in May 2024. The content format changed twice; the normalization rules grew once. Notable changes, newest first:
- 20262026-03Content format switched from Asciidoc to Djot; the "Why Djot?" rationale was added.
- 20252025-12Normalization fixed for non-Latin scripts: preserve UTF-8 letters, lowercase where case exists, keep numbers.
- 2024-252024-2025Heading levels, spelling, JSON formatting, and markdown-leftover cleanups.
- 20242024-08"Parameterized replaceable event" renamed to "addressable event" across the repository.
- 20242024-06Content format changed from Markdown to Asciidoc.
- 20242024-05Wikilink format clarified;
dtag normalization rules added. - Origin2024-05-02fiatjaf published "NIP-54: decentralized wikis" with articles, merge requests, redirects, forks, and deference.
Original Proposal - Credits
| Author | fiatjaf |
| First commit | 2024-05-02 — “NIP-54: decentralized wikis” (PR #787) |
| Status | draft - optional |
| Source | 54.md on GitHub - full change history |
11 See Also
- NIP-01 — addressable events,
d/a/e/ptags, and the base protocol this NIP builds on. - NIP-21 — the
nostr:URI scheme used for links inside article content. - NIP-25 — reactions;
+/-on merge requests and article recommendations. - NIP-51 — lists;
kind:10102wiki relay lists and wiki-specific trust lists. - NIP-02 — contact lists as a seed for article ranking.