Metis · Features

The Soulful Braid, the Agora Commons, and Explainer Films

A focused page within the Metis Features documentation. The full map and every sibling page live in the Features hub.

8sections13 minread1diagram1table

On this page

These three features are V9's "Phase-2 delight & depth" layer (V9_ARCHITECTURE.md §3 P2): the part that turns a correct, grounded lesson into something a learner wants — an experience with an emotional shape, a way for creators to author and share their own journeys, and a watch-don't-poke explainer film when the learner would rather sit back. All three live in a single library, @oshun/v9-theia (libs/v9/theia/src), alongside the wonder-director itself; the package is named for Theia, the Titaness of sight and the "wonder director" who orchestrates awe. The library is small and dense — six source files, one ~9 KB spec — and every function in it composes a real substrate: the live Atlas graph (@oshun/v9-atlas), the real Mnemosyne mastery ladder (@mnemosyne/core), and the V9 contract vocabulary (@oshun/contracts). What it does not do is fabricate the parts it cannot compute: the avatar/face runtime, the headless widget browser, and the Manim renderer are all expressed as typed, fail-loud boundaries that a real service plugs into. This is the feature-side companion to the section hub — ../V9_features.md.

The through-line connecting the braid, the commons, and the films is the same idea Theia exists to serve: a lesson never dead-ends. The emotional arc closes on the next question; Agora lets a learner-turned-creator pin that next question into a publishable journey; and the explainer film is just another shareable social object minted from a verified lesson. Everything here is downstream of the Prometheus lesson forge and the Atlas, and gated by the same seven gates every lesson passes before a learner sees it.

What ships, honestly#

