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.
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
NAP is built on four primitives:
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)
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..."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.
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.
| 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 |
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/
curl -fsSL https://github.com/portalshq/narrativeengine/releases/download/v0.4.2/install.sh | bashInstall 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/narrativeenginegit clone https://github.com/cinematiccanvas/nap.git
cd nap
cargo build --release
# Binaries land in target/release/
# nap — CLI tool
# nap-server — HTTP resolver serverpip install narrativeenginefrom narrativeengine import create_block, generate_candidate, render_lore_summary
block = create_block("char-1", "A brave adventurer")
candidate = generate_candidate(block)npm install @portalshq/narrativeengineimport { createBlock } from "@portalshq/narrativeengine";
const block = createBlock("char-1", "A brave adventurer");# 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# Initialize a new repository
nap init starwars
# See what you created
ls starwars/
# → .nap/ repository.yaml characters/ locations/ scenes/ props/# 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# 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 starwarsnap resolve nap://starwars/character/lukeskywalker -f json
nap resolve nap://starwars/character/lukeskywalker -f yamlThe nap command-line interface (v0.5.2) provides tools for creating, resolving, and managing narrative resources using the Narrative Addressing Protocol.
| Command | Description |
|---|---|
| `nap add-repr` | 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) |
| 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 |
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.
# 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/lukeskywalkerThe 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-serverNAP core uses environment variables for configuration. All variables serve specific purposes with minimal overlap.
| 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) |
| 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) |
| 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.
| 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).
Complete reference for all nap CLI commands.
| Command | Description |
|---|---|
| `nap add-repr` | 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) |
-
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.
This is a v0 prototype. APIs and formats may change.
MIT
This is a v0 prototype. APIs and formats may change.
MIT