| title | description |
|---|---|
Narrative Context Protocol Schema Reference |
Practical implementation guide for validating and exchanging NCP storyforms. |
This document explains the canonical schema at /schema/ncp-schema.json and /schema/ncp-schema.yaml.
Use this page when implementing import/export, validation, and cross-tool interchange.
- A shared envelope for transporting narrative context (
schema_version+story). - A consistent separation of
subtextandstorytellingper narrative. - Closed canonical narrative shapes, so extra keys are rejected unless a shape explicitly allows extensions.
- Canonical enums for
appreciation,narrative_function,dynamic, andvector. - Optional custom mapping fields that preserve canonical meaning.
npm install ajv
node tests/validate-schema.jsThe test runner validates:
- Valid fixtures:
/examples/example-story.json,/examples/ideation-beginner.json,/examples/anora.json,/examples/the-shawshank-redemption.json,/examples/complete-storyform-template.json - Invalid fixtures:
/examples/invalid/*.json
Legacy exports are kept in /examples/legacy/ for migration reference only.
{
"schema_version": "1.3.0",
"story": {
"id": "story_123e4567-e89b-12d3-a456-426614174000",
"title": "Echoes of the Past",
"genre": "Mystery Thriller",
"logline": "A hardened detective uncovers clues linking a cold case to his own haunting history.",
"created_at": "2025-12-01T12:34:56Z",
"ideation": {
"character": [],
"theme": [],
"plot": [],
"genre": []
},
"narratives": []
}
}Required top-level fields:
schema_version(semver string)story
Required story fields:
id,title,logline,created_at,narratives
Optional story fields:
genre(concise story label)ideation(pre-narrative beginner/exploratory concept threads)
story.ideation is optional. If present, it must contain all four arrays:
characterthemeplotgenre
Each ideation array item is a lightweight node with required:
idsummary
Documented optional keys:
titlenotestags(array of strings)
Additional metadata is allowed on ideation nodes to support free-flowing ideation and tool-specific enrichment.
Use the four ideation domains as different lenses on the same early concept:
character: Who this is about. Capture people, roles, motivations, contradictions, relationships, and potential arcs.theme: What this means. Capture the central argument, moral tension, philosophical question, or value conflict.plot: What happens. Capture causally linked events, conflicts, turning points, and possible outcomes.genre: How it should feel. Capture audience expectation, tone, pacing language, and style conventions.
Quick heuristic:
- If it is a person or point-of-view carrier, put it in
character. - If it is a meaning claim or tension of values, put it in
theme. - If it is an event chain or conflict progression, put it in
plot. - If it is a framing/experience contract with the audience, put it in
genre.
Each item in story.narratives[] is a Dramatica storyform: a single, complete argument structure within the story, expressed through subtext and storytelling layers.
Each item in story.narratives[] contains:
idtitlestatus(optional:candidate,draft,complete)subtextstorytelling
Both objects are required.
If status is omitted, consumers may treat the narrative as complete.
subtext contains five required arrays:
perspectivesplayersdynamicsstorypointsstorybeats
Required keys per item:
idauthor_structural_pov(i,you,we,they)summarystorytelling
IDs are opaque strings. Plain UUIDs are fine; type prefixes are optional. Perspectives are closed authorial POV records; do not place role, conflict, or character identity fields here.
Required keys per item:
id,name,role,visual,audio,summary,storytelling,perspectives
perspectives must be an array of objects, each with required perspective_id.
Player identity belongs here, not on perspectives.
IDs are opaque strings. Plain UUIDs are fine; type prefixes are optional.
Required keys per item:
id,dynamic,vector,summary,storytelling
Canonical dynamic values:
main_character_resolveinfluence_character_resolvemain_character_growthmain_character_approachproblem_solving_stylestory_limitstory_driverstory_outcomestory_judgment
Canonical vector values:
change,steadfaststop,startdo_er,be_erlinear,holisticoptionlock,timelockaction,decisionsuccess,failuregood,bad
Custom extension fields:
custom_dynamic,custom_dynamic_namespacecustom_vector,custom_vector_namespace
Required keys per item:
id,appreciation,illustration,summary,storytelling,perspectives
Optional canonical key:
narrative_function(validated against canonical enum when provided)
Custom extension fields:
custom_appreciation,custom_appreciation_namespacecustom_narrative_function,custom_narrative_function_namespace
Required keys per item:
id,scope,sequence,summary,storytelling,perspectives
Optional keys:
signpost(1-4)throughlinenarrative_function(validated against canonical enum when provided)custom_narrative_function,custom_narrative_function_namespace
scope controls allowed sequence range (enforced in schema):
signpost:1-4progression:1-16event:1-64
storytelling contains two required arrays:
overviewsmoments
Required keys per item:
id,label,summary,storytelling
IDs are opaque strings. Plain UUIDs are fine; type prefixes are optional.
label must be exactly one of:
LoglineGenreBlended Throughlines
Canonical exporters should emit those exact Title Case values.
Importers/normalizers may accept legacy inputs such as logline, genre, blended_throughlines, Premise Overview, and Four Throughlines Extraction, but they should normalize those values before schema validation or export.
Required keys per item:
summary,synopsis,setting,timing,imperatives,storybeats
Optional keys:
id,act,order,maximum_steps,fabric,audience_experiential_pov
storybeats inside a moment is an ordered reference list:
"storybeats": [
{ "sequence": 0, "storybeat_id": "beat_abc123" },
{ "sequence": 1, "storybeat_id": "beat_def456" }
]Canonical sets are versioned in two places:
- Enforced by schema enums in
/schema/ncp-schema.json - Documented in:
/docs/terminology/02.appreciations-of-narrative.md/docs/terminology/03.narrative-functions.md/docs/terminology/04.dynamics.md/docs/terminology/05.vectors.md
Use custom fields to map alternate terminology while preserving canonical keys.
Example (storypoint):
{
"id": "storypoint_2345abcd",
"appreciation": "Main Character Symptom",
"narrative_function": "Disbelief",
"custom_appreciation": "Alternative Viewpoint",
"custom_appreciation_namespace": {
"Dramatica": "Main Character Symptom",
"Hero's Journey": "Call to Adventure",
"Save the Cat!": "Debate"
},
"illustration": "the character distrusts obvious evidence",
"summary": "A recurring refusal to accept what is in front of them.",
"storytelling": "The protagonist keeps dismissing direct warnings.",
"perspectives": [
{ "perspective_id": "123e4567-e89b-12d3-a456-426614174000" }
]
}Some historical exports in /examples/legacy/ predate the current interchange contract.
They are useful references but are not guaranteed to validate against the canonical schema.
For migration strategy, see:
/docs/terminology/10.dramatica-translation.md/examples/example-mapping.json