CineSpine

The append-only event spine, 3-axis discrepancy engine
and multi-camera AI previz studio for film & TV production.

Partner track · ClickHouse Cloud via mcp-clickhouseGemini · Google ADK · Cloud RunGrafana Cloud · the agent, traced

Agentic Cinema: The Blockbuster Hackathon · 2026 · ClickHouse track

The problem

Nothing crashes. Nobody is alerted.
The mistake waits for the conform.

The Office · Intent

What should happen

Screenplay scenes, call sheets, one-liners, actor schedules, shot plans.

The Set · Belief

What crew believe happened

Script supervisor logs, camera reports, sound reports, false-start notes.

The Lab / DIT · Existence

What physically exists

Camera raw clips, offload checksums, poly-WAV tracks, editorial conforms.

  • Script supervisor logs a take as False Start. Sound files it as Good.
  • A roll typo, A120 vs A_0120, silently drops four audio channels.
  • Found weeks later in the post-production conform. The footage is gone.
$0
Typical emergency reshoot when a silent paperwork conflict surfaces in the conform.
0 versions of reality
Office, Set and Lab each keep their own truth. No system compares them.
“A document is a witness. Witnesses disagree, and the disagreement is the product.”
The idea

Three axes. One immutable ledger.
Every disagreement becomes a first-class record.

DISCREPANCYappend-only eventINTENTOffice · ScriptBELIEFSet · Crew logsEXISTENCEDIT · Storage
Principle

Documents are witnesses, not truth

Every upload is appended as an immutable, sequenced, typed event. Nothing is edited. Nothing is overwritten. Reconciliation runs across the witnesses and writes the disagreement down.

Belief ⟷ Existence

PAPERWORK_WITHOUT_MEDIA

Clip logged on set, missing from the offload report.

Existence ⟷ Belief

MEDIA_WITHOUT_PAPERWORK

File exists on the volume, referenced by no camera or sound log.

Belief ⟷ Belief

TIMECODE_DRIFT

Script supervisor 14:05:00:00 vs sound 14:05:00:12. Twelve frames.

  • Also caught: shoot-date disagreement, roll-name collisions, circled take absent from the plan, wild tracks with no slate.
  • Every finding carries its witness cards: who said what, on which axis, with the roll and circled flag.
System architecture

One Cloud Run service. Three partner backbones.

CineSpine animated end-to-end architecture: producers, FastAPI gateway, event spine, ClickHouse, Gemini, Grafana
Interactive diagram 1 / 3 · runtime

Runtime: where a request goes, and who may touch what

CineSpine runtime architecture: browser SPA, Cloud Run API, spine.db, ClickHouse mirror, Vertex AI Gemini, cinespine-mcp, Grafana Cloud, Secret Manager and the Litestream replica bucket inside the cinespine-run trust boundaryopen interactive ↗
Multi-persona event flows

Every department is an independent witness

Animated multi-persona user event flows feeding the append-only event spine
// one immutable, sequenced envelope per action
{
  "sequence_num": 1042,
  "production_id": "DEMO_PRODUCTION",
  "shoot_day": "Day 31",
  "user_role": "SCRIPT_SUPERVISOR",
  "event_type": "TAKE_LOGGED",
  "payload": {
    "slate": "101/1", "take_number": 1,
    "status": "GOOD", "circled": true
  }
}
  • Director / DoP · SCREENPLAY_PARSED CAMERA_ANGLE_ADDED DOP_OPTICS_CONFIGURED
  • Script supervisor · TAKE_LOGGED FALSE_START_RECORDED CIRCLED_TAKE_FLAGGED
  • Sound mixer · SOUND_ALE_INGESTED POLY_WAV_TRACKS_MAPPED WILD_TRACK_LOGGED
  • DIT · CARD_OFFLOAD_VERIFIED CHECKSUM_VALIDATED SILVERSTACK_MANIFEST_INGESTED
  • Editorial · DISCREPANCY_INSPECTED OVERRIDE_APPLIED MASTER_CONFORM_LOCKED
Event spine & live bus

Append in ClickHouse. Push over SSE. Zero polling.

Animated event system: producers publish, ClickHouse spine appends, LiveEventBroker fans out over Server-Sent Events
Publish

POST /api/events/publish

Monotonic sequence_num. Projected into ClickHouse tables (events, takes, discrepancies, requirement_events, user_activity).

Subscribe

GET /api/events/subscribe

Server-Sent Events scoped by production, shoot day and role. @assistant_editor sees editorial; sound sees sound. Cloud Run timeout raised to 3600s so the stream lives.

React