The logic in @oshun/v9-theia is real and tested — all six modules, exercised by theia.spec.ts (the spec covers thread continuation, the emotional arc, surprise-me, the widget verifier's ship/block/fail-loud paths, the Manim self-repair loop, the HITL state machine + budget, Agora authoring + share objects, and Chiron-full memory + personas). The functions are not CRUD: they walk the real Atlas edge set, index into the real six-level Dreyfus mastery ladder, parse outputs through the real V9ExplorableSchema, and compute real sha256 provenance hashes.

What is boundary / injected (real interface, no production adapter wired in this package): the HeadlessWidgetRunner that proves a generated widget reaches its success state, the ManimRenderer that renders the film, and — for Chiron-full — the embodied face + emotion-recognition runtime (Psyche). For the Manim renderer specifically, the other half already exists: a genuine 436-line Python render service at services/metis/src/metis/media/manim_render_service.py invokes the manim CLI in a sandboxed subprocess (rlimits, wall-clock timeout, session isolation) and returns structured {syntax,runtime,timeout,unknown} failures whose data model "mirrors the TS ManimRenderRequest contract" (manim_render_helpers.py). The missing piece is the TS↔Python adapter; each half is real, the bridge is not yet in code.

What is spec / aspirational at this seam: Agora's buildShareableObject imports nothing from V7 Mawu distribution or Sekhmet safety — it builds an OpenGraph-ready share descriptor with a templated metis.oshun/share/... URL; the actual safety-gated publish ride is the design's promise, not this function's behavior. And critically, no production code imports @oshun/v9-theia yet — a repo-wide grep for the package turns up only its own spec. The V9 experience layer ships its own simpler thread and surprise-me (libs/v9/experience/src/lesson-player.ts reads a precomputed thread.nextWonders off the lesson artifact; wonder-front-door.ts does an adjacency-based "surprise me"). Theia is the richer, graph-driven version of those ideas, fully built and tested, awaiting wiring into the runtime. Where this page says "Theia threads across the Atlas," read it as "the tested library does this; the running player does not call it yet." Honest "built-but-unwired" beats fake "shipped."

The soulful braid — Theia's emotional arc and thread continuation#

The "soulful braid" the design asks for — science set beside the human, awe set beside understanding — is, at the code level, three small orchestration functions in theia.ts.

Thread continuation (nextWonders)#

nextWonders(atlas, from, max = 3) answers "what better question does this concept open?" by walking the real Atlas edge set in a fixed priority order (theia.ts:17):

ts
const THREAD_EDGE_PRIORITY = ['enables', 'bridges', 'specializes', 'related'];

Of the nine V9ConceptEdgeType values in the contract (prerequisite, related, part_of, generalizes, specializes, enables, conflicts, complements, bridges), the thread deliberately uses only four — and they are the forward ones. It never threads back into a prerequisite (that is remediation, not a next wonder), never offers a conflicts edge as a thread, and prioritizes enables (this unlocks that) over bridges (a cross-axis jump) over specializes over a loose related. The function throws on an unknown source concept, dedups by target id, and slices to max. The spec pins the priority behavior precisely: an enables edge to "Age of the universe" beats a related edge to "Cosmic microwave background," so the Olbers'-paradox thread proposes the age of the universe first (theia.spec.ts:59).

The bridges edge is where the braid lives structurally. The contract defines it as "a cross-axis thread, e.g. cosmology ↔ deep-time" (concept-graph.ts:87), and V9 organizes reality along seven wonder axescosmos, laws, mind, meaning, deep-time, living-world, made-world (primitives.ts:42). A bridges edge from a cosmos node to a meaning or mind node is the "science next to the human" juxtaposition, and because bridges sits second in the thread priority, Theia will surface it. What is not in this package is the curated content that fills those bridge edges — the meditation session beside the neuroscience-of-attention thread, the Hathor myth beside the cosmology lesson, the Nisaba source text beside it. Those are design promises; the structural seam (the bridge edge + its place in the thread priority) is what ships today.

The emotional arc (orchestrateEmotionalArc)#

The arc tags a lesson's narrative beats with one of four emotions — awe → curiosity → understanding → anticipation — by pattern (theia.ts:63): the opening beat (or any /hook/i) is awe, a /why it matters|connect/i beat is understanding, a /next question|the next/i beat is anticipation, the last beat defaults to anticipation, and everything between is curiosity.

This looks like a toy until you read what produces the beats. The Prometheus planner emits exactly this phrasing (libs/v9/prometheus/src/plan.ts):

ts
const beats = [
  `Hook: ${input.wonder}`,
  ...claims.map((c, i) => `Establish[${i}]: ${c.text}`),
  'Why it matters: connect the established facts back to the wonder.',
  'The next question: open the thread to the next, better wonder.',
];

The arc's regexes are tuned to the forge's beat vocabulary: Hook: → awe, Why it matters: connect → understanding, The next question: → anticipation. So even though @oshun/v9-theia does not yet import the planner, the two were written to compose — the arc is designed to run over a real Prometheus lesson plan, opening on awe and closing on the next question. (The shared default persona chiron:warm-generalist is the same constant on both sides — plan.ts and Agora's toPrometheusDirectives — another deliberate alignment.)

Surprise me (surpriseMe)#

surpriseMe(atlas, masteryMap, max = 1) finds "a wonder you didn't know you had, from the frontier of what you almost know." For every concept the learner has not mastered but which has at least one prerequisite, it computes readiness = masteredPrereqs / totalPrereqs, keeps the ones with 0 < readiness ≤ 1, sorts descending, and returns the top max. "Mastered" here means the learner's level is ≥ intermediateMASTERED_FLOOR = MASTERY_LEVELS.indexOf('intermediate') (index 2 of the six-level Dreyfus ladder novice, beginner, intermediate, advanced, expert, master, libs/mnemosyne/core/src/types.ts:154). The prerequisite set comes from the real Atlas, which delegates closure to the Mnemosyne KnowledgeGraph rather than reimplementing it (atlas-store.ts:146). The spec drives a learner who has mastered "Light" toward "Olbers' paradox" at readiness === 1 — every prerequisite satisfied, the highest-readiness unexplored frontier (theia.spec.ts:75).

The Agora commons — author, then share#

Agora (agora.ts) is the creator loop: a learner or educator steers the forge to author a guided journey, and the result becomes a shareable social object — the free-tier growth lever the product analysis calls for.

Authoring a journey (GuidedJourneySpec → directives)#

A creator's choices are a GuidedJourneySpec: { creatorId, topic, tone, depth, audience }, where tone ∈ {playful, rigorous, poetic, socratic}, depth ∈ {intro, standard, deep}, and audience ∈ {kids, teens, adults, experts}. validateJourneySpec enforces two real rules: a topic under three trimmed characters is rejected, and deep depth for a kids audience is refused — a small but genuine age-appropriateness guard at authoring time, before anything reaches the forge.

toPrometheusDirectives maps the authoring intent onto forge directives:

Depth maxConcepts targetSuccess
intro 3 0.80
standard 6 0.75
deep 12 0.70

The targetSuccess is a flow-band target, and note the direction: a deeper journey aims at a lower predicted success rate (0.70), i.e. it is allowed to be harder — that is the difficulty-in-the-flow-channel idea expressed as a number. The personaHint maps tone to a Chiron persona ref (chiron:playful, chiron:rigorous, chiron:poetic), with socratic collapsing to the warm generalist (chiron:warm-generalist). Be precise about what this is: the emitted PrometheusDirectives ({ topic, targetSuccess, maxConcepts, personaHint }) is not the same shape as the forge's LessonPlanInput ({ wonder, conceptSet, groundTruth, ... }). It is an authoring-intent object — a structural seam that a forge front-door would consume to drive planning and ground-truth assembly — not a literal call into planLesson. See the Prometheus lesson forge for what the directives would steer.

The shareable object (buildShareableObject)#

buildShareableObject mints a ShareableObject for either kind of social artifact — explorable or explainer-film — carrying { kind, lessonId, conceptId, title, url, ogDescription }. The url is a deterministic https://metis.oshun/share/<kind>/<encoded-lessonId> and the ogDescription is a templated OpenGraph card line ("Explore … — a grounded, interactive … from Metis"). This is honestly a descriptor builder: the function produces the metadata an OG card or a deep link needs, and nothing more. The module header describes publishing as riding "V7 Mawu distribution + Sekhmet (the injected boundary)," but the code imports neither — the safety review and the distribution ride are the design's promise, layered on by governance and boundaries, not behavior in this function.

On-demand explainer films — the Manim self-repair driver#

manim.ts is the precise-STEM explainer-film driver: a NotebookLM-style video overview, but computed-correct, because it renders only from a verified Kalika derivation, never from prose.

renderExplainerFilm(request, renderer?, options) takes a ManimRenderRequest ({ conceptId, title, derivation: string[] }) and:

  1. Fails loud with ManimNotConfiguredError if no renderer is wired — it will not silently no-op.
  2. Refuses an empty derivation — "refusing to render an explainer film from an empty (unverified) derivation." No verified math, no film. This is the anti-fabrication contract at the film boundary.
  3. Runs a self-repair loop up to maxAttempts (default 3), passing the 1-based attempt count into renderer.render(request, attempt) so a render service can see how many times it has failed and self-correct — the reliability pattern the 2026 Manim-from-LLM literature requires (V9_SOTA_RESEARCH.md §2).
  4. On success, computes a C2PA content hashsha256 over [conceptId, derivation, assetRef] — binding the film to the exact verified derivation that produced it, and returns { rendered: true, film: { assetRef, attempts, c2paContentHash } }.
  5. On exhaustion returns { rendered: false, attempts, lastError } — a structured failure, never a thrown crash mid-loop.

The spec exercises all four edges: retry-then-succeed (attempt 2 wins, calls === 2), give-up-after-maxAttempts, refuse-empty-derivation, and fail-loud-with-no-renderer (theia.spec.ts:127).

The ManimRenderer is the injected boundary, and its real counterpart already exists in Python. ManimRenderService (manim_render_service.py) discovers a manim binary (via PATH or the repo-local services/metis/.venv-manim), builds a manim render argv (build_render_command), runs it in a forked subprocess with CPU and address-space rlimits and a wall-clock ceiling (with_timeout_ceiling), classifies any non-success into a structured RenderError of kind syntax | runtime | timeout | unknown, and locates the produced video artifact (locate_video_artifact) — even treating "returncode 0 but no artifact" as a failure ("the render lied about success"). The helpers module states outright that RenderJob "mirrors the TS ManimRenderRequest contract," so the two halves were co-designed. What is missing is the adapter that implements the TS ManimRenderer interface by calling this service over HTTP or subprocess; until it exists, renderExplainerFilm is real, the Python renderer is real, but the end-to-end TS render is unwired.

A word on C2PA: the hash computed here is real and is the determinism/provenance binding (gate G7) a C2PA manifest would carry, but this driver does not sign a manifest — that cryptographic step is the V3 C2PA remainder. The explorable provenance contract makes the distinction explicit: c2paSigned defaults to false (explorable.ts:95) and only flips true once a real signer runs.

Generative widgets — the same discipline, for ideas without a kernel#

For concepts with no computed kernel, Prometheus can generate a runnable web widget; generative-widgets.ts is the verifier that decides whether it may ship. verifyGenerativeWidget(spec, runner?) fails loud without a HeadlessWidgetRunner, then runs the widget headlessly and blocks it unless it both compiles and reaches its declared success state. Only on a demonstrated success does it parse a real V9Explorable through V9ExplorableSchema with kind: 'generative-widget', successState.reachable: true (plus the runner's evidence string), a grounding pin (sourceId: 'iris:widget-gen', credibility: 0.6), and a provenance block (contentHash = sha256(code), c2paSigned: false). This is the contract's bright line at work: reachable "is set true only after the success state was actually demonstrated … never asserted blind" (explorable.ts:73), and isV9ExplorableShippable returns exactly successState.reachable. A generated-but-unverified widget never ships — and the HeadlessWidgetRunner has no production implementation anywhere yet, so this verification logic is real and tested but not yet running against a real browser. The explorable runtime that hosts the shipped widget lives next door in Chiron and Hephaestus.

Mid-pipeline control: HITL and the per-step budget#

hitl.ts is the human-in-the-loop control plane the forge runs under. HitlSession is a real state machine over running | paused | redirected | resumed | failed | recovered: you may pause only from running/resumed; redirect(direction) only from paused and only with a non-empty direction (this is regenerate-with-direction); resume from paused/redirected; and recover only from failed, where checkpoint-restore returns the latest HitlCheckpoint and replan returns null (start the stage fresh). Illegal transitions throw rather than silently passing. enforceStepBudget(spent, stepCap, requested) is the cost guard: it rejects a negative request, allows a step only if spent + requested ≤ stepCap, and reports the remaining budget. Together these are the seam the platform Yemaya HITL fix plugs into — a pipeline that can be paused, steered, resumed, budget-capped, and recovered from a checkpoint mid-flight.

Chiron-full: cross-session memory and grounded historical personas#

chiron-full.ts is the glue that complements the base Chiron persona library (@oshun/v9-chiron: getChironPersona, integrity modes, delivery). It does two things, both pure logic.

Cross-session memory. buildSessionMemory(traces) partitions the learner's concept traces into struggledConcepts (mastery ≤ beginner) and masteredConcepts (mastery ≥ advanced) — note these floors differ from surprise-me's intermediate floor, because "open the session on it" and "ready for the frontier" are different bars. chironOpeningLine(memory) then opens a returning learner on what was tricky last time ("Last time, Tensor calculus was tricky — want to revisit it before we go further?"), or acknowledges progress, or falls back to a warm "What are you wondering about today?". This is the Mnemosyne trace projected into Chiron's opening turn.

Grounded historical personas. buildHistoricalPersona enforces the anti-fabrication and consent rules for "Chiron as a historical figure." It throws UngroundedPersonaError if there is no Nisaba source pin (no invented personal claims — the persona may say nothing the sources don't ground), always attaches a reconstructionLabel ("Reconstruction of X, bounded by historical sources — not the real person."), and refuses a living-voice persona without a consent record (the V3 voice-clone registry / Sekhmet gate). The embodied face and emotion recognition (Psyche) is the provider-gated runtime remainder; this module ships the memory and persona-safety logic only. The full mentor surface — voice, face, integrity modes, Socratic dialogue — is documented in Chiron and Hephaestus.

How it fits together#

The diagram below traces a creator's authoring choice through the forge and out to the two shareable artifacts, marking which seams are real-and-tested (solid) and which are injected boundaries (dashed):

flowchart TD A[Creator: GuidedJourneySpec<br/>topic · tone · depth · audience] -->|validateJourneySpec| B{ok?} B -->|kids+deep / topic<3 → reject| X[blocked at authoring] B -->|ok| C[toPrometheusDirectives<br/>maxConcepts · targetSuccess · personaHint] C -.authoring-intent seam.-> D[Prometheus forge<br/>plan · ground-truth · gates G1–G7] D --> E[orchestrateEmotionalArc<br/>awe→curiosity→understanding→anticipation] D --> F[nextWonders / surpriseMe<br/>thread across the Atlas] D --> G[verifyGenerativeWidget] D --> H[renderExplainerFilm<br/>self-repair loop ≤3] G -.HeadlessWidgetRunner.-> G2[(headless browser<br/>boundary)] H -.ManimRenderer.-> H2[(Metis manim service<br/>real Python, unwired)] G --> I[V9Explorable<br/>reachable=true] H --> J[ExplainerFilm<br/>c2paContentHash] I --> K[buildShareableObject] J --> K K -.Mawu + Sekhmet.-> L[(safety-gated publish<br/>boundary)]

The solid edges are the tested logic in @oshun/v9-theia; the dashed edges are the three boundaries — the headless widget runner, the Manim render service (real, but unbridged), and the Mawu/Sekhmet publish ride — that a running V9 supplies.