@miadi/ncp-story-studio 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,14 +5,16 @@ zero-dependency validator, a reader that accepts the NCP dialects that actually
5
5
  story-lattice layout with a React renderer, story-project storage over JSON files or Neon Postgres,
6
6
  the agent link protocol, and the canonical terminology as data.
7
7
 
8
- Phase plan, sources of truth, and what is deliberately not built yet: [`PHASES.md`](./PHASES.md).
8
+ In the Miadi stack, this is one of two narrative models. The Narrative Context Protocol (NCP)
9
+ describes a story the way Dramatica does: throughlines, players, storypoints and storybeats.
10
+ Miadi's story studio opens NCP story projects, draws them as a line of beats, and lets agents
11
+ read and link into them. The other model is `@miadi/wampum-narrative-engine`, a peer rather than
12
+ a view of this one, and `@miadi/ncp-wampum-bridge` carries a story between the two.
9
13
 
10
14
  ## Install
11
15
 
12
16
  ```bash
13
- pnpm add @miadi/ncp-story-studio
14
- # in this workspace
15
- pnpm -w add @miadi/ncp-story-studio@workspace:* --filter <consumer>
17
+ npm i @miadi/ncp-story-studio
16
18
  ```
17
19
 
18
20
  `react` and `@neondatabase/serverless` are optional peer dependencies: they are needed only by
@@ -147,7 +149,7 @@ Cards clamp their summary and illustration to three lines, so the canvas is 480p
147
149
  import { JsonStoryStore } from '@miadi/ncp-story-studio/store/json'
148
150
  import { NeonStoryStore } from '@miadi/ncp-story-studio/store/neon'
149
151
 
150
- const store = new JsonStoryStore({ root: '/srv/miadi/ncp-story-projects' })
152
+ const store = new JsonStoryStore({ root: './ncp-story-projects' })
151
153
  await store.init()
152
154
  const project = await store.get('catalyst-of-change')
153
155
  await store.save({ ...project, document }, { expected_updated_at: project.updated_at })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miadi/ncp-story-studio",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Narrative Context Protocol story studio as consumable modules: canonical NCP types and a zero-dependency validator, a headless story-lattice layout with a React renderer, story-project storage providers (JSON files and Neon Postgres), the agent link protocol, and the terminology and example data behind the teaching surface.",
5
5
  "license": "MIT",
6
6
  "author": "Miadi",
@@ -63,9 +63,7 @@
63
63
  "files": [
64
64
  "dist",
65
65
  "assets",
66
- "rispecs",
67
66
  "README.md",
68
- "PHASES.md",
69
67
  "LICENSE"
70
68
  ],