Master Sheet, Discrepancy Matrix, Previz Studio update live

A DIT drops an offload manifest; the assistant editor's discrepancy card resolves on their screen without a refresh.

Interactive diagram 2 / 3 · data flow

From paperwork to agents, five stages, no broker

CineSpine data flow: POST /api/upload, classifier and in-process EventBus topics, IngestionDispatcher, append-only spine_events in SQLite, ClickHouse mirror, cinespine-mcp, Wrap Rescue and AE Queue agents, requirements and LiveEventBroker over SSEopen interactive ↗
Pillar 2 · Set & Editorial Spine

The assistant editor's cockpit: one card per slate, every witness attached

cinespine.curiobox.es
Composed Master Sheet: 15 slate cards for Day 31, each with camera clips, sound files and script supervisor notes
Composed Master Sheet · Day 31 · Sc 1, 2, 27, 27B, 49, 117A. Green card = all three axes agree.
  • Composed Master Sheet (15) · slate cards fusing ZoeLog camera clips, Sound CSV poly-WAVs and the script supervisor's lined notes.
  • Sequences Log Matrix (6) · scene × take grid; circled, wild-track and VFX filters.
  • Card & Roll Map · A001, A120, B039, C005 … which card carried what, and where it was offloaded.
  • Active Discrepancies (10) · the reconciliation output, one click from resolution.
  • Requirements & Alerts · blockers assigned to @dit, @sound_supervisor, with audit fields on resolve.
  • Drop Paperwork · PDF / CSV / ALE / XML ingestion; deterministic parsers, no LLM in the reconciliation path.
3-axis reconciliation engine

Ten open findings on Day 31. Each one names its witnesses.

TIMECODE_DRIFT · 2/1 Take 2

Script Supervisor 14:05:00:00 vs Sound Department 14:05:00:12. Four witness cards: Script (Belief), Sound (Belief), Camera A (Belief), DIT / Silverstack (Existence).

PAPERWORK_WITHOUT_MEDIA · 27/7 Take 2

A120_C002_260728, B039_C002_260728, C005_C002_260728 logged on set, missing from the offload report. Three cameras, one take, one root cause.

MEDIA_WITHOUT_PAPERWORK · A001C099_260831.MOV

Exists on the volume. Referenced by no camera or sound log. The orphan nobody would find until the conform.

Resolution

Resolve / Assign Card appends a DISCREPANCY_RESOLVED event with resolved_by and resolved_at. Diagnose opens the witness diff. The original finding is never deleted.

cinespine.curiobox.es
Active Discrepancies hub showing TIMECODE_DRIFT, PAPERWORK_WITHOUT_MEDIA and MEDIA_WITHOUT_PAPERWORK cards with witness panels
Active Discrepancies (10) · each card lists the departments that testified and on which axis.
Where do we stand

One call says how a production is doing. Eight tools let an agent act on it.

4blockingblocked, open findings
0missinginferred, names its rule
0runningin progress
4lefteditorial needs, untagged
0doneresolved, closed
cinespine.curiobox.es · Productions · DEMO_PRODUCTION · dashboard
Where do we stand card on the production dashboard: most urgent item as headline, five bucket chips with counts, ranked list worst and oldest first with owner and age
Where do we stand tops the production dashboard, straight after Factory Reset → Run Full Demo → one Wrap Rescue run: four blockers, the agent’s Media Without Paperwork requirement for @dit on top, then the reconciler’s three findings. Same answer the WebMCP tool returns.
GET /api/productions/DEMO_PRODUCTION/status
Raw response of GET /api/productions/DEMO_PRODUCTION/status
WebMCP · document.modelContext (W3C draft)

The page is the tool surface

The SPA registers tools on document.modelContext, so a browser agent acts on the page instead of scraping it. Tools resolve through a ref, so an agent always runs the latest React state.

  • navigate_app
  • set_dop_settings
  • generate_dop_test_render
  • select_character
  • trigger_wrap_rescue_agent
  • run_full_demo
  • summarize_production_statusranked status as JSON plus a plain-text summary
  • wipe_all_production_datadestructiveHint, refuses without confirm=true

No shipping browser exposes document.modelContext yet outside Chrome's early preview. Nothing changes for ordinary users.

Pillar 1 · Screenplay & Previz Studio

From the writer's words to a multi-camera coverage plan

cinespine.curiobox.es
Screenplay breakdown with Camera A, B, C setups per scene
3-Camera Previz & Breakdown · Cam A 28mm master · Cam B 50mm medium/OTS · Cam C 85mm profile/macro. Add Cam D crane, E macro, F Steadicam per scene.
  • Ingests .fountain .fdx .pdf .md .txt. Transition slugs (CUT TO:, SMASH CUT TO:) become shot boundaries.
  • Every parse returns a script_id derived from the text plus parse_warnings. A poor parse explains itself instead of presenting as success.
