Output and Rendering¶
TNGS can render the current graph state to six output formats using a single endpoint:
Every render call advances the narrative status to rendered.
Format overview¶
| Type | Content-Type | Best for |
|---|---|---|
prose |
text/markdown |
Reading the narrative as a draft |
diff |
application/json |
Reviewing what each transform changed |
json |
application/json |
Consuming the full graph state programmatically |
cypher |
text/x-cypher |
Replaying or migrating the narrative graph |
markdown |
text/markdown |
Summaries and transform logs for human review |
graphml |
application/xml |
Visual graph exploration in yEd |
prose — Markdown draft¶
Renders atoms in surface order. Scene headings are drawn from scene.summary
when set — which is populated automatically when ingesting with
format: "markdown" from ## heading text. Scenes without a summary fall back
to ## Scene N. Context blocks show the active perspective and mood when
transforms have been applied.
curl -X POST http://localhost:8000/v1/render/<narrative-id> \
-H "Content-Type: application/json" \
-d '{"type": "prose"}' \
| jq -r '.content'
Output — plain-text ingest (no summary set):
# The Gift
## Scene 1
> POV: Alice (internal, reliable) | Mood: warm
Alice offered the book. She smiled.
## Scene 2
Bob accepted it gratefully. He nodded once.
Output — Markdown ingest (summary = chapter heading):
# The Yellow Wallpaper
## The House
> POV: narrator (internal, unreliable) | Mood: dread
It is very seldom that mere ordinary people like John and myself secure
ancestral halls for the summer. …
## The Room
> Mood: dread
I do not like our room a bit. …
The prose render also reflects atom text revisions: if PATCH /v1/atoms/{id}
has been called, the revised text appears here; the original remains in the
graph under HAS_REVISION.
diff — Transformation diff¶
Returns a JSON document showing before/after state for every scene that has been transformed. Grouped by axis.
curl -X POST http://localhost:8000/v1/render/<narrative-id> \
-H "Content-Type: application/json" \
-d '{"type": "diff"}' \
| jq '.content | fromjson'
Output structure:
{
"narrative_id": "...",
"transforms": [
{
"transform_id": "...",
"axis": "pov",
"scene_id": "...",
"before": null,
"after": { "focalizer": "char-alice", "distance": "internal" }
}
]
}
json — Full graph state¶
Dumps the complete graph state as a structured JSON document. Useful for programmatic consumption, archiving, or feeding into downstream tools.
curl -X POST http://localhost:8000/v1/render/<narrative-id> \
-H "Content-Type: application/json" \
-d '{"type": "json"}' \
| jq '.content | fromjson'
Top-level structure:
{
"narrative": {
"id": "...", "title": "...", "status": "rendered",
"scenes": [
{
"id": "...", "sequence": 1,
"atoms": [ { "id": "...", "text": "...", "kind": "descriptive" } ],
"events": [ { "id": "...", "verb": "offered", "tense": "past" } ],
"current_perspective": { ... },
"current_mood": { ... }
}
]
},
"transforms": [ ... ],
"characters": [ ... ],
"event_relations": [ ... ]
}
cypher — Reproducible MERGE script¶
Generates a Cypher script of MERGE statements that, when run against an
empty database, reconstructs the current graph state. Useful for migrations,
snapshots, and sharing narrative graphs between Neo4j instances.
curl -X POST http://localhost:8000/v1/render/<narrative-id> \
-H "Content-Type: application/json" \
-d '{"type": "cypher"}' \
| jq -r '.content' > narrative_snapshot.cypher
# Replay against a fresh Neo4j instance
cypher-shell -u neo4j -p <password> < narrative_snapshot.cypher
markdown — Structured summary¶
Produces a human-readable Markdown document with:
- Narrative metadata header
- Per-scene summary tables (atoms, events, active transforms)
- Transform log sorted by
applied_at - Pattern instance summary
Useful for editorial review, annotation sessions, or exporting to a notebook.
curl -X POST http://localhost:8000/v1/render/<narrative-id> \
-H "Content-Type: application/json" \
-d '{"type": "markdown"}' \
| jq -r '.content' > summary.md
graphml — yEd graph diagram¶
Produces a GraphML document that can be opened directly in yEd Graph Editor. Edges are colored by narrative tension score on a six-stop gradient from neutral grey to dark red.
curl -X POST http://localhost:8000/v1/render/<narrative-id> \
-H "Content-Type: application/json" \
-d '{"type": "graphml"}' \
| jq -r '.content' > narrative.graphml
See Reading the Graph in yEd for a step-by-step guide.
The render response also includes metadata:
{
"narrative_id": "...",
"render_type": "graphml",
"content": "<?xml ...",
"content_type": "application/xml",
"metadata": {
"node_count": 24,
"edge_count": 31,
"format": "graphml-yed"
}
}
Atom revision history¶
Atom text can be revised non-destructively after ingest. Use PATCH to create
a new revision; all renderers pick up the latest text automatically.
# Revise a sentence
curl -X PATCH http://localhost:8000/v1/atoms/<atom-id> \
-H "Content-Type: application/json" \
-d '{
"text": "She hesitated at the threshold, then stepped inside.",
"operator": "editor",
"reason": "strengthen the beat"
}'
{ "atom_id": "…", "revision_id": "…", "text": "She hesitated at the threshold, then stepped inside." }
# Retrieve the full revision chain (oldest first)
curl http://localhost:8000/v1/atoms/<atom-id>/revisions
{
"atom_id": "…",
"revisions": [
{
"id": "rev-001",
"text": "She hesitated at the threshold, then stepped inside.",
"revised_at": "2026-04-26T14:32:00",
"operator": "editor",
"reason": "strengthen the beat"
}
]
}
The original atom text is always preserved in the graph. Revision history is queryable in Neo4j:
MATCH (a:Atom {id: $id})-[:HAS_REVISION]->(r:AtomRevision)
RETURN r.text, r.revised_at, r.operator
ORDER BY r.revised_at ASC
Accessing rendered content from the API¶
The render endpoint always returns the same envelope:
{
"narrative_id": "string",
"render_type": "string",
"content": "string",
"content_type": "string"
}
The content field is always a string. For json and diff types, parse
it with JSON.parse() or jq '.content | fromjson'. For graphml, write it
directly to a .graphml file.
Saving output to files¶
# Save all formats for a narrative
ID="your-narrative-id"
curl -sX POST http://localhost:8000/v1/render/$ID -H "Content-Type: application/json" \
-d '{"type":"prose"}' | jq -r '.content' > output_prose.md
curl -sX POST http://localhost:8000/v1/render/$ID -H "Content-Type: application/json" \
-d '{"type":"json"}' | jq -r '.content' > output_graph.json
curl -sX POST http://localhost:8000/v1/render/$ID -H "Content-Type: application/json" \
-d '{"type":"cypher"}' | jq -r '.content' > output_replay.cypher
curl -sX POST http://localhost:8000/v1/render/$ID -H "Content-Type: application/json" \
-d '{"type":"markdown"}' | jq -r '.content' > output_summary.md
curl -sX POST http://localhost:8000/v1/render/$ID -H "Content-Type: application/json" \
-d '{"type":"graphml"}' | jq -r '.content' > output_graph.graphml