nap — Narrative Addressing Protocol
NAP is a protocol that makes narrative resources addressable, resolvable, and interoperable across tools, storage systems, formats, and AI workflows.
Characters, locations, scenes, props, and entire fictional repositories — NAP gives each one a stable URI, a human-and-machine-readable manifest, a content-addressed history, and a resolver that connects them all.
In the same way that IPFS content-addressed files and OCI container-addressed images, NAP is narrative-addressed — a universal namespace for the building blocks of stories.
Why NAP?
Today, narrative assets live in silos:
- Worldbuilding docs in Notion or Google Docs
- Character sheets in spreadsheets
- Concept art in Dropbox or S3
- Scene breakdowns in Final Draft or Fade In
- AI prompts scattered across chat logs
- 3D assets on Sketchfab or Polycam
None of these tools talk to each other. NAP unifies them under a single addressing and resolution layer.
nap://starwars/character/lukeskywalker
nap://starwars/location/tatooine
nap://starwars/scene/cantina
nap://toystory/prop/andy-hat
Core Primitives
NAP is built on four primitives:
1. URI — Identity
A nap:// URI identifies any narrative resource. Version and branch are orthogonal selectors passed alongside the URI — never encoded in the path (mirrors Git, OCI, and package managers).
nap://starwars/character/lukeskywalker#references.appears_in
────┬── ───┬──── ────┬──── ──────┬────── ─────────────┬───────────
scheme repository entity_type entity_id fragment (query)
2. Manifest — Current State
A YAML manifest is the durable representation of a narrative resource. It is simultaneously:
- Human-editable — readable by worldbuilders
- Machine-editable — structured, schema-validated
- Agent-readable — subtree-queryable for AI workflows
- Portable — no runtime dependency, just a file
- Signable — hash the content, sign the hash (Ed25519 in v0+)
- Versionable — the manifest is what gets committed
id: "nap://starwars/character/lukeskywalker"
name: "Luke Skywalker"
entity_type: character
version: 17
properties:
homeworld: "nap://starwars/location/tatooine"
species: human
representations:
reference_image:
hash: "sha256:e3b0c44..."
format: png
provenance:
model: "midjourney-v6"
prompt_hash: "sha256:abc123..."
head: "a72c9f3b..."
3. Commit — History
Commits are content-addressed (BLAKE3) snapshots with patch metadata. The manifest stores only head — a pointer to the latest commit. Full history lives in the VCS, keeping manifests bounded.
4. Resolver — URI → Manifest
The resolver turns a nap:// URI into a manifest (or a subtree of one). With optional selectors for branch or commit hash, it supports versioned resolution and fragment-based queries for efficient data access.
Scene Clips as Representations
Scenes can own generated video clips the same way characters own reference images. A generated clip is not usually a representation of one character; it is a representation of a scene, with references back to the characters, locations, props, and style guides that shaped it.
nap create scene cantina -u starwars -n "Cantina"
nap add nap://starwars/scene/cantina clip-01 ./cantina-clip-01.mp4 --format mp4 -m "Add cantina scene clip"
The scene manifest remains simple and durable:
id: "nap://starwars/scene/cantina"
name: "Cantina"
entity_type: scene
version: 3
properties:
summary: "Luke and Obi-Wan enter a crowded cantina while searching for passage off Tatooine."
time_of_day: night
mood: tense
references:
characters:
- "nap://starwars/character/lukeskywalker"
- "nap://starwars/character/obiwankenobi"
location: "nap://starwars/location/mos-eisley-cantina"
representations:
clip-01:
hash: "blake3:af1349b9..."
format: mp4
uri: "clip-01.mp4"
head: "a72c9f3b..."
When resolved with provenance, NAP returns versioned per-file provenance for the manifest and each direct representation. This keeps generation metadata attached to the committed files without requiring users to manage the underlying VCS directly.
nap resolve nap://starwars/scene/cantina --provenance
manifest:
id: "nap://starwars/scene/cantina"
name: "Cantina"
entity_type: scene
version: 3
representations:
clip-01:
hash: "blake3:af1349b9..."
format: mp4
uri: "clip-01.mp4"
provenance:
revision: "a72c9f3b..."
files:
- role: manifest
path: "scene/cantina.yaml"
provenance:
nap.provenance.kind: edit
nap.provenance.author: worldbuilder
- role: representation
name: clip-01
path: "scene/clip-01.mp4"
uri: "clip-01.mp4"
hash: "blake3:af1349b9..."
format: mp4
provenance:
nap.provenance.kind: generation
nap.provenance.model: video-generator
nap.provenance.prompt.address: "blake3:b4d2..."
Entity Types
| Type | Example URI | Description |
|---|---|---|
character |
nap://starwars/character/lukeskywalker |
Persistent character with identity across scenes/episodes |
location |
nap://starwars/location/tatooine |
Spatial location within a fictional repository |
scene |
nap://starwars/scene/cantina |
Narrative scene — participants, timeline, events |
prop |
nap://toystory/prop/andy-hat |
Physical object with materials, variants, ownership |
group |
nap://toystory/group/buzz-and-woody-flying |
Mixed-media groups |
world |
nap://starwars/world/starwars |
The repository itself — rules, canon, top-level metadata |
Repository Layout
Each repository is a Git repository on disk:
starwars/ ← repository root (Git repo)
├── .nap/
│ └── config.yaml ← repository configuration
├── repository.yaml ← world manifest
├── characters/
│ ├── lukeskywalker.yaml
│ └── darthvader.yaml
├── locations/
│ └── tatooine.yaml
├── scenes/
│ └── cantina.yaml
└── props/
Installation
Installation Script
curl -fsSL https://github.com/portalshq/narrativeengine/releases/latest/download/install.sh | bash
The installation script installs both native binaries: nap and nap-mcp-server. The MCP server is dormant by default; agent clients start it on demand over stdio so sandboxed agents can use NAP through host-side CLI proxy calls.
Skills Install
Install these skills to use NAP with agent workflows, including entity-aware prompts, generation templates, and the resolve/update steps that keep character and scene output consistent.
npx skills add portalshq/narrativeengine
CLI & Server (Rust — compile from source)
git clone https://github.com/cinematiccanvas/nap.git
cd nap
cargo build --release
# Binaries land in target/release/
# nap — CLI tool
# nap-server — HTTP resolver server
Python SDK (prebuilt wheel, no Rust needed)
pip install narrativeengine
from narrativeengine import create_block, generate_candidate, render_lore_summary
block = create_block("char-1", "A brave adventurer")
candidate = generate_candidate(block)
TypeScript SDK (prebuilt binary, no Rust needed)
npm install @portalshq/narrativeengine
import { createBlock } from "@portalshq/narrativeengine";
const block = createBlock("char-1", "A brave adventurer");
Quick Start
# Initialize a repository (prompts for provider on first run)
nap init starwars
# Initialize with local provider
nap init starwars --provider local
# Configure provider only (no repository)
nap init --provider local
# Initialize with remote provider
nap init --provider remote --remote-url lore://localhost:41337 --workspace-id my-workspace
# Initialize with Portals Cloud
nap init --provider portals-cloud
# Check system status
nap status
# Run diagnostics
nap doctor
# Run diagnostics with auto-repair
nap doctor --repair
Create a Repository
# Initialize a new repository
nap init starwars
# See what you created
ls starwars/
# → .nap/ repository.yaml characters/ locations/ scenes/ props/
Create & Inspect Entities
# Create a character
nap create character lukeskywalker -u starwars -n "Luke Skywalker"
# Create a location
nap create location tatooine -u starwars -n "Tatooine"
# Set properties
nap set nap://starwars/character/lukeskywalker species human
nap set nap://starwars/character/lukeskywalker homeworld "nap://starwars/location/tatooine"
# Resolve a manifest
nap resolve nap://starwars/character/lukeskywalker
# Query a specific field
nap resolve nap://starwars/character/lukeskywalker#properties.species
# → human
# Query a subtree
nap query nap://starwars/character/lukeskywalker properties
Version Control
# View commit history
nap history nap://starwars/character/lukeskywalker
# Create branches
nap branch starwars canon
# Sync with remote
nap sync starwars
# Publish to remote
nap publish starwars
Output Formats
nap resolve nap://starwars/character/lukeskywalker -f json
nap resolve nap://starwars/character/lukeskywalker -f yaml
MCP Server
The NAP installer bundles the native nap-mcp-server binary alongside nap. The MCP server is not a daemon; agent clients start it on demand over stdio, and it proxies tool calls to the host nap CLI.
Connect with Codex
Codex stores MCP configuration in ~/.codex/config.toml alongside the rest of its config. The Codex CLI, the ChatGPT desktop app, and the IDE extension all share that MCP configuration, so you only need to register nap once.
Add the server with the CLI:
codex mcp add nap --env NAP_DIR="$HOME/.nap" -- /bin/sh -lc 'exec nap-mcp-server'
If nap-mcp-server is not on PATH, use the full installed path instead, usually ~/.local/bin/nap-mcp-server or /usr/local/bin/nap-mcp-server.
You can also configure it manually in ~/.codex/config.toml:
[mcp_servers.nap]
command = "/bin/sh"
args = ["-lc", "NAP_DIR=\"$HOME/.nap\" exec nap-mcp-server"]
enabled = true
Project-scoped config works too for trusted projects:
[mcp_servers.nap]
command = "/bin/sh"
args = ["-lc", "NAP_DIR=\"$HOME/.nap\" exec nap-mcp-server"]
enabled = true
Use the same block in .codex/config.toml inside a trusted project if you want the server scoped to that repository.
Other MCP Clients
Claude Desktop and other MCP clients use the same stdio pattern. Add a server entry that runs the bundled nap-mcp-server command on demand, and keep NAP_DIR pointed at your NAP workspace if you need a non-default data directory.
Example host-side launch command:
/bin/sh -lc 'NAP_DIR="$HOME/.nap" exec nap-mcp-server'
Use the same command/args form in any client that supports stdio MCP servers.
Inside sandboxes, use the MCP tools instead of shelling out to nap directly for network-backed operations. Direct nap CLI commands remain the right choice for humans and host-local shells.
NAP CLI Reference
The nap command-line interface (v0.5.4) provides tools for creating, resolving, and managing narrative resources using the Narrative Addressing Protocol.
Command Overview
| Command | Description |
|---|---|
| `nap add` | Add a representation to an entity manifest |
| `nap branch` | Create or list branches |
| `nap choose` | Choose backend provider |
| `nap commit` | Commit changes to a repository repository |
| `nap content-hash` | Compute the SHA-256 content hash of a file |
| `nap create` | Create a new entity manifest |
| `nap diff` | Show diff between two manifest files or versions |
| `nap doctor` | Run diagnostics and repair |
| `nap head-hash` | Show the current HEAD commit hash |
| `nap history` | View commit history for an entity |
| `nap init` | Initialize a repository repository and/or configure the backend provider |
| `nap install` | Install required dependencies |
| `nap list` | List repositories or entities within a repository |
| `nap merge` | Three-way merge of JSON/YAML values |
| `nap publish` | Publish changes to remote |
| `nap pull` | Clone or pull a repository from a remote |
| `nap push` | Push the current branch to its configured upstream remote |
| `nap query` | Query a subtree from a manifest |
| `nap remote` | Manage remotes on a repository |
| `nap resolve` | Resolve a NAP URI to its manifest or a subtree |
| `nap revert` | Revert a commit by hash (undoes all changes in that commit) |
| `nap schema` | Print a JSON Schema for manifest or commit types |
| `nap set` | Set a property on an entity manifest |
| `nap sign` | Sign a manifest (stub for v0) |
| `nap status` | Show system status |
| `nap switch` | Switch to a branch |
| `nap sync` | Sync with remote |
| `nap validate` | Validate a manifest against the NAP schema |
| `nap verify` | Verify a manifest signature (stub for v0) |
Global Options
| Flag | Description | Default |
|---|---|---|
| -d, --base-dir <BASE_DIR> | Base directory for repository repositories. Defaults to $NAP_DIR, or ~/.nap if unset | |
| -v, --verbose | Enable verbose debug logging |
Output Formats
Most commands support --format (-f) with values yaml (default) or json.
When stdout is not a terminal, JSON is used automatically. Override with $NAP_OUTPUT.
Common Examples
# Initialize a repository
nap init starwars
# Create an entity
nap create character lukeskywalker -u starwars -n "Luke Skywalker"
# Resolve a manifest
nap resolve nap://starwars/character/lukeskywalker
# Query a subtree
nap query nap://starwars/character/lukeskywalker properties
# View commit history
nap history nap://starwars/character/lukeskywalker
HTTP Server
The NAP resolver server provides a REST API for resolution and commits.
# Start the server (defaults to port 3100, base path = current directory)
nap-server
# Custom port and base path
NAP_PORT=8080 NAP_BASE_PATH=/path/to/repositories nap-server
Configuration
NAP core uses environment variables for configuration. All variables serve specific purposes with minimal overlap.
Storage Configuration
| Variable | Purpose | Default | Required |
|---|---|---|---|
NAP_STORAGE_BACKEND |
Storage backend selection (local or s3) |
local |
No |
NAP_DIR |
Base directory for local storage | ~/.nap |
No (local) |
NAP_S3_BUCKET |
S3 bucket name | — | Yes (s3) |
AWS_ACCESS_KEY_ID |
AWS/R2 access key | — | Yes (s3) |
AWS_SECRET_ACCESS_KEY |
AWS/R2 secret key | — | Yes (s3) |
AWS_REGION |
AWS region | — | Yes (s3) |
AWS_ENDPOINT_URL_S3 |
Custom S3 endpoint (R2, MinIO) | — | No (s3) |
AWS_ENDPOINT_URL |
Fallback S3 endpoint if AWS_ENDPOINT_URL_S3 unset |
— | No (s3) |
Lore VCS Configuration
| Variable | Purpose | Default | Required |
|---|---|---|---|
NAP_LORE_URL_BASE |
Lore server URL base | lore://localhost:8700 |
No |
NAP_WORKSPACE_ID |
Workspace identifier for multi-tenancy | default |
No |
NAPLORE_CLI |
Path to lore CLI binary | lore (from PATH) |
No |
NAP_LORE_GRPC_ENDPOINT |
gRPC endpoint for branch ref sync | — | No (optional) |
NAP_LORE_GRPC_TOKEN |
JWT bearer token for gRPC auth | — | No (optional) |
NAP_LORE_GRPC_RID |
Repository ID (hex-encoded) for gRPC | — | No (optional) |
NAP_LORE_GRPC_INSECURE |
Skip TLS verification (1/true/yes) |
0 |
No (optional) |
Constants
| Constant | Value | Purpose |
|---|---|---|
NAP_DIR (const) |
.nap |
Metadata directory name within repositories |
Note: The environment variable NAP_DIR (storage base directory) and the constant NAP_DIR (metadata directory name) serve different purposes and do not overlap.
Endpoints
| Method | Path | Description |
|---|---|---|
GET |
/resolve/{repository}/{entity_type}/{entity_id} |
Resolve a manifest |
GET |
/resolve/{repository}/{entity_type}/{entity_id}?branch=canon |
Resolve at a branch |
POST |
/commit/{repository}/{entity_type}/{entity_id} |
Commit changes |
GET |
/history/{repository}/{entity_type}/{entity_id} |
Get commit history |
GET |
/repositories |
List all repositories |
GET |
/repositories/{repository}/entities |
List entities in a repository |
GET |
/health |
Health check |
Query parameters for resolution: branch, commit, path (subtree query).
CLI Command Reference
Complete reference for all nap CLI commands.
| Command | Description |
|---|---|
| `nap add` | Add a representation to an entity manifest |
| `nap branch` | Create or list branches |
| `nap choose` | Choose backend provider |
| `nap commit` | Commit changes to a repository repository |
| `nap content-hash` | Compute the SHA-256 content hash of a file |
| `nap create` | Create a new entity manifest |
| `nap diff` | Show diff between two manifest files or versions |
| `nap doctor` | Run diagnostics and repair |
| `nap head-hash` | Show the current HEAD commit hash |
| `nap history` | View commit history for an entity |
| `nap init` | Initialize a repository repository and/or configure the backend provider |
| `nap install` | Install required dependencies |
| `nap list` | List repositories or entities within a repository |
| `nap merge` | Three-way merge of JSON/YAML values |
| `nap publish` | Publish changes to remote |
| `nap pull` | Clone or pull a repository from a remote |
| `nap push` | Push the current branch to its configured upstream remote |
| `nap query` | Query a subtree from a manifest |
| `nap remote` | Manage remotes on a repository |
| `nap resolve` | Resolve a NAP URI to its manifest or a subtree |
| `nap revert` | Revert a commit by hash (undoes all changes in that commit) |
| `nap schema` | Print a JSON Schema for manifest or commit types |
| `nap set` | Set a property on an entity manifest |
| `nap sign` | Sign a manifest (stub for v0) |
| `nap status` | Show system status |
| `nap switch` | Switch to a branch |
| `nap sync` | Sync with remote |
| `nap validate` | Validate a manifest against the NAP schema |
| `nap verify` | Verify a manifest signature (stub for v0) |
Design Principles
-
Content-addressed — Every piece of content is identified by its cryptographic hash. Manifests are immutable once committed.
-
URI-addressed — Every entity has a stable, portable URI. URIs are never invalidated by renames or moves.
-
Human-readable — YAML manifests are readable by worldbuilders and AI agents alike.
-
Portable — No runtime dependencies. A manifest is just a YAML file. A repository is just a Git repo.
-
AI-native — Subtree queries let AI agents fetch exactly the data they need. Provenance tracking records generation metadata.
-
Schema-validated — All manifests conform to a JSON Schema. Invalid manifests are rejected at commit time.
-
Decentralized — Repositories are Git repositories. They can be cloned, forked, merged, and published independently.
-
Extensible — New entity types, representation formats, and merge strategies can be added without breaking existing data.
Status
This is a v0 prototype. APIs and formats may change.
License
MIT
Status
This is a v0 prototype. APIs and formats may change.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file narrativeengine-0.5.4-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: narrativeengine-0.5.4-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 144.5 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
655686cb29e025574067fd511e85c42f5cbce9857d844473e1179153a11b4030
|
|
| MD5 |
7b7664041570c2019d1a68b8a642fd7a
|
|
| BLAKE2b-256 |
688aeceff8398e2e1497db91fae5bd65799e6c3f29c2fd38d56919e561946fd3
|
File details
Details for the file narrativeengine-0.5.4-cp313-cp313-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: narrativeengine-0.5.4-cp313-cp313-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 276.0 kB
- Tags: CPython 3.13, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae4d131a3957aad6071e3b8c96668839b4c9fabdd4ca07346792c43d05baa320
|
|
| MD5 |
02c3a287582bda369b6b1befd6c86960
|
|
| BLAKE2b-256 |
0663934ab6f8e038974efc042181b07dfb8809da8279100123caeb396634ae6a
|
File details
Details for the file narrativeengine-0.5.4-cp313-cp313-manylinux_2_34_aarch64.whl.
File metadata
- Download URL: narrativeengine-0.5.4-cp313-cp313-manylinux_2_34_aarch64.whl
- Upload date:
- Size: 269.7 kB
- Tags: CPython 3.13, manylinux: glibc 2.34+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d909a9a6f6edced36f041060b7a25d69dbdd4997583664b8c92873f45a63d6b6
|
|
| MD5 |
1f39ed41e781d1c94ac2a5836316cd77
|
|
| BLAKE2b-256 |
79321dc8bdf50924c965af1c2a7e731313ddc2d9636eb70e8ecf52cd8ee31514
|
File details
Details for the file narrativeengine-0.5.4-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: narrativeengine-0.5.4-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 243.7 kB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5af4eec45de43bc63746087425058662b477f53199643314ce907921a5c3d79b
|
|
| MD5 |
5a1766b08be663fb7091190c12cee882
|
|
| BLAKE2b-256 |
1424a952f1001d4718c95c684e6692e97702c490efff50a42a563f24fd3243fa
|
File details
Details for the file narrativeengine-0.5.4-cp313-cp313-macosx_10_12_x86_64.whl.
File metadata
- Download URL: narrativeengine-0.5.4-cp313-cp313-macosx_10_12_x86_64.whl
- Upload date:
- Size: 245.4 kB
- Tags: CPython 3.13, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3c7d3e37e26f60238c47e1782553a8e60d66cae0141693c8f3b29fe234d4aba
|
|
| MD5 |
358e97e95a338570729237d210cfd37f
|
|
| BLAKE2b-256 |
01f09ca3deb76919788f909beb597a8603f09ada364f390e156a3e160a573722
|