cinespine.curiobox.es
Cast & Character Profiles: six detected characters with Gemini-inferred appearance, wardrobe and facial features, personality radar and dialogue evidence
Cast & Character Profiles (6) · Gemini infers role, appearance, wardrobe, facial features from dialogue and action-line evidence.
  • Validated, not trusted. Descriptions are checked for filler, placeholders and at least one concrete noun; vague output gets one targeted retry, then is reported.
  • Durable. Profiles live in SQLite keyed by script_id; hand edits survive re-upload and restart. Large casts are inferred in concurrent batches; frames are prompted only with the characters in the scene.
Director of Photography studio

Optics that are computed, not decorative

Twelve master DoP presets, a manual matrix, and a viewfinder that does the sensor maths for real.

cinespine.curiobox.es
DoP Optics & Master Styles: preset list (Deakins, Fincher, Fraser, Willis…) and real-time optical viewfinder with extraction, angle of view and depth of field
Real-Time Optical Viewfinder · ARRI ALEXA 35 open gate · 2.39:1 · live compiled generative prompt underneath.
27.99× 11.71 mm
Extraction for 2.39:1 on an ALEXA 35. Largest frame that fits the gate.
0
Gate used, width-limited. Switch to 4:3 and it becomes height-limited at 91.6%.
4608× 1928
Delivered resolution: DCI 4K, 6.07 µm photosites.
0
Horizontal angle of view at 35mm from 2·atan(w / 2f). Not a lookup table.
  • Depth of field from the circle of confusion, c = f² / (N · s), rendered as a live backdrop-filter blur mask. T2.8 at 3.00 m: 2.67–3.42 m.
  • Presets carry Kelvin, key-to-fill ratio and film-stock LUT: Deakins 35mm T2.8 5600K Vision3 500T; Fincher 28mm T2.0 4300K bleach bypass.
  • Per-camera overrides and saved custom presets. The compiled prompt on screen is exactly what is sent to Gemini image generation.
Google Cloud

Gemini for judgement. ADK for agents. Cloud Run for everything.

Cloud Run

One service, one origin

  • FastAPI + React SPA in one image, europe-west4, max-instances=1: one SQLite writer
  • Litestream ships the WAL to gs://cinespine-spine-db every 1s, hourly snapshots; a revision restores before uvicorn starts
  • CINESPINE_RESTORE_GENERATION pins the restore for recovery; Secret Manager holds keys, read by the cinespine-run SA only
  • Second service: self-hosted mcp-clickhouse, scale-to-zero
Gemini · google-genai SDK

Semantic work, routed by cost

  • Character inference, screenplay breakdown, DoP prompt compilation, Wrap Rescue memo
  • llm_router: 4-model fallback on 404 / 429 / 503, cache by prompt hash
  • Ingestion parsers call Document AI, Speech, Video Intelligence for scans, audio and footage
  • Flash for trivial tasks, Pro only when context demands; Vertex AI via GOOGLE_GENAI_USE_VERTEXAI
Google ADK

Two agents, both traced

  • Wrap Rescue Agent: queries ClickHouse over MCP, ranks blockers, writes requirements + audit event, drafts handoff memo
  • Assistant Editor Queue Agent: balances clean scenes across assistants for one day or all days
  • Every generate_content and execute_tool is an OTel GenAI span
Cloud Storage

Archival & durability

  • Screenplay PDFs and media archived with google-cloud-storage
  • Point-in-time restore of the spine: litestream restore -timestamp …
  • GET /api/productions/{id}/status: done, running, blocking, left, missing, in one call
  • Runs without any of it: every integration degrades gracefully and the UI says so
cinespine.curiobox.es
Hackathon Demo panel: Run Full Demo seeds Day 31 paperwork end to end
Hackathon Demo → Run Full Demo · seeds Day 31 paperwork, offloads and conflicts against the live Cloud Run service.
cinespine.curiobox.es--timeout=3600 for SSE--memory=2Gi
Interactive diagram 3 / 3 · AI usage

Every place a model is used, and where it is not

Where CineSpine uses AI: ingestion parsers with Document AI, Speech and Video Intelligence; Script Studio AI; ADK agents; llm_router with 4-model fallback and cache; Gemini text and image models; cinespine-mcp read-only SQL; WebMCP tools; production status; Grafana GenAI spansopen interactive ↗
ClickHouse Cloud · the partner track

