Clio, for developers and agents.
A ~12-14 minute architectural onboarding tour of the Mnemosyne Research Institute's civic-intelligence apparatus. Aimed at future Claude sessions opening this repo cold and at human contributors writing a first artifact. Walks the doctrine (rendered civic intelligence, the 25 non-negotiable invariants), the Stagehand command surface (~50 commands across 14 areas, demonstrated live), the typed registry (12,600+ curated entities plus a 200K+ open-data shard via ADR-0011), the 5-layer runtime validator, the public/private boundary, the deterministic render pipeline, the 8-phase script-writing workflow (database-first, MCP-driven), the trust hierarchy (Gold Master through Session Draft), and the multi-agent src/artifacts/ layout. Closer points at the four documents that actually onboard you: CLAUDE.md, docs/reference/stagehand.md, docs/registry/script-writing-workflow.md, and docs/reference/script-authoring.md.
Sources (4)
| Source | Score |
|---|---|
| Clio editorial frame — What is Clio (viewer + developer episodes) Mnemosyne Research Institute | 60% |
| Stagehand command vocabulary (canonical reference) Mnemosyne Research Institute | 70% |
| Script-writing & MP4-export workflow (the 8 phases) Mnemosyne Research Institute | 70% |
| Clio doctrine — CLAUDE.md, civic-intelligence, showrunner ADRs Mnemosyne Research Institute | 70% |
Full Script
Narration + Stagehand commands
Commands like [map.highlight] are
Stagehand directives — they control the map renderer and pass through schema validation
before any visual effect reaches the public output.
[camera.establish_globe lat=22 lon=0 zoom=1.45] [map.basemap kind=dark] [scene.fade color="#020617" opacity=0.2 duration=500] [scene.title kind=intro eyebrow="CLIO AGIS" title="Clio, for developers and agents." subtitle="A tour of the apparatus. Doctrine, command surface, validator, render pipeline, agent layout."] [mark.clip type="hook"] If you are an agent or a developer opening this repository cold, welcome. The next twelve minutes are your onboarding tour. Every primitive this episode explains is also being fired on screen as the explanation lands. [scene.title kind=clear] [scene.fade opacity=0 duration=500] [chat.say source="clio_internal_doctrine_reference_2026"] [source.show id="clio_internal_doctrine_reference_2026"] The codebase root has a CLAUDE.md and a clio-master-plan.md. The docs tree has doctrine, reference, specs, registry, and history. This episode does not replace those documents. It orients you to them. [scene.title kind=chapter title="Doctrine" subtitle="Rendered civic intelligence. Twenty-five non-negotiable invariants."] [map.basemap kind=dark] [camera.establish_globe lat=20 lon=0 zoom=1.55] [chat.say source="clio_internal_doctrine_reference_2026"] The product is not a chatbot with a map. It is a private production room that emits validated, sourced, inspectable public events. The database is the intelligence. The renderer is the body. The model proposes; validators commit; the public stream replays without model calls. [whiteboard.show title="Seven of the twenty-five non-negotiables" subtitle="The full list lives in CLAUDE.md. These are the ones the validator enforces every frame." style=grid background="#020617" opacity=0.95] [whiteboard.text id="inv-rule" x=50 y=18 text="Rules the validator enforces every frame" size=md color="#f8fafc"] [whiteboard.text id="inv-1" x=14 y=36 text="1 · raw tokens never reach UI" size=sm color="#dcfce7"] [whiteboard.text id="inv-2" x=14 y=46 text="2 · tool-call JSON never reaches chat" size=sm color="#dcfce7"] [whiteboard.text id="inv-7" x=14 y=56 text="7 · every source card from a real Source" size=sm color="#dcfce7"] [whiteboard.text id="inv-8" x=14 y=66 text="8 · every map effect from validated Stagehand" size=sm color="#dcfce7"] [whiteboard.text id="inv-10" x=56 y=36 text="10 · uncertainty cannot be erased" size=sm color="#dcfce7"] [whiteboard.text id="inv-14" x=56 y=46 text="14 · validated shows replay without model calls" size=sm color="#dcfce7"] [whiteboard.text id="inv-15" x=56 y=56 text="15 · exports generated from trace, not live output" size=sm color="#dcfce7"] [whiteboard.box id="inv-rule-box" x=50 y=82 width=70 height=12 color="#22c55e" opacity=0.16 label="the system is built so these hold"] [asset.show id="asset:clio_key_invariants" x=50 y=72 anchor=center width="74vw" maxHeight="22vh" fadeIn=320 fadeOut=260] These seven are the load-bearing ones. The other eighteen are listed in CLAUDE.md. Treat the whole list as PR-review rules — not aspirations. [asset.clear fadeOut=260] [whiteboard.hide] [whiteboard.clear] [scene.title kind=chapter title="The Command Surface" subtitle="Stagehand — ~50 commands across 14 areas."] [map.basemap kind=light] [camera.center target="city:new_york" zoom_level=regional padding=110] [chat.say source="clio_internal_stagehand_reference_2026"] [source.show id="clio_internal_stagehand_reference_2026"] The narrator emits typed stage directions inline in narration text. They look like this — bracketed actions with optional positional arguments and keyword arguments. The parser extracts them, the validator rejects malformed ones, the canonicalizer resolves entity refs, the reducer mutates scene state, and the renderer paints. [asset.show id="asset:clio_command_surface" x=50 y=58 anchor=center width="78vw" maxHeight="50vh" fadeIn=320 fadeOut=260] About fifty commands across fourteen surface areas. [asset.clear fadeOut=260] Watch some of them work. [camera.center target="city:new_york" zoom_level=regional padding=120] [map.highlight entity="city:new_york" color="#22c55e" opacity=0.55 pulse=true] [map.label entity="city:new_york" text="map.highlight + map.label"] That just fired a highlight and a label. [map.circle entity="city:new_york" color="#22c55e" radius="medium"] That fired a circle. [map.arrow from="city:new_york" to="strait:hormuz" color="#fbbf24"] That fired a great-circle arrow from New York to the Strait of Hormuz. [camera.center target="strait:hormuz" zoom_level=regional padding=110] [map.highlight entity="strait:hormuz" color="#fbbf24" opacity=0.8 pulse=true] [flow.animate route="gulf:persian_gulf->strait:hormuz->ocean:indian_ocean" color="#f59e0b"] [map.label entity="strait:hormuz" text="flow.animate"] That is an animated flow along a multi-waypoint route. [map.clear annotations] [flow.clear] [camera.center target="city:new_york" zoom_level=local padding=95] [piece.place id="demo:public-worker-alpha" asset="piece:infantry_unit" entity="public_institution:nyc_dot" label="public-works crew" status=active] That placed a globe-anchored piece — usually used for OSINT units, here standing in for a public-works crew at NYC DOT. [piece.clear] [map.clear annotations] [camera.center target="city:new_york" zoom_level=regional padding=110] [layer.on populated_places] A layer toggle just turned on the populated-places dataset. The renderer reads from a registered overlay schema and either paints or stages — depending on what is wired. [layer.off populated_places] [camera.establish_globe lat=20 lon=0 zoom=1.6] [map.basemap kind=satellite] A basemap swap moves the bottom raster layer from streets to satellite. The full basemap registry lives in src slash atlas slash overlays slash basemaps dot ts. [map.basemap kind=dark] Every one of those primitives just fired off a single bracketed command. The validator caught nothing because every entity resolved through the registry. If any reference had failed, the system would have surfaced an unresolved-ref event instead of painting. [scene.title kind=chapter title="The Registry" subtitle="12,600 curated entities. 200K open-data on demand. 87K dams. 34K power plants. 7.6K airports. Watersheds down to HUC12."] [map.basemap kind=light] [camera.center target="city:new_york" zoom_level=regional padding=110] [chat.say source="clio_internal_doctrine_reference_2026"] The truth surface is the typed registry. Every map effect routes through it. [asset.show id="asset:clio_registry_shards" x=50 y=58 anchor=center width="78vw" maxHeight="38vh" fadeIn=320 fadeOut=260] ADR-0011 split the substrate into two shards. clio-core loads on boot. clio-bulk loads when a script asks for an entity it owns. [asset.clear fadeOut=260] [camera.center target="strait:hormuz" zoom_level=regional padding=120] [map.highlight entity="strait:hormuz" color="#fbbf24" opacity=0.7] [map.label entity="strait:hormuz" text="curated"] A strait like Hormuz is curated in core. [map.clear annotations] [camera.center target="city:new_york" zoom_level=local padding=95] [map.highlight entity="public_institution:new_york_public_library" color="#22c55e" opacity=0.85 pulse=true] [map.label entity="public_institution:new_york_public_library" text="curated"] NYPL is curated in core. [map.clear annotations] [camera.center target="public_institution:laguardia_airport" zoom_level=local padding=95] [map.highlight entity="public_institution:laguardia_airport" color="#fbbf24" opacity=0.85 pulse=true] [map.label entity="public_institution:laguardia_airport" text="curated · airport stub"] LaGuardia is curated as a public-institution because there is no airport entity type yet — the OpenFlights bulk shard could provide a richer record, on demand. [map.clear annotations] [camera.establish_globe lat=38 lon=-98 zoom=3.8] [layer.on admin1_regions] The bulk shard has scale a curated list never could. Three thousand two hundred counties. Thirty-two thousand populated places. Eighty-seven thousand dams from the National Inventory of Dams. Thirty-four thousand power plants from the World Resources Institute. Seven thousand six hundred airports from OpenFlights. And a watershed hierarchy from HUC two down to HUC twelve — sub-basins, catchments, headwaters, all resolved through the same entity surface. [layer.off admin1_regions] [map.fit entities="watershed:huc4_1704,watershed:huc4_1802" padding=100 maxZoom=5] [map.highlight entity="watershed:huc4_1704" color="#38bdf8" opacity=0.55] [map.highlight entity="watershed:huc4_1802" color="#38bdf8" opacity=0.4] [map.label entity="watershed:huc4_1704" text="HUC4 · Upper Colorado"] Those two are HUC-four watersheds in the Colorado system. Zoom one level and you reach HUC-six. Two more and you reach a named catchment. The same entity type, the same lookup, the same map effect — just a different scope. [map.clear annotations] [camera.establish_globe lat=22 lon=0 zoom=1.55] The MCP server runs both channels as a single tool surface — twenty-seven tools. Entity search, source search, asset list, stagehand validate, schema discovery, propose write-side. When you draft a script, the MCP server is what makes the database talk back. [scene.title kind=chapter title="The Validator" subtitle="Five runtime layers. Nothing paints that has not passed all five."] [map.basemap kind=dark] [camera.establish_globe lat=22 lon=0 zoom=1.6] [chat.say source="clio_internal_stagehand_reference_2026"] A command does not paint because the model emitted it. It paints because it passed five layers. [asset.show id="asset:clio_runtime_layers" x=50 y=58 anchor=center width="78vw" maxHeight="42vh" fadeIn=320 fadeOut=260] The parser is syntactic. The validator is schematic. The canonicalizer is referential. The runtime emits typed events. Only scene_command events enter the reducer. [asset.clear fadeOut=260] [whiteboard.show title="The validator boundary" subtitle="On the model side: proposals. On the user side: paint." style=grid background="#020617" opacity=0.95] [whiteboard.text id="val-prop" x=22 y=32 text="model emits a command" size=sm color="#fecaca"] [whiteboard.box id="val-prop-box" x=22 y=48 width=22 height=18 color="#ef4444" opacity=0.16 label="proposal"] [whiteboard.text id="val-gate" x=50 y=32 text="five-layer validation" size=sm color="#fbbf24"] [whiteboard.box id="val-gate-box" x=50 y=48 width=22 height=18 color="#fbbf24" opacity=0.18 label="gate"] [whiteboard.text id="val-paint" x=78 y=32 text="paint on the map" size=sm color="#dcfce7"] [whiteboard.box id="val-paint-box" x=78 y=48 width=22 height=18 color="#22c55e" opacity=0.16 label="public effect"] [whiteboard.line id="val-line-1" x1=33 y1=57 x2=39 y2=57 color="#ef4444" stroke=5] [whiteboard.line id="val-line-2" x1=61 y1=57 x2=67 y2=57 color="#22c55e" stroke=5] [whiteboard.text id="val-bottom" x=50 y=78 text="Invalid commands surface as runtime errors, never as painted state." size=md color="#e0f2fe"] That is the trust transducer. The model proposes; the validator decides; only validated commands ever reach scene state. [whiteboard.hide] [whiteboard.clear] [scene.title kind=chapter title="The Public Private Boundary" subtitle="Raw tokens stay backstage. The public show is a separate event stream."] [chat.say source="clio_internal_doctrine_reference_2026"] [map.basemap kind=light] [camera.establish_globe lat=22 lon=0 zoom=1.55] Inside a production run there is a private stream and a public stream. [whiteboard.show title="Two streams" subtitle="One backstage. One on the air." style=grid background="#020617" opacity=0.95] [whiteboard.text id="ps-title" x=24 y=22 text="PRIVATE" size=lg color="#fecaca"] [whiteboard.text id="ps-list" x=24 y=38 text="agent tokens" size=sm color="#fecaca"] [whiteboard.text id="ps-list2" x=24 y=44 text="tool-call JSON" size=sm color="#fecaca"] [whiteboard.text id="ps-list3" x=24 y=50 text="rejected drafts" size=sm color="#fecaca"] [whiteboard.text id="ps-list4" x=24 y=56 text="repair loops" size=sm color="#fecaca"] [whiteboard.text id="ps-list5" x=24 y=62 text="mutation proposals" size=sm color="#fecaca"] [whiteboard.text id="ps-list6" x=24 y=68 text="audit notes" size=sm color="#fecaca"] [whiteboard.box id="ps-box" x=24 y=52 width=30 height=42 color="#ef4444" opacity=0.14 label="backstage"] [whiteboard.text id="pub-title" x=72 y=22 text="PUBLIC" size=lg color="#dcfce7"] [whiteboard.text id="pub-list" x=72 y=38 text="status messages" size=sm color="#dcfce7"] [whiteboard.text id="pub-list2" x=72 y=44 text="validated narration" size=sm color="#dcfce7"] [whiteboard.text id="pub-list3" x=72 y=50 text="captions" size=sm color="#dcfce7"] [whiteboard.text id="pub-list4" x=72 y=56 text="validated stagehand effects" size=sm color="#dcfce7"] [whiteboard.text id="pub-list5" x=72 y=62 text="source + gap cards" size=sm color="#dcfce7"] [whiteboard.text id="pub-list6" x=72 y=68 text="show completion" size=sm color="#dcfce7"] [whiteboard.box id="pub-box" x=72 y=52 width=30 height=42 color="#22c55e" opacity=0.14 label="on the air"] The production orchestrator routes every event into one stream or the other. ProductionRun, PrivateProductionEvent, PublicShowEvent — they are in src slash production slash types dot ts. The most important rule that comes out of this is invariant one. Raw model tokens never reach normal user UI. Ever. If you ever find a code path that lets a raw token leak into chat, captions, or TTS — that is a P0 bug. [whiteboard.hide] [whiteboard.clear] [scene.title kind=chapter title="The Render Pipeline" subtitle="Script → renderPlan → headless capture → ffmpeg compose → MP4."] [map.basemap kind=dark] [camera.establish_globe lat=22 lon=0 zoom=1.55] [chat.say source="clio_internal_doctrine_reference_2026"] The episode you are watching is not coming from a live model. It came from a script.ts file, deterministically. [whiteboard.show title="The render chain" subtitle="Five steps, each in its own module under scripts/lib/export." style=grid background="#020617" opacity=0.95] [whiteboard.text id="rp-1" x=12 y=32 text="script.ts" size=sm color="#e2e8f0"] [whiteboard.box id="rp-box-1" x=12 y=50 width=14 height=14 color="#38bdf8" opacity=0.16 label="author"] [whiteboard.text id="rp-2" x=32 y=32 text="renderPlan" size=sm color="#e2e8f0"] [whiteboard.box id="rp-box-2" x=32 y=50 width=14 height=14 color="#38bdf8" opacity=0.16 label="plan"] [whiteboard.text id="rp-3" x=52 y=32 text="browser capture" size=sm color="#e2e8f0"] [whiteboard.box id="rp-box-3" x=52 y=50 width=14 height=14 color="#22c55e" opacity=0.16 label="paint"] [whiteboard.text id="rp-4" x=72 y=32 text="ffmpeg compose" size=sm color="#e2e8f0"] [whiteboard.box id="rp-box-4" x=72 y=50 width=14 height=14 color="#f59e0b" opacity=0.16 label="encode"] [whiteboard.text id="rp-5" x=90 y=32 text="MP4" size=sm color="#e2e8f0"] [whiteboard.box id="rp-box-5" x=90 y=50 width=10 height=14 color="#22c55e" opacity=0.16 label="ship"] [whiteboard.line id="rp-line-1" x1=20 y1=57 x2=26 y2=57 color="#38bdf8" stroke=4] [whiteboard.line id="rp-line-2" x1=40 y1=57 x2=46 y2=57 color="#38bdf8" stroke=4] [whiteboard.line id="rp-line-3" x1=60 y1=57 x2=66 y2=57 color="#22c55e" stroke=4] [whiteboard.line id="rp-line-4" x1=80 y1=57 x2=86 y2=57 color="#f59e0b" stroke=4] [whiteboard.text id="rp-bottom" x=50 y=78 text="Same script + same registry = bit-identical MP4. That is invariant fourteen." size=md color="#e0f2fe"] RenderPlan turns the script into a deterministic timeline. The browser-capture step paints each segment with paint-time audio sync — the export pipeline reads the actual paint offsets the player emits and places each TTS clip at the captured moment. Then ffmpeg composes frames and audio into the MP4 you are watching. The cmdline can overflow on Windows when there are hundreds of narration clips, so the compose step falls back to filter-script files with movie filter sources to stay under the CreateProcess cap. [whiteboard.hide] [whiteboard.clear] [scene.title kind=chapter title="The Script Writing Workflow" subtitle="Database first. Script second."] [map.basemap kind=light] [camera.center target="city:new_york" zoom_level=regional padding=110] [chat.say source="clio_internal_workflow_reference_2026"] [source.show id="clio_internal_workflow_reference_2026"] The canonical workflow inverts the obvious one. The database is the source of truth. The script is written in relationship to it, not the other way around. [asset.show id="asset:clio_8_phase_workflow" x=50 y=58 anchor=center width="80vw" maxHeight="50vh" fadeIn=320 fadeOut=260] Eight phases. Each one has a quality gate. The script does not get written until the registry has every entity, source, and asset it is going to cite. If you draft a sentence about a place — call entity dot resolve first. If it hits, use the canonical id. If it misses, stop drafting and finish phase three for that id. The MCP server makes that loop fast enough to do per sentence. [asset.clear fadeOut=260] [map.clear annotations] [scene.title kind=chapter title="The Trust Hierarchy" subtitle="Gold Master → Verified Import → Project Overlay → User Assumption → Session Draft."] [map.basemap kind=light] [camera.establish_globe lat=22 lon=0 zoom=1.55] [chat.say source="clio_internal_doctrine_reference_2026"] Not every fact in the registry has the same weight. There is a tiering. [asset.show id="asset:clio_trust_hierarchy" x=50 y=58 anchor=center width="76vw" maxHeight="40vh" fadeIn=320 fadeOut=260] Public users build project overlays and session drafts. They do not write to the Gold Master. Promotion from overlay to canonical requires the pipeline in ADR-0008. The point is not that overlays are second-class. The point is that the canonical layer is shared infrastructure — and the only way to keep it usable across briefings is to gate writes. [asset.clear fadeOut=260] [scene.title kind=chapter title="Multi-Agent Layout" subtitle="src/artifacts/ is shared territory. Author in your own namespace."] [map.basemap kind=light] [camera.center target="city:new_york" zoom_level=regional padding=110] [chat.say source="clio_internal_doctrine_reference_2026"] The src slash artifacts directory is shared across multiple agents. Each one has a namespace. [whiteboard.show title="Author in your own namespace" subtitle="Touch registry.ts carefully — additions only, don't strip another agent's import." style=grid background="#020617" opacity=0.95] [whiteboard.text id="ml-rule-1" x=50 y=28 text="• sibling artifacts belong to other agents — hands off unless asked" size=md color="#e0f2fe"] [whiteboard.text id="ml-rule-2" x=50 y=40 text="• registry.ts is additive — don't strip another agent's import" size=md color="#e0f2fe"] [whiteboard.text id="ml-rule-3" x=50 y=52 text="• src/atlas/entities/<topic>.ts — use a topic file, don't append to someone else's" size=md color="#e0f2fe"] [whiteboard.text id="ml-rule-4" x=50 y=64 text="• stash-write tools (entity.propose / source.propose / asset.propose) land in llmProposed.ts" size=md color="#e0f2fe"] [whiteboard.text id="ml-rule-5" x=50 y=76 text="• promotion from llmProposed.ts to a topic file requires curator review" size=md color="#e0f2fe"] If you propose a new entity, source, or asset live via the MCP write-side tools, it lands in the llm_proposed stash file — explicitly excluded from the build-time registry, the SQLite export, and the browser runtime until a curator promotes it. That gate is intentional. The whole point of typed civic intelligence is that nothing becomes canonical without review. [whiteboard.hide] [whiteboard.clear] [scene.title kind=chapter title="What To Read. What To Ship." subtitle="The four documents that actually onboard you."] [map.basemap kind=dark] [camera.establish_globe lat=22 lon=0 zoom=1.5] [mark.clip type="payoff"] [chat.say source="clio_internal_doctrine_reference_2026"] If you do not read anything else this week, read these four files. CLAUDE.md at the repo root. That is the doctrine, the invariants, the module map, the working rule. [chat.say source="clio_internal_stagehand_reference_2026"] docs slash reference slash stagehand dot md. That is the canonical command vocabulary — every bracket you can emit and every kwarg it accepts. [chat.say source="clio_internal_workflow_reference_2026"] docs slash registry slash script-writing-workflow dot md. That is the eight-phase loop. Database first, script second. [chat.say source="clio_internal_doctrine_reference_2026"] And docs slash reference slash script-authoring dot md. That is the inline-cue convention — where to put your brackets so the visual lands with the spoken word. Then write a topic file under src slash atlas slash entities, a sources file, an assets file if you need one, a script dot ts, and an exports dot ts. Wire your new artifact into src slash artifacts slash registry dot ts. Run npx vitest run src slash artifacts. Render with npm run export colon artifact. That is the apparatus. Welcome. [scene.title kind=outro eyebrow="CLIO AGIS" title="The Mnemosyne Research Institute" subtitle="The database is the intelligence. The renderer is the body. The validator is the law."]