Package Exports
- plotos
- plotos/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (plotos) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
PlotOS
A local-first CLI tool for story creation and management.
PlotOS helps writers create structured narratives with world-building, character management, conflict graphs, and plot generation.
Features
- Plain Text, Local-first - All data stored as JSON, works offline
- BYO API - Bring your own LLM API key (OpenAI, OpenRouter, DeepSeek, etc.)
- Static Output - Generate shareable HTML plot pages
- Four Core Schemas - World, Character, Conflict Graph, Plot
- Narrative Engine - Generate plots from structured data
- State Machine - Track project status from draft to published
Installation
# Install globally from npm
npm install -g plotos
# Or use with npx (no install required)
npx plotos init my-storyFrom Source
# Clone or download
git clone https://github.com/plotos/plotos.git
cd plotos
# Install dependencies
npm install
# Build
npm run build
# Link for global use
npm linkQuick Start
# Create a new project
plot init my-story
cd my-story
# Fill in world settings
# Edit memory/canon/world.json
# Add characters
# Edit memory/canon/characters.json
# Define conflicts
# Edit memory/canon/conflict_graph.json
# Check project health
plot doctor
# Validate data
plot validate
# Generate plot
plot build
# Export to HTML
plot export
# Publish to GitHub Pages
plot publishCommands
plot init [name]
Initialize a new PlotOS project.
plot init my-story
plot init my-story --force # Overwrite existingCreates:
my-story/
├── plotos.json # Project configuration
├── state.json # Project state
├── memory/canon/ # Canon (locked) settings
│ ├── world.json # World settings
│ ├── characters.json # Characters
│ ├── conflict_graph.json # Conflict graph
│ └── style_card.json # Style guide
├── workspace/ # Working directory
│ ├── drafts/
│ ├── experiments/
│ ├── notes/
│ └── plot_variants/ # Plot versions
└── dist/ # Output filesplot doctor
Diagnose project structure and configuration.
plot doctor
plot doctor --fix # Auto-fix issuesplot validate
Validate project data against schemas.
plot validate
plot validate --strict # Treat warnings as errorsplot build [version]
Generate plot from canon data.
plot build # Generate new version
plot build v002 # Specific version
plot build --model five_act # Story structure model
plot build --scenes 30 # Target scene count
plot build --no-llm # Generate without LLM
plot build --force # Overwrite existingplot lock / plot unlock
Lock or unlock canon settings.
plot lock # Freeze canon
plot lock --reason "Ready for publication"
plot unlock # Allow editingplot export [version]
Export plot to HTML.
plot export # Export current version
plot export v002 # Export specific version
plot export --all # Export all versions
plot export --runtime # Generate runtime.jsonplot publish
Publish to GitHub Pages.
plot publish
plot publish --dry-run # Preview without publishingplot preview
Preview exported plot locally.
plot preview
plot preview --port 8080Project Structure
Canon Layer (memory/canon/)
Authoritative settings that should not be changed after locking.
- world.json - World rules, systems, stakes, setting
- characters.json - Character desires, fears, beliefs, arcs
- conflict_graph.json - Conflict nodes, edges, sets
- style_card.json - Narrative voice, prose style
Workspace Layer (workspace/)
Draft area for experimentation.
- drafts/ - Draft content
- experiments/ - Experimental variations
- notes/ - Research and notes
- plot_variants/ - Plot versions (plot_v001.json, etc.)
Publish Layer (dist/)
Generated output for sharing.
- index.html - Version index
- plot_v001.html - Plot page
- runtime.json - Interactive mode config
Configuration (plotos.json)
{
"name": "my-story",
"version": "0.1.0",
"provider": "openrouter",
"model": "deepseek-chat",
"api_key_env": "PLOTOS_API_KEY",
"base_url": "https://openrouter.ai/api/v1",
"language": "zh-CN",
"template": "default",
"generation": {
"temperature": 0.7,
"max_tokens": 4096
}
}State Machine
Init ──→ Draft ──→ Canon ──→ Published ──→ Interactive
│ │ │ │ │
└────────┴─────────┴───────────┴─────────────┘
(can iterate back)| State | Description |
|---|---|
| Init | Project created, no content yet |
| Draft | World/characters/conflict in progress |
| Canon | Settings locked, ready for generation |
| Published | HTML exported and published |
| Interactive | Runtime mode with user interaction |
Schema Overview
World Schema
{
"schema_version": "1.0",
"world_id": "w_xxx",
"title": "Story Title",
"genre": ["fantasy", "adventure"],
"premise": {
"logline": "One-line story summary",
"theme": "Core theme"
},
"axioms": [...], // World rules
"systems": [...], // Power/magic systems
"stakes": {...}, // What can be lost
"setting": {...} // Time, place, factions
}Character Schema
{
"schema_version": "1.0",
"characters": [{
"character_id": "c_xxx",
"name": "Character Name",
"role": "protagonist",
"core": {
"desire": "What they want",
"fear": "What they fear",
"belief": "Core belief"
},
"arc": {...},
"relationships": [...]
}]
}Conflict Graph Schema
{
"schema_version": "1.0",
"graph_id": "g_xxx",
"nodes": [
{ "id": "c_hero", "type": "character" },
{ "id": "goal_truth", "type": "goal" }
],
"edges": [
{ "type": "wants", "from": "c_hero", "to": "goal_truth" },
{ "type": "blocks", "from": "c_villain", "to": "c_hero" }
],
"conflict_sets": [...]
}Plot Schema
{
"schema_version": "1.0",
"plot_id": "p_xxx",
"structure": {
"model": "three_act",
"beats": [...]
},
"promises": {
"reader_promise": [...]
},
"scenes": [{
"scene_id": "s_001",
"act": 1,
"goal": "Scene goal",
"turn": "Turning point",
"outcome": "Result"
}],
"chapter_map": [...]
}LLM Integration
PlotOS supports any OpenAI-compatible API:
# Set API key
export PLOTOS_API_KEY=your-api-key
# Configure provider in plotos.json
{
"provider": "openrouter",
"model": "deepseek-chat",
"base_url": "https://openrouter.ai/api/v1"
}Supported providers:
- OpenAI
- OpenRouter
- DeepSeek
- Anthropic (via OpenRouter)
- Local models (Ollama, vLLM)
Development
# Development
npm run dev -- init test-story
# Build
npm run build
# Type check
npm run typecheckLicense
MIT
Contributing
Contributions welcome! Please read the documentation in /docs for architecture details.