ClickHouse is the agent's operational memory

The Wrap Rescue Agent does not guess what is blocking wrap. It asks the database, through the official mcp-clickhouse server.

-- mcp-clickhouse · run_select_query
SELECT requirement_id, priority, assigned_to,
       dateDiff('hour', created_at, now()) AS age_h,
       acknowledged_at IS NULL          AS never_opened
FROM   cinespine.requirement_events FINAL
WHERE  production_id = 'DEMO_PRODUCTION'
  AND  status = 'blocked'
ORDER BY priority, age_h DESC
  • Projections, not a second source of truth. Every mutation route mirrors into six tables: production_events, takes_meta, audit_discrepancies, requirement_events, editorial_tag_events, user_activity. FINAL for current state.
  • Agent loop: list_tables → run_select_query → rank blockers by severity, age and missing acknowledgement → file a requirement per blocker, assigned to the owning department → audit event. The memo is delivered: a notification from @wrap_rescue_agent to whoever ran it plus the director, producers and post supervisors.
  • Same mirror, read three ways. Analytics panels, the crew workload ledger and the ranked status endpoint are all ClickHouse queries; the operational SQLite never answers a whole-production question.
  • Honest failure. An MCP error is a 200 with an error body; the client checks isError and shows the failed call. The memo walks the Gemini chain (live: gemini-2.5-flash 404, gemini-3.5-flash drafted) and says so when every model fails.
cinespine.curiobox.es
Productions hub: Wrap Rescue Agent panel with Query / Rank / Write steps and the blocked requirements it raised
Wrap Rescue Agent · ClickHouse MCP + Gemini Enterprise · Query → Rank → Write. Below it, the three blocked requirements it raised for @dit and @sound_supervisor.
console.clickhouse.cloud
ClickHouse Cloud query insights for the cinespine database
console.clickhouse.cloud
ClickHouse Cloud SQL console querying the user_activity table
console.clickhouse.cloud
ClickHouse Cloud advanced dashboard for the cinespine service
Grafana Cloud · supporting

Production health, read straight from ClickHouse

A dashboard a line producer can read: what the audit found, who has filed, what was shot, what is blocked, who is looking.

grafana.net · Dashboards · CineSpine · Production Health from ClickHouse
Grafana dashboard 'Production Health from ClickHouse (CineSpine)': open critical/warning counts, findings by type, documents ingested per department, takes per shoot day, requirements by status, time to acknowledge by actor
Production Health from ClickHouse · ClickHouse datasource with a read-only grafana_ro user · variable per production.
Five sections
  • Continuity: open CRITICAL / WARNING, findings by type
  • Ingestion: documents per department, minutes since last filing
  • Takes: per shoot day; post-production stage per scene
  • Requirements: by status × priority; blocked, oldest first
  • Engagement: actions/hour; median time-to-acknowledge
Signals shipped
  • Traces, logs, metrics over OTLP HTTP; logs stamped with trace_id
  • Business metrics as OTel instruments (cinespine_*): discrepancies by severity, events by axis, live SSE connections
  • Faro RUM from the SPA; Synthetic checks on /api/health deep probe
SLO · backend availabilitySLO · Wrap Rescue run successAlert · telemetry silent 20m
Grafana Cloud · the agent, traced

One screen proves the agent did what it says

A Wrap Rescue run is a span tree: ADK → mcp-clickhouse → ClickHouse → Gemini. Runs, MCP tool calls, p95, tokens by model, active discrepancies, on one dashboard.

grafana.net · Dashboards · CineSpine · Wrap Rescue Agent
Grafana dashboard 'Wrap Rescue Agent': agent runs, MCP tool calls, run p95, Gemini tokens since deploy, active discrepancies, agent runs as traces ADK to mcp-clickhouse to ClickHouse to Gemini, tokens by model, latency p50/p95
Wrap Rescue Agent dashboard, linked from the Hackathon Demo page. Last hour, after the pre-flight reset: 4 runs, 24 MCP tool calls, p95 23.0s, 3 active discrepancies on Day 31. Runs and tool calls come from Tempo TraceQL metrics.
Agent Observability
Grafana Agent Observability reading OTel GenAI spans
Synthetics · Checks
Grafana Synthetic Monitoring checks for CineSpine
Alerting · Rules
Grafana alert rules for CineSpine
Pipeline spans we wrote
  • cinespine.ingest · cinespine.parse · cinespine.reconcile (each unresolved finding as a span event)
  • cinespine.mirror.insert · cinespine.mcp.tool · cinespine.agent.*
