Collaborative Documentation Extension
NIP-XX: Collaborative Documentation Spaces
draft optional
This NIP extends the Documentation Spaces specification to support multi-author collaboration, allowing anyone to contribute to documentation while maintaining quality control through various permission models.
Overview
This extension adds collaboration features to Documentation Spaces by introducing:
- Contributor Lists for managing who can edit documentation
- Edit Proposals for suggesting changes without direct write access
- Merge Events for accepting proposed changes
- Permission Models (open, moderated, restricted) for different collaboration styles
- Full backwards compatibility with non-collaborative documentation spaces
New Event Kinds
Edit Proposal (kind:39562)
Proposes changes to an existing documentation page without directly modifying it.
{
"kind": 39562,
"content": "# Welcome\n\nThis is the UPDATED introduction page with improvements.",
"tags": [
["d", "proposal-uuid-12345"],
["a", "39561:<author-pubkey>:introduction", "<relay>"],
["space", "my-project-docs"],
["page", "introduction"],
["title", "Introduction"],
["format", "markdown"],
["summary", "Fixed typos and added more details"],
["parent", "getting-started"]
]
}Required tags:
d: Unique identifier for this proposala: Address tag pointing to the target page being modified (39561:<pubkey>:<page-d-tag>)space: The space identifier where the target page existspage: Thedtag of the target pagetitle: Proposed title for the pageformat: Markup format of the proposed content
Optional tags:
summary: Description of changes being proposedparent: Proposed parent page (if changing hierarchy)order: Proposed order valuet: Proposed category tags- All other tags from the original page specification
Content field: The complete proposed content for the page (not a diff/patch).
Merge Event (kind:39563)
Accepts an edit proposal and signals that changes should be incorporated.
{
"kind": 39563,
"content": "Looks good, merging this proposal.",
"tags": [
["d", "merge-uuid-67890"],
["e", "<proposal-event-id>", "<relay>", "proposal"],
["a", "39562:<proposer-pubkey>:proposal-uuid-12345", "<relay>"],
["p", "<proposer-pubkey>"],
["merged_at", "1234567890"]
]
}Required tags:
d: Unique identifier for this merge evente: Event ID of the accepted proposala: Address of the accepted proposalp: Pubkey of the proposal author
Optional tags:
merged_at: Unix timestamp when merge was acceptedreview_comment: Additional notes about the merge
Content field: Optional message about the merge decision.
After publishing a merge event, the page owner should publish an updated kind:39561 event incorporating the proposed changes.
Extended Space Permissions
Documentation Spaces (kind:33527) gain new optional tags for collaboration:
{
"kind": 33527,
"content": "# Welcome to Our Wiki",
"tags": [
["d", "community-wiki"],
["title", "Community Wiki"],
["permission_model", "open"],
["p", "<contributor1-pubkey>", "", "editor"],
["p", "<contributor2-pubkey>", "", "editor"],
["p", "<moderator-pubkey>", "", "moderator"]
]
}New optional tags:
permission_model: Collaboration mode (open,moderated,restricted, or omitted for single-author)open: Anyone can directly publish pages in this spacemoderated: Anyone can propose edits, but only editors can merge themrestricted: Only listed contributors can propose or publishp: Contributor/role assignments with role marker in the 3rd positioneditor: Can publish pages and merge proposalsmoderator: Can merge proposals but not directly publishcontributor: Can propose edits (explicit listing for restricted spaces)
Backwards Compatibility:
- Spaces without
permission_modeltag default to single-author (only space creator can edit) - Spaces without any
ptags with roles function as before - Existing clients ignore unknown tags
Permission Models
Single-Author (Default - Backwards Compatible)
{
"kind": 33527,
"tags": [
["d", "my-docs"],
["title", "My Documentation"]
]
}- No
permission_modeltag - Only the space creator (event author) can create/edit pages
- Fully backwards compatible with existing implementation
Open Collaboration
{
"kind": 33527,
"tags": [
["d", "open-wiki"],
["title", "Open Wiki"],
["permission_model", "open"]
]
}- Anyone can publish pages directly
- Anyone can edit any page by publishing newer versions
- Like Wikipedia's model: assume good faith, rollback vandalism
- Best for: Community knowledge bases, public documentation
Moderated Collaboration
{
"kind": 33527,
"tags": [
["d", "moderated-docs"],
["title", "Moderated Documentation"],
["permission_model", "moderated"],
["p", "<editor1-pubkey>", "", "editor"],
["p", "<editor2-pubkey>", "", "editor"]
]
}- Anyone can submit edit proposals (
kind:39562) - Only listed editors can publish pages and merge proposals
- Best for: Official documentation, curated wikis
Restricted Collaboration
{
"kind": 33527,
"tags": [
["d", "private-wiki"],
["title", "Team Wiki"],
["permission_model", "restricted"],
["p", "<member1-pubkey>", "", "contributor"],
["p", "<member2-pubkey>", "", "editor"]
]
}- Only listed contributors can submit proposals
- Only listed editors can publish pages and merge proposals
- Best for: Private team documentation, sensitive content
Page Collaboration
Direct Editing (Open Spaces)
In open spaces, anyone can publish an updated version of a page:
{
"kind": 39561,
"content": "# Updated Content",
"tags": [
["d", "introduction"],
["space", "open-wiki"],
["title", "Introduction (Updated)"],
["format", "markdown"],
["e", "<previous-version-event-id>", "", "previous"]
]
}The e tag with marker "previous" creates a version chain.
Edit Proposals (Moderated/Restricted Spaces)
In moderated or restricted spaces, non-editors submit proposals:
{
"kind": 39562,
"content": "# Improved Introduction\n\nI fixed the grammar and added examples.",
"tags": [
["d", "proposal-intro-fix"],
["a", "39561:<original-author>:introduction"],
["space", "moderated-docs"],
["page", "introduction"],
["title", "Introduction"],
["format", "markdown"],
["summary", "Grammar fixes and added examples"]
]
}Editors review and can merge:
{
"kind": 39563,
"content": "Great improvements, thanks!",
"tags": [
["d", "merge-intro-fix"],
["e", "<proposal-event-id>", "", "proposal"],
["a", "39562:<proposer-pubkey>:proposal-intro-fix"],
["p", "<proposer-pubkey>"]
]
}Then publish the updated page:
{
"kind": 39561,
"content": "# Improved Introduction\n\nI fixed the grammar and added examples.",
"tags": [
["d", "introduction"],
["space", "moderated-docs"],
["title", "Introduction"],
["format", "markdown"],
["e", "<previous-version-event-id>", "", "previous"],
["e", "<proposal-event-id>", "", "merged"],
["p", "<proposer-pubkey>", "", "contributor"]
]
}The p tag with "contributor" marker gives credit to the proposal author.
Querying Collaborative Content
Find Edit Proposals for a Page
{
"kinds": [39562],
"#space": ["my-docs"],
"#page": ["introduction"]
}Find Pending Proposals (Unmerged)
{
"kinds": [39562],
"#space": ["my-docs"],
"since": <timestamp>
}Then filter out proposals that have corresponding merge events.
Find Merge History
{
"kinds": [39563],
"#a": ["39561:<author>:introduction"]
}Find Contributors to a Space
Query all pages in a space and collect unique p tags with "contributor" marker.
Version History and Attribution
Version Chain
Pages should maintain version history through e tags:
{
"kind": 39561,
"tags": [
["e", "<version1-event-id>", "", "previous"],
["e", "<version2-event-id>", "", "previous"],
["e", "<proposal-event-id>", "", "merged"]
]
}Attribution
Pages should credit all contributors:
{
"kind": 39561,
"tags": [
["p", "<author1>", "", "author"],
["p", "<contributor1>", "", "contributor"],
["p", "<contributor2>", "", "contributor"]
]
}Conflict Resolution
Concurrent Edits
When multiple versions of the same page exist with the same created_at:
- Clients should show both versions and let editors merge manually
- The version from the space owner takes precedence (for moderated/restricted)
- The newest version takes precedence (for open)
Edit Conflicts
When a proposal becomes stale (target page has been updated):
- Proposer should submit a new proposal based on current version
- Clients should show diff between proposal base and current version
- Editors can choose to merge anyway or request rebase
Client Implementation
Displaying Collaborative Spaces
Clients should:
- Show permission model prominently
- Display contributor lists
- Indicate when pages have pending proposals
- Show edit history and attribution
Proposing Edits
For non-editors in moderated/restricted spaces:
- Fetch current page version
- Present editor interface with current content
- On save, publish
kind:39562proposal - Notify editors (through notifications or UI)
Reviewing Proposals
For editors:
- Show pending proposals with diffs
- Provide approve/reject interface
- On approve, publish merge event (
kind:39563) - Publish updated page with attribution
Version History
Clients should:
- Track version chains through
etags - Show who contributed what (from
ptags) - Provide rollback capabilities
- Display merge history
Security Considerations
Permission Validation
Clients must validate:
- User has appropriate role for action
- Pubkey is listed in space's
ptags (for restricted/moderated) - Merge events come from authorized editors
Spam Prevention
For open wikis:
- Implement rate limiting
- Track reputation/trust scores
- Provide easy rollback mechanisms
- Consider WoT (Web of Trust) filters
Vandalism Protection
- Maintain complete version history
- Make rollbacks easy
- Ban malicious contributors (client-side filtering)
- Consider requiring proof-of-work for edits
Migration from Single-Author
Existing single-author spaces can become collaborative by publishing an updated space event:
Before:
{
"kind": 33527,
"tags": [
["d", "my-docs"],
["title", "My Documentation"]
]
}After:
{
"kind": 33527,
"tags": [
["d", "my-docs"],
["title", "My Documentation"],
["permission_model", "moderated"],
["p", "<trusted-editor>", "", "editor"]
]
}All existing pages remain valid. The space owner maintains full control.
Examples
Community Wiki (Open)
Space:
{
"kind": 33527,
"content": "# Nostr Community Wiki\n\nEveryone can contribute!",
"tags": [
["d", "nostr-wiki"],
["title", "Nostr Community Wiki"],
["permission_model", "open"],
["default_format", "markdown"],
["visibility", "public"]
]
}Anyone can publish/edit pages directly:
{
"kind": 39561,
"content": "# What is Nostr?\n\nNostr is a protocol...",
"tags": [
["d", "what-is-nostr"],
["space", "nostr-wiki"],
["title", "What is Nostr?"],
["format", "markdown"]
]
}Official Documentation (Moderated)
Space:
{
"kind": 33527,
"tags": [
["d", "bitcoin-docs"],
["title", "Bitcoin Protocol Documentation"],
["permission_model", "moderated"],
["p", "npub1maintainer...", "", "editor"],
["p", "npub2reviewer...", "", "editor"]
]
}User submits proposal:
{
"kind": 39562,
"content": "# Lightning Network\n\nImproved explanation with examples...",
"tags": [
["d", "lightning-improvement"],
["a", "39561:npub1maintainer...:lightning-network"],
["space", "bitcoin-docs"],
["page", "lightning-network"],
["title", "Lightning Network"],
["format", "markdown"],
["summary", "Added examples and improved clarity"]
]
}Editor merges:
{
"kind": 39563,
"content": "Excellent contribution!",
"tags": [
["d", "merge-lightning"],
["e", "<proposal-id>", "", "proposal"],
["p", "<contributor-pubkey>"]
]
}Editor publishes updated page:
{
"kind": 39561,
"content": "# Lightning Network\n\nImproved explanation with examples...",
"tags": [
["d", "lightning-network"],
["space", "bitcoin-docs"],
["title", "Lightning Network"],
["format", "markdown"],
["e", "<previous-version-id>", "", "previous"],
["e", "<proposal-id>", "", "merged"],
["p", "<contributor-pubkey>", "", "contributor"]
]
}Team Wiki (Restricted)
Space:
{
"kind": 33527,
"tags": [
["d", "team-internal"],
["title", "Team Internal Wiki"],
["permission_model", "restricted"],
["visibility", "private"],
["p", "npub1alice...", "", "editor"],
["p", "npub1bob...", "", "editor"],
["p", "npub1carol...", "", "contributor"]
]
}Only listed people can propose or publish.
Rationale
Why Proposals Instead of Patches?
- Simpler implementation: Full content is easier to validate than diffs
- Format independence: Works with all markup formats
- Better review: Editors see complete result, not just changes
- Nostr-native: Each proposal is a standalone event
Why Multiple Permission Models?
- Flexibility: Different communities have different needs
- Gradual adoption: Start single-author, expand to collaborative
- Backwards compatibility: Default to single-author if no model specified
Why Not Just Use Multiple Authors?
The p tag system with roles provides:
- Clear permissions: Know who can do what
- Attribution: Track all contributors
- Trust management: Space owners control access
Compatibility
With Original NIP
- All original event kinds remain unchanged
- Spaces without
permission_modelwork exactly as before - No breaking changes to existing functionality
Client Support Levels
- Basic: Ignore collaboration features, single-author only
- Read-only: Display collaborative content, show contributors
- Proposal: Can submit edit proposals
- Full: Can manage permissions, merge proposals, full collaboration
Future Extensions
Possible Additions
- Discussion threads on proposals (using kind:1 with
etag) - Approval voting (multiple editors approve before merge)
- Automated merges for trusted contributors
- Review workflows with required reviewer counts
- Conflict resolution mechanisms
- Change request comments (inline notes on proposals)