Data model
How Sonaloop stores everything as JSON in one graph.
Sonaloop stores everything as JSON in a graph. Three layers explain the format — and each concept shows its concrete schema when you open it.
Three layers
Every piece of content in every artefact is one of five: Statement · Finding · Prompt · Ref · Stance. One renderer per primitive — so the "same thing" looks the same everywhere.
Every artefact (persona, council, report, prototype, note, section) is a Node with {id, kind, title, project_id, created_at}. Typed Edges wire them together (based_on, feeds_into, refines, answers).
Persona memory lives in its own dated records (experiences, daily summaries, pain points), so recall and time-travel work.
The five primitives
Statement{ "persona_id": "persona_…",
"text": "…markdown, in the persona's voice…",
"stance": { "value": 1, "label": "conditional" }, // optional
"about": { "kind": "prompt", "id": "q0" }, // what it responds to
"refs": [ { "kind": "memory", "text": "missed a deadline in March" } ] }Finding{ "text": "…markdown…",
"kind": "summary|key_problem|recommendation|open_question|risk|cluster|segment",
"score": { "effort": 2, "value": 5 }, // optional
"refs": [ { "kind": "council", "id": "council_…" } ] }Prompt{ "text": "…markdown…", "kind": "question|proposal|goal|focus|hypothesis", "id": "q0" }Ref{ "kind": "memory|council|synthesis|prototype_state|persona|external",
"id": "council_…", // when it points at a stored record
"text": "…", // when it is a free observed-state string
"quote": "…" } // optional supporting quoteStance{ "value": -2, "label": "oppose" }
// −2 oppose · −1 skeptical · 0 neutral · +1 conditional · +2 supportFull details & migration path: spec/unified-artifact-schema.md.