71
69
  "repository": {
package/PHASES.md DELETED
@@ -1,299 +0,0 @@
1
- # @miadi/ncp-story-studio — Phase Plan
2
-
3
- **Written:** 2026-09-12 · steered by Guillaume's annotations on the capability survey.
4
- **Reads with:** `AGENTS.md` (direction, version table stale — read manifests), `STATUS.md`,
5
- `rispecs/`, and `/a/src/Miadi-18/rispecs/wampum-narrative-engine/` (later phases).
6
- **Origin issue:** `jgwill/Miadi#361`. Wampum lanes: `#437` foundations, `#438` NCP bridge,
7
- `#439` package surface.
8
-
9
- ## Sources of truth
10
-
11
- | what | where |
12
- |---|---|
13
- | Canonical NCP schema | `/workspace/repos/avadisabelle/holisticagnostic-narrative-context-protocol/schema/ncp-schema.json` |
14
- | Prototype experience to rebuild | `/workspace/repos/miadisabelle/a1f8409e-1a36-495e-9ac2-84f617e6447c-ncp-story-studio-251125` |
15
- | Governance research | that repo's `foundations/{decolonization-protocol-extensions,oral-tradition-storywork,linguistic-relativity-indigenous-epistemology}/` |
16
- | Wampum specs | `rispecs/wampum-narrative-engine/` in this checkout |
17
- | Consumption target | `app/ncp` in this checkout — **planned, not yet created** |
18
-
19
- `app/ncp` is where the published packages are consumed to rebuild the prototype experience
20
- inside Miadi, with the seed projects (Catalyst of Changes and the other four narratives)
21
- observable there. It is a target, not a stale reference.
22
-
23
- ## Status — 2026-09-19 (phone round, from a real phone — 0.7.3 to 0.7.6)
24
-
25
- Reported from an iPhone: sweep the scrubber to the end and back, and the page died. Reproduced in
26
- WebKit (the engine of every iOS browser) with Playwright's iPhone profile: the studio rewrote the
27
- URL on every beat crossed, and WebKit throws a `SecurityError` past 100 `replaceState` calls in 10
28
- seconds. The app now writes the URL once the reader rests. In the package, for the phone's memory:
29
-
30
- - **The graph draws the window around the view, not the whole line** (`visibleNodeRange`): a dozen
31
- cards, rings and stems instead of ninety, however long the story. The canvas keeps its full width,
32
- so scrolling, snapping and focus-following are unchanged.
33
- - **A focused beat stays drawn, and the first screen is drawn before hydration** (0.7.4, from a
34
- WebKit review); a follow longer than six beats cuts instead of gliding, and the follow
35
- runs before paint so a cut never shows an empty frame (0.7.5, 0.7.6): arrow keys kept working past the window's edge only while the focused beat
36
- stayed mounted, and a link to beat 40 painted an empty line until the page hydrated.
37
- - **No full-length SVG blur.** The line's glow was an `feGaussianBlur` over a 32,000px path — at
38
- a phone's 3x density a buffer 97,000 pixels wide. It is now a faint wide stroke under the thin one.
39
-
40
- ## Status — 2026-09-19 (phone round, second pass — 0.7.0 to 0.7.2)
41
-
42
- Two independent reviews read the first pass: a code review (9 findings) and a phone UX walk at
43
- 360, 390, 430, 768 and landscape (20 findings, one blocking). What the package took from them:
44
-
45
- - **The line and the scrubber cannot disagree.** `centerBeatId` separates where the reader is from
46
- the beat they chose; a relaid line (cards ↔ compact) is put back on its beat.
47
- - **A swipe is reported where it comes to rest**, not beat by beat as it passes; the scroll the
48
- graph makes itself is never reported. The scrubber reads the beat from where the thumb lifts.
49
- - **Fine mode and go-to-number** on the scrubber: ninety beats across a phone is four pixels a
50
- beat; a resting thumb gets twelve, and the counter takes "60".
51
- - **Cards open their beat**; rings are thicker and more opaque; nothing in the graph is under
52
- 10px; the scrubber has a visible keyboard focus ring.
53
- - **`ValidationIssue.elementIds`**: a sequence clash names its beats, once per clash.
54
- - **A crossing costs two beats, not ninety** (0.7.2): beat marks are memoised behind one stable
55
- click handler, so the scrubber no longer drags a full re-render of the line behind the thumb.
56
- Fine mode reads the pause from event timestamps (0.7.1): a timer fired mid-slide on a busy page.
57
- - Held for Guillaume: a tone palette where each axis owns a hue family. Three axes currently share
58
- purples (opinion, power, transcendence), which a phone cannot tell apart; the prototype's
59
- palette is kept until that is decided.
60
-
61
- ## Status — 2026-09-19 (phone round)
62
-
63
- The studio was built at a desk and read on a phone. On a 390px screen the nine tabs wrapped into
64
- three rows and scrolled away with the page, the save sat at the top of a 32,000px beat list, the
65
- edit buttons appeared only on hover — which a touch screen never does — and a vertical swipe that
66
- started on the graph could not scroll the page past it. What changed (0.6.0, and `app/ncp`):
67
-
68
- - **`<BeatScrubber>`** — one tick per beat, coloured by tone, signposts tallest. A thumb runs along
69
- ninety beats in one stroke; the graph or the list follows it. It rides in the studio's sticky bar
70
- in both the graph and the beats view.
71
- - **The graph on touch is a carousel.** `snap` settles one beat at the centre; `followFocus` scrolls
72
- a linked beat into view (before, `?view=graph&beat=x` opened on beat 1); `onCenteredBeatChange`
73
- lets the host know where the reader is. Vertical swipes pass through to the page.
74
- - **Shorter cards, shorter canvas.** Cards clamp to three lines; the canvas drops from 720 to 480.
75
- - **In the app:** a bottom bar on phones (overview · graph · beats · ask · more), a views sheet and
76
- the chat as sheets over the shared `DragSheet` (jgwill/Miadi#381), a sticky status bar with the
77
- save, beats that filter by words and appreciation and fold into an outline, card actions shown on
78
- touch, 16px fields so iOS does not zoom into every edit, and whole-card links on the project list.
79
-
80
- ## Status — 2026-09-19 (navigation round)
81
-
82
- Four things a reader asked for after using it:
83
-
84
- - **The line is navigable.** Drag the empty space to pan; arrow keys scroll it, shift for a longer
85
- step, Home and End for the ends. A press that starts on a beat still opens that beat.
86
- - **Compact says something.** It was circles; now each mark carries its narrative function, its
87
- summary and its three tone letters, so a ninety-beat story is readable at a glance.
88
- - **Cards are the default at every length** — the card is what makes a beat readable, and the line
89
- is now navigable, so length is no longer a reason to hide them. Compact is one click away.
90
- - **Every view is reachable without dragging.** The tab bar wraps; `terminology` was hidden behind a
91
- sideways scroll.
92
- - **Validation reads as three things**: what to fix, what the story extends (declared, not drift),
93
- and what is worth knowing — each group counted once with its places behind a disclosure, instead
94
- of sixty-three identical lines.
95
-
96
- ## Status — 2026-09-15 (interface round)
97
-
98
- The surface was refined against the prototype it is modelled on, which had a visual language the
99
- rebuild had not carried across:
100
-
101
- - **The graph draws cards again.** A node is a numbered mark with three tone rings that turn slowly;
102
- above the line its card carries the appreciation, the perspective, the summary and the
103
- illustration; below it a panel names each tone axis with its colour. The headless layout is
104
- unchanged — this is presentation over the same geometry — so a server still draws the same SVG.
105
- - **Beats are a timeline, not a list.** A gradient spine with the sequence circles sitting on it and
106
- the cards alternating left and right, each card carrying its tone triad as A/S/T chips. Editing
107
- opens in place and closes back into the same shape.
108
- - **Every element view is a card** in the prototype's shapes: perspectives with a point-of-view
109
- badge, players with an avatar and their visual and audio lines, storypoints with an appreciation
110
- eyebrow and a function chip, dynamics with their vector.
111
- - **One room, one light.** `app/ncp` uses the prototype's slate ground with indigo, purple and pink
112
- accents rather than the portal's neutral tokens — the studio is its own room, and the rest of the
113
- portal keeps its own.
114
- - **The view is in the URL.** `?view=graph&beat=<id>` — a link can point at a story's graph, or at
115
- one beat inside it, and a reload lands where it left.
116
- - **The tab bar counts.** Each view says how much it holds.
117
-
118
- ## Status — 2026-09-12 (second round)
119
-
120
- A third review — a parity audit against the prototype — returned 14 gaps. What closed:
121
-
122
- - **The six teaching stories are back.** Catalyst of Change, Echoes of the Past, Tushell and the
123
- Orchestra of Agents, The Keeper Chronicles, The Bridge Walker, The Archive Keeper — every beat
124
- toned. Catalyst is assembled from its source document plus the enrichment table the prototype
125
- kept separately, so it arrives with its 90 toned beats, 23 moments and 5 overviews (the
126
- prototype's own adapter dropped 22 of those moments).
127
- - **The agent reads the whole story.** The digest threshold was 60k, and the seed story is ~80k, so
128
- the studio's own narrative reached the model as an index. Default is 400k now.
129
- - **A story can be read**: beat storytelling and illustration without opening an editor, tone names
130
- beside the colours, storypoint and player storytelling rendered, perspective references named.
131
- - **The graph says what its colours mean** — a legend, and every node describes itself in words.
132
- - **Terminology is a place**: `/ncp/terminology`, all 255 terms by section plus the legacy table.
133
- - **The chat is a chat**: a welcome, a thinking indicator, auto-scroll, and a drawer on a phone.
134
- - **A story can bring its own reading positions** — the persona registry is open, so the prototype's
135
- guest voices (a wise owl, a data dolphin) can be registered without changing this package.
136
-
137
- Both of those are now closed. A story's guest voices reach the prompt: asking *Tushell and the
138
- Orchestra of Agents* about its first beat answers as 🧠 Mia · 🌸 Miette · 🎨 Ava8 · 🌊 Tushell ·
139
- 🦉 Wise Owl, and the Keeper Chronicles answer with 🌀 Miawapaskone and 🪶 Grandmother Yazhi. And the
140
- studio answers for real by default — `NCP_AGENT_DISABLED=1` is the off switch, not an on switch.
141
- A live call still needs the writer credential, because the port is publicly reachable and a model
142
- call costs money; a browser without it gets the prompt instead of an error.
143
-
144
- ## Status — 2026-09-12
145
-
146
- Phase 1 and Phase 2 are **built and running**: `@miadi/ncp-story-studio` 0.1.0 with 86 tests, and
147
- `app/ncp` consuming it on port 3335. What landed, and what each phase still holds, is below; the
148
- module surface is in `README.md`.
149
-
150
- Verified end to end on 2026-09-12: the four bundled examples seeded into a JSON store, the studio
151
- rendering graph and beat editor, an edit saved from the browser through a server action to
152
- `story.ncp.json` on disk, a conditional `PUT` accepted and a stale one refused with 409, an
153
- unauthenticated write refused with 401.
154
-
155
- Two adversarial reviews ran against this work — one on the package, one on `app/ncp`. They
156
- returned 18 and 14 findings. All are fixed; the package half carries a regression test per finding
157
- (`test/review-findings.test.mjs`), and the surface half was re-verified by request:
158
-
159
- ```bash
160
- # a server action without the credential is refused, and with it is allowed
161
- curl -X POST /api/ncp/session -H "Authorization: Bearer $MIADI_API_TOKEN_WRITER" -c jar.txt
162
- # a story that arrived invalid stays editable; an edit that adds an error does not
163
- curl -X PUT /api/ncp/projects/shawshank-redemption ... # 200, preexisting_errors: 19
164
- # a server action and a REST PUT racing on the same version: one wins, one conflicts
165
- ```
166
-
167
- ## Phase 1 — vocabulary and data · **built**
168
-
169
- Goal: one NCP type surface everyone can produce compatible data against, and a viewer in
170
- `app/ncp` reading real stories.
171
-
172
- - **S1 `/schema`** — TypeScript types, a zero-dependency validator (Zod was dropped: a published
173
- package should not pin a validation library on its consumers), the canonical JSON Schema as an
174
- asset, and fixtures, from the
175
- canonical schema (29 appreciations, 148/144 narrative functions, 9 dynamics × 16 vectors,
176
- 3-axis tones, 6 audience POVs, `moments.fabric`). Prototype-only fields
177
- (`custom_appreciation`, `custom_narrative_function`, `Player.motivations`,
178
- `Perspective.throughline`) become **declared extensions**; `pov` renames to
179
- `author_structural_pov`. No Wampum fields in the model at this phase.
180
- - **S2 `/graph`** — the story lattice as a real component package (headless layout + React
181
- renderer), consumed by `app/ncp`, not copied into it.
182
- - **S9 examples + terminology** — the 5 canonical examples, the 5 prototype narratives, and
183
- `docs/terminology/` as data behind a browser view. Teaching surface is first-class, not a
184
- by-product.
185
- - **`app/ncp` v1** — project list, story viewer, graph view, reading from the store provider.
186
-
187
- ## Phase 2 — editing and story projects · **built**
188
-
189
- - **S3 `/editor`** — CRUD for beats / players / storypoints, drag-reorder, dynamic perspectives,
190
- live validation with structural-tension alerts. **Two storage providers behind one
191
- interface: JSON files and Neon (Postgres).** Story projects are managed, not held in a tab.
192
- - **S4 `/agents`** — the `[[Beat|Player|Perspective|Point:ID|Label]]` link protocol as its own
193
- parser module, and a provider-neutral model adapter (the prototype hard-codes one vendor and
194
- one model string). Personas: 🧠 Mia structural, 🌸 Miette narrative, 🎨 Ava8 musical.
195
- - **S12 chronicle ↔ story** — import episode material into a story, and surface a story inside
196
- an episode. Both directions, reusing `@miadi/inquiry-weave` and the chronicle readers in
197
- `app/chronicle/lib/`.
198
- - **S10 import / export** — NCP JSON in and out, then reuse what Miadi already publishes:
199
- `@miadi/voice` for spoken readings, the Twine promotion path for a readable book,
200
- `@miadi/musical-composition-to-episode` for composition links.
201
-
202
- ### What Phase 1 and 2 taught, and what changed because of it
203
-
204
- - **Three dialects, not one.** The canonical schema, the subtxt exports, and the Catalyst design
205
- file disagree about shape *and* vocabulary. One reader now recognizes each and reports every
206
- adaptation, which is what lets all four examples open in the same studio.
207
- - **The canonical `required` lists name every field.** No shipped example satisfies them, so the
208
- studio validates what a studio needs by default and enforces the schema's own lists on request.
209
- - **Beat `sequence` numbers a series, not a narrative.** Signposts 1-4 and progressions 1-16 are
210
- separate runs inside one throughline; uniqueness is checked per series.
211
- - **An adversarial review found 18 defects** in the first cut, the worst of which deleted a store
212
- root. Every one is fixed with a named regression test in `test/review-findings.test.mjs`.
213
-
214
- ## Phase 3 — relational and symphonic readings
215
-
216
- - **S11 Ava8 × NCP** — Ava8 is a musical orchestra agent, not a name collision. Relate story
217
- `moments` to musical structure and explore symphonic capability inside a story. RISE specs
218
- drafted during Phase 1–2 so this phase has ground to stand on.
219
- - **S5 Wampum** — specs first (`rispecs/wampum-narrative-engine/` already holds the belt model,
220
- the `project`/`read` bridge with its `crossing_report`, and the four-layer perspective
221
- prompt). First concrete artifact: **Catalyst of Changes rendered in belt form**, to look at
222
- and reflect on, before any schema support lands.
223
- - **S6 governance** — the ground is now local and pinned. The three research packets were carried
224
- into `foundations/` on 2026-09-20 from `avadisabelle/holisticagnostic-narrative-context-protocol`
225
- at `0ce09365` (an unmerged branch — see each packet's `carried-from.yaml`), and the five layers
226
- are specified one folder each in `rispecs/governance/`: transmission conditions, relational
227
- provenance, linguistic frame, performativity, semantic access control. Nothing is implemented,
228
- deliberately — only the layers a later phase proves it needs, and the refusal gate the Wampum
229
- perspective layer already requires.
230
-
231
- ## Phase 4 — narrative workflow runtime
232
-
233
- **S7** — goals, candidate trajectories, state versions, budgets, termination authority. The
234
- spec needs revision before it is built; it is not Phase 1 material.
235
-
236
- ## Phase 5 — three universes
237
-
238
- **S8** — Engineer / Ceremony / Story validators returning evidence rather than a score.
239
- Deliberately last: elements of the model resemble it already, and introducing it early would
240
- confuse the vocabulary. It gets integrated where it belongs, not early.
241
-
242
- ## The spec lane that runs through every phase
243
-
244
- Specifications advance even where implementation does not.
245
-
246
- - `rispecs/governance/<layer>/` — one folder per layer: transmission conditions, relational
247
- provenance, linguistic frame, performativity, semantic access control. Each states who the
248
- teller and receiver requirements are, what the layer means, and how it sits in the model.
249
- Kept alive as later phases reveal what governance actually has to do. If a phase needs part
250
- of it early, that part gets analysed and implemented then — not pre-built.
251
- - Wampum specs and the Ava8 × NCP spec, written ahead of their phase for the same reason.
252
-
253
- ## Consumption inside `app/`
254
-
255
- - **C1** — publish order: schema, then the graph component, then editor, then agents. Headless
256
- first: validators and layout carry no React so route handlers can use them; the React
257
- renderer ships behind a subpath export (`@miadi/attention-ui` is the local precedent).
258
- - **C2** — `workspace:*` in the root `package.json` while exports move; published semver once
259
- they settle. Every manifest change updates `pnpm-lock.yaml` with scoped install/build/test.
260
- - **C3** — surface: `app/ncp` (projects), `app/ncp/studio/[storyId]` (the studio),
261
- `app/api/ncp/*` (validate, stories, later projections). Pattern to copy:
262
- `app/chronicle/lib/*.ts` and `app/chronicle/[episode]/page.tsx` importing
263
- `@miadi/episodic-memory-schema`, `@miadi/inquiry-weave`, `@miadi/tide` server-side.
264
- - **C4** — validation runs server-side, where its record can be persisted.
265
- - **C5** — storage provider chosen by environment: JSON files under a stories root, or Neon.
266
- Browser storage only for per-viewer conveniences.
267
- - **C6** — `app/live-story-monitor` and `app/narrative-lattice` become consumers of these
268
- packages. Today `app/narrative-lattice/page.tsx` runs on fixtures from
269
- `@/types/live-story-monitor-data`; they need feeding from the same schema and provider.
270
- - **C7** — port 3335 is the single surface: dev mode while building, prod rebuild when
271
- shipping, and state what is shipping from an untracked tree before rebuilding.
272
-
273
- ## What this gives Concordia
274
-
275
- - **K1** — an authorship record a rights or ethics review can read: state version, agent and
276
- role, model, prompt, schema version, approvals, rejected alternatives.
277
- - **K2** — per-field artifacts for the faculty alignment open as `jgwill/Miadi#611`–`#614`.
278
- - **K3** — the Martin Lefebvre report in this folder is a literature anchor for the
279
- narrative-theory framing. Cite from it; do not specify from it.
280
- - **K4** — a seminar-ready teaching surface: terminology browser and worked example stories,
281
- with governance handling stated in the data rather than promised in prose.
282
-
283
- ## Risks that set the order
284
-
285
- - **R2** — schema divergence between the prototype types and the canonical schema. Freeze S1
286
- before porting any UI.
287
- - **R3** — the schema repo is not vendored here (its only submodule is `llms`). Pin it or copy
288
- the schema with a version stamp, or the enums drift silently.
289
- - **R1** — cultural protocol. Deferring Wampum out of Phase 1 removes this from the critical
290
- path. When it returns: public seed belts only, no community-specific readings without
291
- consent, and the refusal gate exists before any generated reading ships.
292
-
293
- ## Stale claims in `AGENTS.md` (do not carry forward)
294
-
295
- - The version table. Real versions today: `@miadi/episodic-memory-schema` 0.10.0, `@miadi/tide`
296
- 0.4.0, `@miadi/tide-contract` 0.3.0, `@miadi/hooks-core` 0.5.0, `@miadi/a2a-contracts` 0.1.1.
297
- Read the manifests, per the `miadi-package-truth` skill.
298
- - `pnpm add @miadi/ncp-story-studio` — no manifest, nothing published yet.
299
- - `@miadi/three-universe-processor` appears in issue prose only; no such package exists.
@@ -1,5 +0,0 @@
1
- # RISE README: @miadi/ncp-story-studio
2
-
3
- NCP story studio for story studio workflows for narrative continuity and production planning.
4
-
5
- Read `./RISPEC.md`, check `../package.json`, and use the narrowest package needed. Indexed from root `llms.txt` and `llms-full.txt`.
package/rispecs/RISPEC.md DELETED
@@ -1,9 +0,0 @@
1
- # RISPEC: @miadi/ncp-story-studio
2
-
3
- RISE = Reverse-engineer, Intent-extract, Specify, Export.
4
-
5
- Purpose: story studio workflows for narrative continuity and production planning.
6
- Install: `pnpm add @miadi/ncp-story-studio` or workspace `pnpm -w add @miadi/ncp-story-studio@workspace:* --filter <consumer-package>`.
7
- Contract: public exports, schemas, CLI flags, or adapter payloads owned by this package.
8
- Authority: `package.json`, source exports, tests, and release metadata remain truth.
9
- Handoff: verify exports, examples, test evidence, and publish/stub/deprecated status.