0.00s
GenAI instrumentation init. Was ~34s with OpenLIT.
0 → 3gauge
Active discrepancies read 0 for weeks: keyed by str(enum), so Severity.WARNING matched nothing. Fixed 9 Sep; the test now feeds enums.
0silent traces
Cloud Run forwards an unsampled traceparent; the sampler now keeps sampling under it, so curl, probes and agent triggers trace too.
By the numbers

Built to be verified, not believed

0
pytest cases passing in CI, across 70 test modules. Python 3.11 and 3.14.
0
axes reconciled: Intent, Belief, Existence. Deterministic rules, no LLM in the path.
0
witness roles emitting typed events: Director/DoP, Script Supervisor, Sound, DIT, Editorial.
0polling
Server-Sent Events push every ledger change to the crew that needs it.
0service
API and SPA from one origin, Litestream-replicated spine, restore to any timestamp.
0tables
ClickHouse mirror the agent, analytics and status read: production_events, takes_meta, audit_discrepancies, requirement_events, editorial_tag_events, user_activity.
0signals
Traces, logs, metrics, browser RUM, all landing in one Grafana Cloud stack. Plus 2 SLOs and synthetic checks.
0presets
Deakins to Kubrick, each with lens, T-stop, Kelvin and film-stock LUT. 5 screenplay formats parsed.
Live demo

Three minutes on the running service

Live app · Cloud Run · europe-west4cinespine.curiobox.esSource · MITgithub.com/ftenaf/cinespine
Pre-flight, before the recorder starts
  • Factory Reset → Run Full Demo once, before recording, never during: it empties the whole spine
  • Run Wrap Rescue once off-camera: MCP cold start ~45s, and every run files requirements about the previous run
  • Open Day 31 in the app first; the Grafana gauge is recorded on open, not scraped, and should read 3. A 0 is a regression (fixed 9 Sep), not a cold cache
  • Warm /status once (first call reconciles every day); a test render must not answer “Previz Placeholder”
  1. 1

    Hackathon Demo → Factory Reset → Run Full Demo

    Seeds Day 31: script supervisor log, camera and sound reports, one Silverstack offload. Watch the SSE feed light up.

  2. 2

    Set & Editorial Spine → Day 31 → Active Discrepancies

    Timecode drift, paperwork without media, media without paperwork. Open Diagnose on 2/1 Take 2; resolve one and see the event appended.

  3. 3

    Productions → Wrap Rescue Agent → Run

    MCP status, list_tables, run_select_query, ranked blockers, a requirement per blocker for @dit and @sound_supervisor. Click the bell: the memo arrived from @wrap_rescue_agent.

  4. 4

    Dashboard → Where do we stand · Grafana → Wrap Rescue Agent

    The ranked status card, most urgent item as the headline. Then one Grafana screen: the run you just triggered as a span tree, ADK → mcp-clickhouse → ClickHouse → Gemini.

  5. 5

    Screenplay & Previz Studio → Demo Production

    6 scenes, 6 characters. Break down Scene 1 or 4: both carry a CUT TO:, the path where Gemini writes the breakdown. Pick Deakins, switch 2.39:1 → 4:3.

What's next

The honest gaps, and what closes them

Grafana

Agent generation ingest

Wire AGENTO11Y_* so Agent Observability gets conversation replay, per-agent cost and live evaluations, on top of the OTel spans it already reads.

ClickHouse

Hosted MCP via OAuth

Move the agent from the self-hosted mcp-clickhouse service to ClickHouse Cloud's remote MCP once a headless OAuth flow is available.

Google Cloud

Image generation on billing

Gemini image models sit behind a billed project; until then the studio serves a labelled placeholder and logs every model it tried.

Ingestion

More witnesses

Avid / Resolve bin exports and EDLs as the Editorial axis; ARRI and RED camera metadata straight from the card, not the report.

WebMCP

Browsers that expose modelContext

Eight page tools are registered today; only Chrome's early preview can see them. When the W3C draft ships, a browser agent drives CineSpine without scraping.

Product

Multi-tenant productions

Per-production auth and crew invitations; the spine already keys everything by production_id, so isolation is a policy, not a rewrite.

“A document is a witness.
Witnesses disagree, and the disagreement is the product.”
Google CloudClickHouseGrafana Labs

CineSpine · Francisco Tena · Agentic Cinema: The Blockbuster Hackathon 2026 · ClickHouse track · MIT

The product calls Google Cloud AI only: Gemini via the GenAI SDK and Vertex AI, Google ADK, plus the official ClickHouse MCP server. An AI coding assistant (Anthropic’s Claude Code) was used as a developer tool during development.