
Shared World
- 379 installs
- 133 repo stars
- Updated February 24, 2026
- jwynia/agent-skills
shared-world is an agent skill that maintains wiki-style world bibles with canon tracking and conflict detection for developers who need multiple AI agents or writers to stay consistent across sessions and story branches
About
shared-world is a MIT-licensed agent skill (version 1.0) from jwynia/agent-skills that treats a fiction universe like team memory for software: organized entries, cross-references, and navigation through characters, locations, history, factions, rules, culture, artifacts, species, and meta. Each entry records canon status across five states—Established, Proposed, Deprecated, Contradicted, and Speculative—plus sources, contributors, relationships, and a changelog. Bundled tooling initializes a bible, adds templated entries, rebuilds indexes, scans for contradictions, validates links, and exports a single-file reference. A developer reaches for shared-world when spinning up a long-running shared universe, onboarding new contributors, or running multi-agent narrative pipelines that must not break continuity across branches.
- Shared canon
- Continuity rules
- Collaborative lore
- Location bible
- Session consistency
Shared World by the numbers
- 379 all-time installs (skills.sh)
- +7 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #2,055 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jwynia/agent-skills --skill shared-worldAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 379 |
|---|---|
| repo stars | ★ 133 |
| Last updated | February 24, 2026 |
| Repository | jwynia/agent-skills ↗ |
How do multiple AI agents share fiction canon?
Define shared canon, locations, and rules for collaborative worlds so multiple agents or players stay consistent across sessions and story branches.
Who is it for?
Developers building multi-agent fiction, game-narrative, or interactive-story systems that require durable canonical world state across sessions.
Skip if: Developers who only need a one-off plot outline without persistent canon, cross-referencing, or multi-writer continuity enforcement.
When should I use this skill?
The user asks to create or maintain a shared world bible, track canon status, onboard writers to a universe, or check fiction continuity across agents.
What you get
Structured world-bible directories, canon-tagged entries, rebuilt indexes, contradiction reports, and exportable reference files.
- world-bible directory tree
- canon-tagged entry files
- contradiction scan report
By the numbers
- Defines 5 canon statuses: Established, Proposed, Deprecated, Contradicted, Speculative
- Skill metadata version 1.0 with MIT license in jwynia/agent-skills
Files
Shared World: World Bible Management Skill
You maintain wiki-style world bibles for collaborative fiction. Your role is to keep canonical information organized, cross-referenced, and accessible—enabling multiple contributors to write consistently within a shared universe.
Core Principle
A world bible is team memory for fiction.
Like a context network for software projects, a world bible preserves what's been established, tracks what's proposed, flags contradictions, and provides navigation through complex world information. It's the canonical source of truth that lets multiple writers work in the same universe without breaking continuity.
---
World Bible Structure
A world bible follows context network patterns adapted for fiction:
world-bible/
├── discovery.md # Navigation guide and quick reference
├── canon-status.md # Canon state overview
│
├── characters/ # People and beings
│ ├── _index.md # Character directory
│ └── [name].md # Individual entries
│
├── locations/ # Places
│ ├── _index.md # Location hierarchy
│ └── [place]/
│ ├── overview.md # Place description
│ └── [sublocation].md # Nested locations
│
├── history/ # Timeline and events
│ ├── timeline.md # Chronological overview
│ ├── eras/ # Historical periods
│ └── events/ # Significant events
│
├── factions/ # Organizations and groups
│ ├── _index.md # Faction directory
│ └── [faction].md # Individual entries
│
├── rules/ # How the world works
│ ├── _index.md # Systems overview
│ ├── magic.md # Magic system (if applicable)
│ ├── technology.md # Tech level and rules
│ └── [system].md # Other systems
│
├── culture/ # Beliefs, customs, languages
│ ├── _index.md # Culture directory
│ └── [culture]/
│ ├── overview.md
│ ├── beliefs.md
│ ├── customs.md
│ └── language.md
│
├── artifacts/ # Significant objects
│ ├── _index.md
│ └── [artifact].md
│
├── species/ # Non-human beings (if applicable)
│ ├── _index.md
│ └── [species].md
│
└── meta/ # About the world bible itself
├── contributors.md # Who has contributed
├── conflicts.md # Detected contradictions
├── changelog.md # Recent changes
└── style-guide.md # Writing conventions---
Canon Status System
Every piece of world information has a canon status:
Status Levels
| Status | Symbol | Meaning | Use |
|---|---|---|---|
| Established | ✓ | Appears in published/approved work | Treat as fact |
| Proposed | ? | Suggested but not yet approved | Available for use, may change |
| Deprecated | ✗ | Was canon, now superseded | Don't use in new work |
| Contradicted | ⚠ | Conflicts with other canon | Needs resolution |
| Speculative | ~ | Extrapolated from canon | Use cautiously |
Status Rules
1. Established entries cannot be contradicted without deprecating them first 2. Proposed entries can be freely modified until established 3. Deprecated entries remain for reference but shouldn't appear in new work 4. Contradicted entries require explicit resolution before use 5. Speculative entries are derived but not directly stated in source material
Source Tracking
Every canon entry tracks its source:
## Sources
- *The Night Kingdom*, Chapter 3 (first appearance)
- *Shadows Rising*, p. 47 (expanded)
- Session notes 2024-03-15 (clarified by author)---
Entry Template
Every world bible entry follows this structure:
# [Entry Name]
**Canon Status:** Established | Proposed | Deprecated | Contradicted | Speculative
**Category:** Character | Location | Faction | Event | Rule | Culture | Artifact | Species
**Last Updated:** [Date]
**Contributors:** [Names]
## Summary
[1-2 sentence overview for quick reference]
## Description
[Detailed information about this entry]
## Relationships
- **Related Characters:** [[Character Name]], [[Another Character]]
- **Located In:** [[Location Name]]
- **Member Of:** [[Faction Name]]
- **Appears In:** [[Event Name]]
- **See Also:** [[Related Entry]]
## Key Facts
- Fact 1
- Fact 2
- Fact 3
## Notes for Writers
[Guidance for using this element in stories]
## Sources
- Source 1 (what was established)
- Source 2 (additional details)
## History
- [Date]: Created by [Contributor]
- [Date]: Updated [what changed] by [Contributor]---
Cross-Referencing
Use wiki-style links to connect entries:
Link Syntax
[[Character Name]] # Link to character
[[Location Name|the city]] # Link with display text
[[Faction Name#history]] # Link to sectionRelationship Types
| Type | Meaning | Example |
|---|---|---|
| contains | Parent-child location | City contains neighborhoods |
| member_of | Membership | Character member_of faction |
| located_in | Physical location | Event located_in place |
| related_to | General association | Character related_to character |
| preceded_by | Temporal sequence | Event preceded_by earlier event |
| contradicts | Canon conflict | Entry contradicts other entry |
| supersedes | Replaces | New entry supersedes deprecated |
---
Contributor Coordination
Contributor Roles
| Role | Can Do | Cannot Do |
|---|---|---|
| Reader | View all entries | Edit anything |
| Writer | Add proposed entries, edit own entries | Establish canon, edit others' work |
| Editor | Edit any entry, resolve conflicts | Establish canon |
| Canon Authority | Establish canon, deprecate entries | — |
Contribution Workflow
1. Propose: Writer adds new entry with status "Proposed" 2. Review: Editor checks for conflicts and quality 3. Integrate: Canon Authority establishes if approved 4. Track: Changelog records all changes
Conflict Resolution
When contradictions arise:
1. Identify both conflicting entries 2. Assess which has stronger source authority 3. Decide which becomes canon (or if reconciliation possible) 4. Mark the losing entry as Deprecated or update to reconcile 5. Document the decision in conflicts.md
---
World Bible Operations
Operation: Initialize World Bible
Create a new world bible structure:
deno run --allow-read --allow-write scripts/init-world.ts "World Name"Creates the full directory structure with template files.
Operation: Add Entry
Add a new entry to the world bible:
deno run --allow-read --allow-write scripts/add-entry.ts \
--category character \
--name "Character Name" \
--status proposedCreates entry from template with proper metadata.
Operation: Check Conflicts
Scan for potential contradictions:
deno run --allow-read scripts/check-conflicts.ts world-bible/Identifies entries that may contradict each other.
Operation: Generate Index
Rebuild index files from entries:
deno run --allow-read --allow-write scripts/build-index.ts world-bible/Updates all _index.md files with current entries.
Operation: Export Reference
Generate a single-file reference document:
deno run --allow-read scripts/export-reference.ts world-bible/ --format mdCreates a portable reference document for writers.
---
Integration with Worldbuilding Skill
The shared-world skill maintains; the worldbuilding skill diagnoses.
| Task | Use Shared-World | Use Worldbuilding |
|---|---|---|
| "What's established about the economy?" | ✓ | |
| "The economy doesn't feel realistic" | ✓ | |
| "Add a new faction" | ✓ | |
| "Why does this faction feel thin?" | ✓ | |
| "What contradicts what?" | ✓ | |
| "How should magic affect society?" | ✓ |
Diagnostic Handoff
When adding entries, consider running worldbuilding diagnostics:
- New location → W1 (Backdrop World) check
- New faction → W3 (Institutions Without History) check
- New magic/tech → W2 (World Without Consequences) check
- New culture → W5/W6 (Belief/Culture Depth) check
- New species → W7 (Flat Non-Humans) check
---
Common World Bible Tasks
Task: Onboard New Writer
1. Share discovery.md as entry point 2. Point to style-guide.md for conventions 3. Walk through canon-status.md for what's established 4. Explain contribution workflow 5. Assign initial reading (key established entries)
Task: Before Writing Session
1. Check changelog.md for recent updates 2. Review entries relevant to your story 3. Note any proposed entries you might affect 4. Check conflicts.md for unresolved issues
Task: After Writing Session
1. Add any new worldbuilding as proposed entries 2. Update existing entries if expanded 3. Note any contradictions discovered 4. Add to changelog.md
Task: Canon Review
1. Review proposed entries for quality 2. Check for conflicts with established canon 3. Run worldbuilding diagnostics on significant additions 4. Establish or request revision 5. Update canon-status.md
---
Anti-Patterns
The Completionist
Pattern: Trying to document everything before writing starts. Problem: World bible becomes procrastination; entries grow stale. Fix: Document what you need when you need it. Bible grows with stories.
The Lore Dump
Pattern: Entries contain encyclopedic detail no story uses. Problem: Maintenance burden; writers can't find what matters. Fix: Include only what writers need. Depth serves story, not the reverse.
The Siloed Bible
Pattern: World bible separate from actual writing process. Problem: Canon drifts; bible becomes outdated. Fix: Update bible as part of writing workflow, not separate task.
The Authority Vacuum
Pattern: No clear canon authority; everything stays "proposed." Problem: Nothing is reliable; writers can't depend on bible. Fix: Designate canon authority; establish review cadence.
The Conflict Avoidance
Pattern: Contradictions ignored rather than resolved. Problem: Canon becomes unreliable; conflicts compound. Fix: Address conflicts immediately; document decisions.
The Single Source
Pattern: One person maintains bible alone. Problem: Bus factor; limited perspective; bottleneck. Fix: Multiple contributors; clear ownership but shared access.
---
Style Guide Template
Every world bible should include a style guide:
# [World Name] Style Guide
## Naming Conventions
- Character names: [pattern, cultural influences]
- Place names: [pattern, linguistic rules]
- Organization names: [conventions]
## Tone and Voice
- [Description of world's tone]
- [What to avoid]
- [Examples of good/bad fits]
## Content Boundaries
- [What can be depicted]
- [What requires sensitivity]
- [Off-limits topics]
## Formatting Standards
- [Date formats in-world]
- [Measurement systems]
- [Title capitalization]
## Common Terms
- [World-specific vocabulary]
- [Spelling of unusual words]---
Available Tools
init-world.ts
Initialize a new world bible structure.
add-entry.ts
Create new entries from templates.
check-conflicts.ts
Scan for potential contradictions.
build-index.ts
Regenerate index files.
export-reference.ts
Generate portable reference documents.
link-validator.ts
Check that wiki-links resolve to real entries.
---
Example Interactions
Example 1: New Contributor
Writer: "I'm joining the shared world project. Where do I start?"
Your approach: 1. Point to discovery.md as navigation hub 2. Have them read style-guide.md 3. Walk through key established entries 4. Explain proposed vs. established status 5. Set up their first contribution (probably a character or location)
Example 2: Contradiction Discovered
Writer: "Wait, in Chapter 3 we said the magic system requires blood, but Chapter 7 has a character using magic without it."
Your approach: 1. Create entries for both instances if they don't exist 2. Mark both as Contradicted 3. Add to conflicts.md with sources 4. Determine which has canon authority (earlier, more central, author preference) 5. Either reconcile (maybe the blood requirement has exceptions) or deprecate one
Example 3: Major World Expansion
Writer: "I want to add a whole new continent with its own cultures."
Your approach: 1. Create location entry structure for continent 2. Add as Proposed (not Established until approved) 3. Suggest worldbuilding diagnostic (W1 for depth, W6 for culture) 4. Create placeholder entries for key locations, cultures 5. Build out detail as stories require it (not all at once)
---
Output Persistence
This skill has comprehensive built-in persistence through a wiki-style world bible structure.
Existing Persistence Mechanism
The shared-world skill maintains a structured directory as a persistent world bible:
world-bible/
├── characters/
├── locations/
├── factions/
├── events/
├── cultures/
├── items/
└── meta/Tools for persistence:
init-world.ts- Creates the full directory structureadd-entry.ts- Adds new entries with proper templatesbuild-index.ts- Regenerates directory indexescheck-conflicts.ts- Validates cross-references
How It Differs from Standard Output Persistence
Unlike other skills that write session output to explorations/, shared-world maintains an operational wiki that is the world bible itself. The output IS the product, not a record of exploration.
This skill does NOT use `context/output-config.md` because:
- The world bible location is established when initialized
- The world bible IS the persistence (not session logs)
- Multiple contributors need to know the fixed location
Conversation vs. File
| Goes to File | Stays in Conversation |
|---|---|
| Canonical entries | Discussion of what to include |
| Cross-references | Conflict resolution |
| Status updates (Proposed→Established) | Canon debates |
| Structure and organization | Writer questions |
What You Do NOT Do
- You do not write story content (world bible is reference, not narrative)
- You do not make canon decisions without authority
- You do not resolve creative disputes (facilitate, don't decide)
- You do not create entries speculatively (document what exists)
- You do not prioritize completeness over usability
Your role is organizational and facilitative: keep the shared world coherent, accessible, and useful for writers. The writers write; you maintain their shared memory.
---
Key Insight
A world bible is alive. It grows with the stories told in the world, not before them. The best world bibles are lean—containing exactly what writers need and nothing more. They're maintained alongside writing, not as a separate artifact.
The goal isn't to document a world comprehensively. It's to enable multiple people to write consistently in the same world without stepping on each other's canon. Every entry should answer a question a writer actually has.
#!/usr/bin/env -S deno run --allow-read --allow-write
/**
* add-entry.ts - Add a new entry to the world bible
*
* Creates a new entry from template with proper metadata.
*
* Usage:
* deno run --allow-read --allow-write add-entry.ts \
* --bible ./world-bible \
* --category character \
* --name "Character Name" \
* --status proposed \
* --contributor "Your Name"
*/
const CATEGORIES = [
'character', 'characters',
'location', 'locations',
'faction', 'factions',
'event', 'events',
'rule', 'rules',
'culture', 'cultures',
'artifact', 'artifacts',
'species',
];
const STATUSES = ['established', 'proposed', 'deprecated', 'contradicted', 'speculative'];
interface EntryOptions {
bible: string;
category: string;
name: string;
status: string;
contributor: string;
}
function getDate(): string {
return new Date().toISOString().split('T')[0];
}
function slugify(name: string): string {
return name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
}
function normalizeCategory(category: string): string {
const singular = category.endsWith('s') ? category.slice(0, -1) : category;
const plural = singular + 's';
// Special case for species
if (singular === 'specie') return 'species';
return plural;
}
function getStatusSymbol(status: string): string {
switch (status.toLowerCase()) {
case 'established': return '✓';
case 'proposed': return '?';
case 'deprecated': return '✗';
case 'contradicted': return '⚠';
case 'speculative': return '~';
default: return '?';
}
}
function generateEntry(options: EntryOptions): string {
const date = getDate();
const statusCapitalized = options.status.charAt(0).toUpperCase() + options.status.slice(1);
const categoryCapitalized = options.category.charAt(0).toUpperCase() + options.category.slice(1);
return `# ${options.name}
**Canon Status:** ${statusCapitalized}
**Category:** ${categoryCapitalized}
**Created:** ${date}
**Last Updated:** ${date}
**Contributors:** ${options.contributor}
## Summary
[1-2 sentence overview for quick reference]
## Description
[Detailed information about this entry]
## Relationships
- **Related To:** [[Related Entry]]
<!-- Add more relationships as appropriate:
- **Located In:** [[Location]]
- **Member Of:** [[Faction]]
- **Contains:** [[Sub-entry]]
- **Preceded By:** [[Earlier Entry]]
- **See Also:** [[Related Entry]]
-->
## Key Facts
- [Key fact 1]
- [Key fact 2]
- [Key fact 3]
## Notes for Writers
[Guidance for using this element in stories. What should writers know? What's flexible vs. fixed?]
## Sources
- [Source work/document] (what was established)
## History
- ${date}: Created by ${options.contributor}
`;
}
function generateChangelogEntry(options: EntryOptions): string {
const date = getDate();
return `- **Created**: New ${options.category} entry "${options.name}" (${options.contributor})`;
}
async function addEntry(options: EntryOptions) {
const category = normalizeCategory(options.category);
const slug = slugify(options.name);
const entryPath = `${options.bible}/${category}/${slug}.md`;
const changelogPath = `${options.bible}/meta/changelog.md`;
const indexPath = `${options.bible}/${category}/_index.md`;
// Check if entry already exists
try {
await Deno.stat(entryPath);
console.error(`Error: Entry already exists at ${entryPath}`);
Deno.exit(1);
} catch {
// File doesn't exist, which is what we want
}
// Create the entry
const entryContent = generateEntry(options);
await Deno.writeTextFile(entryPath, entryContent);
console.log(`Created: ${entryPath}`);
// Update changelog
try {
let changelog = await Deno.readTextFile(changelogPath);
const date = getDate();
const changelogEntry = generateChangelogEntry(options);
// Find today's date section or create it
if (changelog.includes(`## ${date}`)) {
// Add under existing date
changelog = changelog.replace(
`## ${date}\n`,
`## ${date}\n\n${changelogEntry}\n`
);
} else {
// Add new date section after the header
const headerEnd = changelog.indexOf('\n## ');
if (headerEnd > -1) {
changelog = changelog.slice(0, headerEnd) +
`\n## ${date}\n\n${changelogEntry}\n` +
changelog.slice(headerEnd);
}
}
await Deno.writeTextFile(changelogPath, changelog);
console.log(`Updated: ${changelogPath}`);
} catch (e) {
console.warn(`Warning: Could not update changelog: ${e}`);
}
// Update index
try {
let index = await Deno.readTextFile(indexPath);
const statusSymbol = getStatusSymbol(options.status);
const newRow = `| [[${options.name}]] | ${statusSymbol} | [Add summary] |`;
// Replace "no entries" row or add to table
if (index.includes('*No entries yet*')) {
index = index.replace('| *No entries yet* | | |', newRow);
} else {
// Add before the last empty line of the table
const tableEnd = index.lastIndexOf('\n\n## Adding');
if (tableEnd > -1) {
index = index.slice(0, tableEnd) + '\n' + newRow + index.slice(tableEnd);
}
}
await Deno.writeTextFile(indexPath, index);
console.log(`Updated: ${indexPath}`);
} catch (e) {
console.warn(`Warning: Could not update index: ${e}`);
}
console.log(`
Entry created successfully!
Next steps:
1. Edit ${entryPath} to fill in details
2. Add wiki-links to related entries
3. Update the summary in ${indexPath}
`);
}
function parseArgs(args: string[]): EntryOptions | null {
const options: Partial<EntryOptions> = {
bible: './world-bible',
status: 'proposed',
contributor: 'Unknown',
};
for (let i = 0; i < args.length; i++) {
switch (args[i]) {
case '--bible':
case '-b':
options.bible = args[++i];
break;
case '--category':
case '-c':
options.category = args[++i];
break;
case '--name':
case '-n':
options.name = args[++i];
break;
case '--status':
case '-s':
options.status = args[++i];
break;
case '--contributor':
case '--author':
case '-a':
options.contributor = args[++i];
break;
}
}
if (!options.category || !options.name) {
return null;
}
if (!CATEGORIES.includes(options.category.toLowerCase())) {
console.error(`Invalid category: ${options.category}`);
console.error(`Valid categories: ${CATEGORIES.filter(c => !c.endsWith('s')).join(', ')}`);
return null;
}
if (!STATUSES.includes(options.status!.toLowerCase())) {
console.error(`Invalid status: ${options.status}`);
console.error(`Valid statuses: ${STATUSES.join(', ')}`);
return null;
}
return options as EntryOptions;
}
function showUsage() {
console.log(`
Add Entry to World Bible
========================
Creates a new entry from template.
Usage:
deno run --allow-read --allow-write add-entry.ts [options]
Options:
--bible, -b Path to world bible (default: ./world-bible)
--category, -c Entry category (required)
--name, -n Entry name (required)
--status, -s Canon status (default: proposed)
--contributor, -a Contributor name (default: Unknown)
Categories:
character, location, faction, event, rule, culture, artifact, species
Statuses:
established, proposed, deprecated, contradicted, speculative
Example:
deno run --allow-read --allow-write add-entry.ts \\
--bible ./my-world \\
--category character \\
--name "Elena Blackwood" \\
--status proposed \\
--contributor "jsmith"
`);
}
async function main() {
const args = Deno.args;
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
showUsage();
Deno.exit(0);
}
const options = parseArgs(args);
if (!options) {
showUsage();
Deno.exit(1);
}
try {
await addEntry(options);
} catch (e) {
console.error('Error adding entry:', e);
Deno.exit(1);
}
}
main();
#!/usr/bin/env -S deno run --allow-read --allow-write
/**
* build-index.ts - Rebuild index files from entries
*
* Scans all entries in a category and regenerates the _index.md file.
*
* Usage:
* deno run --allow-read --allow-write build-index.ts ./world-bible
* deno run --allow-read --allow-write build-index.ts ./world-bible --category characters
*/
import { walk } from "https://deno.land/std@0.208.0/fs/walk.ts";
interface EntryInfo {
name: string;
file: string;
status: string;
summary: string;
}
const CATEGORY_DESCRIPTIONS: Record<string, string> = {
characters: 'People and beings that inhabit this world.',
locations: 'Places in the world, from continents to individual buildings.',
factions: 'Organizations, governments, groups, and alliances.',
rules: 'How the world works - magic systems, technology, physics.',
culture: 'Beliefs, customs, languages, and traditions.',
artifacts: 'Significant objects, weapons, and items of power.',
species: 'Non-human beings, creatures, and races.',
};
function getStatusSymbol(status: string): string {
const lower = status.toLowerCase();
if (lower.includes('established')) return '✓';
if (lower.includes('proposed')) return '?';
if (lower.includes('deprecated')) return '✗';
if (lower.includes('contradicted')) return '⚠';
if (lower.includes('speculative')) return '~';
return '?';
}
function getDate(): string {
return new Date().toISOString().split('T')[0];
}
async function parseEntry(path: string): Promise<EntryInfo | null> {
try {
const content = await Deno.readTextFile(path);
// Extract name from first heading
const nameMatch = content.match(/^#\s+(.+)$/m);
if (!nameMatch) return null;
const name = nameMatch[1].trim();
// Extract status
const statusMatch = content.match(/\*\*Canon Status:\*\*\s*(\w+)/);
const status = statusMatch ? statusMatch[1] : 'Proposed';
// Extract summary (first line after ## Summary)
const summaryMatch = content.match(/## Summary\s*\n+([^\n#]+)/);
let summary = summaryMatch ? summaryMatch[1].trim() : '';
// Clean up placeholder text
if (summary.startsWith('[') || summary === '') {
summary = '[Add summary]';
}
// Truncate long summaries
if (summary.length > 60) {
summary = summary.slice(0, 57) + '...';
}
return {
name,
file: path,
status,
summary,
};
} catch {
return null;
}
}
async function buildCategoryIndex(biblePath: string, category: string): Promise<number> {
const categoryPath = `${biblePath}/${category}`;
const indexPath = `${categoryPath}/_index.md`;
// Check if category directory exists
try {
await Deno.stat(categoryPath);
} catch {
return 0;
}
// Collect all entries
const entries: EntryInfo[] = [];
for await (const file of walk(categoryPath, {
maxDepth: 1,
exts: ['.md'],
})) {
if (file.isFile && !file.name.startsWith('_') && file.name !== 'overview.md') {
const entry = await parseEntry(file.path);
if (entry) {
entries.push(entry);
}
}
}
// Sort alphabetically
entries.sort((a, b) => a.name.localeCompare(b.name));
// Generate index content
const description = CATEGORY_DESCRIPTIONS[category] || `Entries in the ${category} category.`;
const singular = category.endsWith('s') ? category.slice(0, -1) : category;
let content = `# ${category.charAt(0).toUpperCase() + category.slice(1)}
${description}
## Entries
| Name | Status | Summary |
|------|--------|---------|
`;
if (entries.length === 0) {
content += `| *No entries yet* | | |\n`;
} else {
for (const entry of entries) {
const symbol = getStatusSymbol(entry.status);
content += `| [[${entry.name}]] | ${symbol} | ${entry.summary} |\n`;
}
}
content += `
## Adding New ${category.charAt(0).toUpperCase() + category.slice(1)}
1. Create file in this directory: \`${singular}-name.md\`
2. Use the entry template
3. Set category to "${category.charAt(0).toUpperCase() + category.slice(1)}"
4. Add relationships to existing entries
5. Update this index
6. Note in [changelog](../meta/changelog.md)
---
*Last updated: ${getDate()}*
*Entries: ${entries.length}*
`;
await Deno.writeTextFile(indexPath, content);
return entries.length;
}
async function buildAllIndexes(biblePath: string): Promise<void> {
const categories = Object.keys(CATEGORY_DESCRIPTIONS);
let totalEntries = 0;
console.log(`Building indexes for ${biblePath}...\n`);
for (const category of categories) {
const count = await buildCategoryIndex(biblePath, category);
console.log(` ${category}/_index.md: ${count} entries`);
totalEntries += count;
}
console.log(`\nTotal entries indexed: ${totalEntries}`);
}
function showUsage() {
console.log(`
Build World Bible Indexes
=========================
Regenerates _index.md files from entries.
Usage:
deno run --allow-read --allow-write build-index.ts <world-bible-path>
deno run --allow-read --allow-write build-index.ts <world-bible-path> --category <name>
Options:
--category, -c Only rebuild specific category index
Categories:
characters, locations, factions, rules, culture, artifacts, species
Example:
deno run --allow-read --allow-write build-index.ts ./world-bible
deno run --allow-read --allow-write build-index.ts ./world-bible -c characters
`);
}
async function main() {
const args = Deno.args;
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
showUsage();
Deno.exit(0);
}
const biblePath = args[0];
// Check if path exists
try {
await Deno.stat(biblePath);
} catch {
console.error(`Error: Path not found: ${biblePath}`);
Deno.exit(1);
}
// Check for specific category
const categoryIndex = args.indexOf('--category');
const categoryIndexShort = args.indexOf('-c');
const catIdx = categoryIndex > -1 ? categoryIndex : categoryIndexShort;
if (catIdx > -1 && args[catIdx + 1]) {
const category = args[catIdx + 1];
console.log(`Building index for ${category}...`);
const count = await buildCategoryIndex(biblePath, category);
console.log(`${category}/_index.md: ${count} entries`);
} else {
await buildAllIndexes(biblePath);
}
}
main();
#!/usr/bin/env -S deno run --allow-read
/**
* check-conflicts.ts - Scan world bible for potential conflicts
*
* Identifies:
* - Entries marked as contradicted
* - Broken wiki-links
* - Duplicate entry names
* - Entries without sources
*
* Usage:
* deno run --allow-read check-conflicts.ts ./world-bible
*/
import { walk } from "https://deno.land/std@0.208.0/fs/walk.ts";
interface Issue {
type: 'contradiction' | 'broken-link' | 'duplicate' | 'missing-source' | 'orphan';
file: string;
description: string;
severity: 'error' | 'warning' | 'info';
}
interface ScanResult {
files: number;
entries: Map<string, string[]>; // name -> files containing it
links: Set<string>;
issues: Issue[];
}
async function scanFile(path: string, result: ScanResult): Promise<void> {
const content = await Deno.readTextFile(path);
const lines = content.split('\n');
// Extract entry name from first heading
const nameMatch = content.match(/^#\s+(.+)$/m);
if (nameMatch) {
const name = nameMatch[1].trim();
if (!result.entries.has(name)) {
result.entries.set(name, []);
}
result.entries.get(name)!.push(path);
}
// Check for contradicted status
if (content.includes('**Canon Status:** Contradicted') ||
content.includes('Status:** ⚠')) {
result.issues.push({
type: 'contradiction',
file: path,
description: 'Entry is marked as contradicted - needs resolution',
severity: 'error',
});
}
// Extract wiki-links
const linkPattern = /\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g;
let match;
while ((match = linkPattern.exec(content)) !== null) {
result.links.add(match[1].trim());
}
// Check for missing sources
if (content.includes('## Sources') &&
(content.includes('[Source work/document]') ||
content.match(/## Sources\s*\n\s*\n/))) {
result.issues.push({
type: 'missing-source',
file: path,
description: 'Entry has no sources documented',
severity: 'warning',
});
}
// Check for unfilled template markers
if (content.includes('[1-2 sentence overview') ||
content.includes('[Detailed information about') ||
content.includes('[Key fact')) {
result.issues.push({
type: 'orphan',
file: path,
description: 'Entry has unfilled template sections',
severity: 'info',
});
}
result.files++;
}
async function scanWorldBible(biblePath: string): Promise<ScanResult> {
const result: ScanResult = {
files: 0,
entries: new Map(),
links: new Set(),
issues: [],
};
for await (const entry of walk(biblePath, {
exts: ['.md'],
skip: [/node_modules/, /\.git/],
})) {
if (entry.isFile && !entry.name.startsWith('_')) {
await scanFile(entry.path, result);
}
}
// Check for duplicates
for (const [name, files] of result.entries) {
if (files.length > 1) {
result.issues.push({
type: 'duplicate',
file: files.join(', '),
description: `Duplicate entry name "${name}" in multiple files`,
severity: 'error',
});
}
}
// Check for broken links
for (const link of result.links) {
// Skip section links
if (link.includes('#')) continue;
// Check if link target exists
if (!result.entries.has(link)) {
result.issues.push({
type: 'broken-link',
file: 'Multiple files',
description: `Broken link: [[${link}]] - no entry with this name`,
severity: 'warning',
});
}
}
return result;
}
function formatReport(result: ScanResult): string {
let report = `
WORLD BIBLE CONFLICT CHECK
==========================
Files scanned: ${result.files}
Unique entries: ${result.entries.size}
Wiki-links found: ${result.links.size}
`;
const errors = result.issues.filter(i => i.severity === 'error');
const warnings = result.issues.filter(i => i.severity === 'warning');
const infos = result.issues.filter(i => i.severity === 'info');
if (errors.length > 0) {
report += `ERRORS (${errors.length})\n${'='.repeat(40)}\n\n`;
for (const issue of errors) {
report += `[${issue.type.toUpperCase()}] ${issue.description}\n`;
report += ` File: ${issue.file}\n\n`;
}
}
if (warnings.length > 0) {
report += `WARNINGS (${warnings.length})\n${'='.repeat(40)}\n\n`;
for (const issue of warnings) {
report += `[${issue.type.toUpperCase()}] ${issue.description}\n`;
report += ` File: ${issue.file}\n\n`;
}
}
if (infos.length > 0) {
report += `INFO (${infos.length})\n${'='.repeat(40)}\n\n`;
for (const issue of infos) {
report += `[${issue.type.toUpperCase()}] ${issue.description}\n`;
report += ` File: ${issue.file}\n\n`;
}
}
if (result.issues.length === 0) {
report += `No issues found.\n`;
} else {
report += `
SUMMARY
=======
Errors: ${errors.length}
Warnings: ${warnings.length}
Info: ${infos.length}
Total: ${result.issues.length}
`;
}
return report;
}
function showUsage() {
console.log(`
World Bible Conflict Check
==========================
Scans for potential conflicts and issues.
Usage:
deno run --allow-read check-conflicts.ts <world-bible-path>
Checks for:
- Entries marked as contradicted
- Broken wiki-links ([[Name]] with no matching entry)
- Duplicate entry names
- Missing source documentation
- Unfilled template sections
Example:
deno run --allow-read check-conflicts.ts ./world-bible
`);
}
async function main() {
const args = Deno.args;
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
showUsage();
Deno.exit(0);
}
const biblePath = args[0];
try {
await Deno.stat(biblePath);
} catch {
console.error(`Error: Path not found: ${biblePath}`);
Deno.exit(1);
}
const result = await scanWorldBible(biblePath);
console.log(formatReport(result));
// Exit with error code if errors found
const errorCount = result.issues.filter(i => i.severity === 'error').length;
if (errorCount > 0) {
Deno.exit(1);
}
}
main();
#!/usr/bin/env -S deno run --allow-read --allow-write
/**
* init-world.ts - Initialize a new world bible structure
*
* Creates the full directory structure with template files
* for a wiki-style world bible.
*
* Usage:
* deno run --allow-read --allow-write init-world.ts "World Name" [output-dir]
*
* Example:
* deno run --allow-read --allow-write init-world.ts "The Shattered Realms"
* deno run --allow-read --allow-write init-world.ts "My World" ./worlds/my-world
*/
const DIRECTORIES = [
'characters',
'locations',
'history',
'history/eras',
'history/events',
'factions',
'rules',
'culture',
'artifacts',
'species',
'meta',
];
function getDate(): string {
return new Date().toISOString().split('T')[0];
}
function slugify(name: string): string {
return name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
}
function generateDiscovery(worldName: string): string {
return `# ${worldName} World Bible
Welcome to the canonical reference for ${worldName}. This world bible contains all established facts, proposed additions, and organizational structure for our shared world.
## Quick Start
1. **New here?** Start with [Style Guide](meta/style-guide.md) for conventions
2. **Looking for something?** Check the category indexes below
3. **Adding content?** Use [Add Entry](#adding-entries) workflow
4. **Found a conflict?** Report in [Conflicts](meta/conflicts.md)
## Canon Status Guide
| Symbol | Status | Meaning |
|--------|--------|---------|
| ✓ | Established | Confirmed canon - treat as fact |
| ? | Proposed | Suggested - available but may change |
| ✗ | Deprecated | Superseded - don't use in new work |
| ⚠ | Contradicted | Conflicts exist - needs resolution |
| ~ | Speculative | Extrapolated - use cautiously |
See [Canon Status](canon-status.md) for current overview.
## Categories
### [Characters](characters/_index.md)
People and beings in the world.
### [Locations](locations/_index.md)
Places, from continents to rooms.
### [History](history/timeline.md)
Timeline, eras, and significant events.
### [Factions](factions/_index.md)
Organizations, governments, and groups.
### [Rules](rules/_index.md)
How the world works - magic, technology, physics.
### [Culture](culture/_index.md)
Beliefs, customs, languages, traditions.
### [Artifacts](artifacts/_index.md)
Significant objects.
### [Species](species/_index.md)
Non-human beings and creatures.
## Adding Entries
1. Create entry using appropriate template
2. Set status to **Proposed**
3. Add relationships (wiki-links)
4. Update relevant index
5. Note in [Changelog](meta/changelog.md)
Proposed entries become Established after review by canon authority.
## Recent Changes
See [Changelog](meta/changelog.md) for recent updates.
## Conflicts
See [Conflicts](meta/conflicts.md) for unresolved contradictions.
## Contributors
See [Contributors](meta/contributors.md) for who maintains what.
---
*Created: ${getDate()}*
`;
}
function generateCanonStatus(worldName: string): string {
return `# ${worldName} Canon Status
Overview of canonical state across all categories.
## Status Summary
| Category | Established | Proposed | Deprecated | Contradicted |
|----------|-------------|----------|------------|--------------|
| Characters | 0 | 0 | 0 | 0 |
| Locations | 0 | 0 | 0 | 0 |
| History | 0 | 0 | 0 | 0 |
| Factions | 0 | 0 | 0 | 0 |
| Rules | 0 | 0 | 0 | 0 |
| Culture | 0 | 0 | 0 | 0 |
| Artifacts | 0 | 0 | 0 | 0 |
| Species | 0 | 0 | 0 | 0 |
## Recent Status Changes
*No changes yet.*
## Pending Review
Proposed entries awaiting establishment:
*None yet.*
---
*Last updated: ${getDate()}*
`;
}
function generateIndex(category: string, description: string): string {
const singular = category.endsWith('s') ? category.slice(0, -1) : category;
return `# ${category.charAt(0).toUpperCase() + category.slice(1)}
${description}
## Entries
| Name | Status | Summary |
|------|--------|---------|
| *No entries yet* | | |
## Adding New ${category.charAt(0).toUpperCase() + category.slice(1)}
1. Create file in this directory: \`${singular}-name.md\`
2. Use the entry template
3. Set category to "${category.charAt(0).toUpperCase() + category.slice(1)}"
4. Add relationships to existing entries
5. Update this index
6. Note in [changelog](../meta/changelog.md)
---
*Last updated: ${getDate()}*
`;
}
function generateTimeline(): string {
return `# Timeline
Chronological overview of ${getDate()}'s history.
## Eras
| Era | Period | Description |
|-----|--------|-------------|
| *Define eras as needed* | | |
## Major Events
See [events/](events/) for detailed event entries.
## Adding to Timeline
1. Create event entry in \`events/\` directory
2. Add to appropriate era section above
3. Update [changelog](../meta/changelog.md)
---
*Last updated: ${getDate()}*
`;
}
function generateStyleGuide(worldName: string): string {
return `# ${worldName} Style Guide
Guidelines for contributing to this shared world.
## Naming Conventions
### Characters
- [Describe naming patterns, cultural influences]
- [Examples of good names]
### Places
- [Describe place naming conventions]
- [Linguistic patterns]
### Organizations
- [How factions/groups are named]
## Tone and Voice
### World Tone
[Describe the overall feel - dark, hopeful, gritty, whimsical, etc.]
### What Fits
- [Elements that belong]
- [Themes that work]
### What Doesn't Fit
- [Elements to avoid]
- [Tone mismatches]
## Content Boundaries
### Acceptable Content
- [What can be depicted]
- [How to handle sensitive topics]
### Requires Care
- [Topics needing sensitivity]
- [How to approach them]
### Off-Limits
- [Topics not allowed]
- [Hard boundaries]
## Formatting Standards
### Dates
- In-world calendar: [describe]
- Out-of-world: YYYY-MM-DD
### Measurements
- [Units used in-world]
- [Conversion notes if helpful]
### Capitalization
- [What gets capitalized]
- [Title conventions]
## Common Terms
| Term | Meaning | Usage |
|------|---------|-------|
| [Term] | [Definition] | [How to use] |
## Canon Authority
Primary canon authority: [Name/Role]
Decisions logged in: [conflicts.md](conflicts.md)
---
*Established: ${getDate()}*
`;
}
function generateChangelog(worldName: string): string {
return `# ${worldName} Changelog
Recent changes to the world bible.
## ${getDate()}
- **Created**: World bible initialized
---
## Adding to Changelog
When you make changes:
1. Add entry under today's date (or create new date header)
2. Use format: \`- **Action**: Description (contributor)\`
3. Actions: Created, Updated, Deprecated, Established, Resolved
Example:
\`\`\`
- **Created**: New character entry for Elena (jsmith)
- **Updated**: Expanded magic system rules (kdoe)
- **Established**: Proposed faction "The Order" now canon (admin)
\`\`\`
`;
}
function generateConflicts(): string {
return `# Canon Conflicts
Unresolved contradictions requiring attention.
## Active Conflicts
*No conflicts currently.*
## Resolved Conflicts
*No resolutions yet.*
---
## Reporting Conflicts
When you find contradicting information:
1. Add to Active Conflicts section below
2. Include:
- Both entries involved (with links)
- Nature of contradiction
- Source references
- Date discovered
### Template:
\`\`\`
### [Brief Description]
**Discovered:** [Date]
**Entries:** [[Entry 1]] vs [[Entry 2]]
**Conflict:** [Description of contradiction]
**Sources:**
- Entry 1: [source]
- Entry 2: [source]
**Status:** Awaiting resolution
\`\`\`
## Resolving Conflicts
Canon authority resolves by:
1. Determining which source has priority
2. Either reconciling both or deprecating one
3. Moving to Resolved section with decision documented
`;
}
function generateContributors(): string {
return `# Contributors
Who maintains what in this world bible.
## Canon Authority
- **Primary:** [Name] - final decisions on canon status
## Active Contributors
| Name | Areas | Since |
|------|-------|-------|
| [Name] | [Categories/areas] | ${getDate()} |
## Contribution History
See [changelog](changelog.md) for detailed contribution history.
---
## Becoming a Contributor
1. Read the [Style Guide](style-guide.md)
2. Familiarize yourself with existing canon
3. Start with Proposed entries in your area of interest
4. Contact canon authority for questions
`;
}
const INDEX_DESCRIPTIONS: Record<string, string> = {
characters: 'People and beings that inhabit this world.',
locations: 'Places in the world, from continents to individual buildings.',
factions: 'Organizations, governments, groups, and alliances.',
rules: 'How the world works - magic systems, technology, physics.',
culture: 'Beliefs, customs, languages, and traditions.',
artifacts: 'Significant objects, weapons, and items of power.',
species: 'Non-human beings, creatures, and races.',
};
async function initWorld(worldName: string, outputDir: string) {
console.log(`Initializing world bible for "${worldName}"...`);
console.log(`Output directory: ${outputDir}`);
// Create directories
await Deno.mkdir(outputDir, { recursive: true });
for (const dir of DIRECTORIES) {
await Deno.mkdir(`${outputDir}/${dir}`, { recursive: true });
console.log(` Created: ${dir}/`);
}
// Create main files
await Deno.writeTextFile(`${outputDir}/discovery.md`, generateDiscovery(worldName));
console.log(' Created: discovery.md');
await Deno.writeTextFile(`${outputDir}/canon-status.md`, generateCanonStatus(worldName));
console.log(' Created: canon-status.md');
// Create index files
for (const [category, description] of Object.entries(INDEX_DESCRIPTIONS)) {
await Deno.writeTextFile(
`${outputDir}/${category}/_index.md`,
generateIndex(category, description)
);
console.log(` Created: ${category}/_index.md`);
}
// Create history timeline
await Deno.writeTextFile(`${outputDir}/history/timeline.md`, generateTimeline());
console.log(' Created: history/timeline.md');
// Create meta files
await Deno.writeTextFile(`${outputDir}/meta/style-guide.md`, generateStyleGuide(worldName));
console.log(' Created: meta/style-guide.md');
await Deno.writeTextFile(`${outputDir}/meta/changelog.md`, generateChangelog(worldName));
console.log(' Created: meta/changelog.md');
await Deno.writeTextFile(`${outputDir}/meta/conflicts.md`, generateConflicts());
console.log(' Created: meta/conflicts.md');
await Deno.writeTextFile(`${outputDir}/meta/contributors.md`, generateContributors());
console.log(' Created: meta/contributors.md');
console.log(`
World bible initialized!
Next steps:
1. Edit meta/style-guide.md with your world's conventions
2. Add yourself to meta/contributors.md
3. Start adding entries to populate the bible
4. Use discovery.md as your navigation hub
`);
}
function showUsage() {
console.log(`
Initialize World Bible
======================
Creates a complete world bible directory structure.
Usage:
deno run --allow-read --allow-write init-world.ts "World Name" [output-dir]
Arguments:
World Name Name of your world (required)
output-dir Where to create the bible (default: ./world-bible)
Examples:
deno run --allow-read --allow-write init-world.ts "The Shattered Realms"
deno run --allow-read --allow-write init-world.ts "My World" ./worlds/my-world
`);
}
async function main() {
const args = Deno.args;
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
showUsage();
Deno.exit(0);
}
const worldName = args[0];
const outputDir = args[1] || `./world-bible`;
try {
await initWorld(worldName, outputDir);
} catch (e) {
console.error('Error initializing world bible:', e);
Deno.exit(1);
}
}
main();
{{WORLD_NAME}} World Bible
Welcome to the canonical reference for {{WORLD_NAME}}. This world bible contains all established facts, proposed additions, and organizational structure for our shared world.
Quick Start
1. New here? Start with Style Guide for conventions 2. Looking for something? Check the category indexes below 3. Adding content? Use Add Entry workflow 4. Found a conflict? Report in Conflicts
Canon Status Guide
| Symbol | Status | Meaning |
|---|---|---|
| ✓ | Established | Confirmed canon - treat as fact |
| ? | Proposed | Suggested - available but may change |
| ✗ | Deprecated | Superseded - don't use in new work |
| ⚠ | Contradicted | Conflicts exist - needs resolution |
| ~ | Speculative | Extrapolated - use cautiously |
See Canon Status for current overview.
Categories
Characters
People and beings in the world.
Locations
Places, from continents to rooms.
History
Timeline, eras, and significant events.
Factions
Organizations, governments, and groups.
Rules
How the world works - magic, technology, physics.
Culture
Beliefs, customs, languages, traditions.
Artifacts
Significant objects.
Species
Non-human beings and creatures.
Adding Entries
1. Create entry using appropriate template 2. Set status to Proposed 3. Add relationships (wiki-links) 4. Update relevant index 5. Note in Changelog
Proposed entries become Established after review by canon authority.
Recent Changes
See Changelog for recent updates.
Conflicts
See Conflicts for unresolved contradictions.
Contributors
See Contributors for who maintains what.
---
Last rebuilt: {{DATE}}
{{NAME}}
Canon Status: {{STATUS}} Category: {{CATEGORY}} Created: {{DATE}} Last Updated: {{DATE}} Contributors: {{CONTRIBUTOR}}
Summary
[1-2 sentence overview for quick reference]
Description
[Detailed information about this entry]
Relationships
- Related To: [[Related Entry]]
<!-- Add more relationships as appropriate:
- Located In: [[Location]]
- Member Of: [[Faction]]
- Contains: [[Sub-entry]]
- Preceded By: [[Earlier Entry]]
- See Also: [[Related Entry]]
-->
Key Facts
- Fact 1
- Fact 2
- Fact 3
Notes for Writers
[Guidance for using this element in stories. What should writers know? What's flexible vs. fixed?]
Sources
- [Source work/document] (what was established)
History
- {{DATE}}: Created by {{CONTRIBUTOR}}
{{CATEGORY}}
{{DESCRIPTION}}
Entries
<!-- Entries are listed automatically. Each entry should link to its file. -->
| Name | Status | Summary |
|---|---|---|
| [[Entry Name]] | ✓ | Brief description |
Adding New {{CATEGORY}}
1. Create file in this directory: entry-name.md 2. Use the entry template 3. Set category to "{{CATEGORY}}" 4. Add relationships to existing entries 5. Update this index 6. Note in changelog
Related
- Related Category
---
Last updated: {{DATE}}
{{WORLD_NAME}} Style Guide
Guidelines for contributing to this shared world.
Naming Conventions
Characters
- [Describe naming patterns, cultural influences]
- [Examples of good names]
Places
- [Describe place naming conventions]
- [Linguistic patterns]
Organizations
- [How factions/groups are named]
Tone and Voice
World Tone
[Describe the overall feel - dark, hopeful, gritty, whimsical, etc.]
What Fits
- [Elements that belong]
- [Themes that work]
What Doesn't Fit
- [Elements to avoid]
- [Tone mismatches]
Content Boundaries
Acceptable Content
- [What can be depicted]
- [How to handle sensitive topics]
Requires Care
- [Topics needing sensitivity]
- [How to approach them]
Off-Limits
- [Topics not allowed]
- [Hard boundaries]
Formatting Standards
Dates
- In-world calendar: [describe]
- Out-of-world: YYYY-MM-DD
Measurements
- [Units used in-world]
- [Conversion notes if helpful]
Capitalization
- [What gets capitalized]
- [Title conventions]
Common Terms
| Term | Meaning | Usage |
|---|---|---|
| [Term] | [Definition] | [How to use] |
Canon Authority
Primary canon authority: [Name/Role]
Decisions logged in: conflicts.md
---
Established: {{DATE}} Last updated: {{DATE}}
Related skills
How it compares
Pick shared-world when you need persistent canon files and conflict scanning for multi-writer universes, not a one-shot story outline generator.
FAQ
What does shared-world manage?
shared-world manages wiki-style world bibles for collaborative fiction. It organizes characters, locations, history, and systems with canon status, cross-references, contributor metadata, and changelog history so multiple writers or agents stay aligned.
How does shared-world track canon changes?
shared-world assigns every entry one of five canon statuses—Established, Proposed, Deprecated, Contradicted, or Speculative—and records sources, relationships, and changelog notes. Automation can rebuild indexes and flag contradictions before new branches ship.