Contents

ADR-0003: Two programs: a TypeScript core and a Godot engine

  • Status: Accepted (2026-09-29)
  • Date: 2026-09-29

Context

The brief says "Reelwright = editor plugin + runtime + CLI" and "statically typed GDScript unless an ADR justifies C#/GDExtension for a hot path". It also asks for an AI showrunner using the Claude API with tool use and structured outputs, schema validation with an auto-repair loop, change sets with undo, recorded-fixture tests, provider abstractions for LLM, TTS, image, music and SFX, and a CLI for headless Linux boxes.

Findings that bear on where that work should live:

  • Godot has no JSON Schema validator in GDScript. The only maintained one (GDSchema) is a C++ GDExtension. Godot's JSON.parse turns every number into a float and accepts trailing commas and duplicate keys.
  • There is no official Anthropic SDK for GDScript. Streaming, tool loops, retries, refusal fallbacks, prompt caching and structured outputs would all be hand-written and maintained against a moving API.
  • The official Anthropic SDK and the reference MCP SDK are TypeScript and Python. Ajv is the reference JSON Schema 2020-12 validator.
  • Rendering on Linux needs xvfb-run around Godot anyway, so the CLI benefits from being a launcher rather than Godot itself.
  • --headless --write-movie crashes; headless Godot cannot capture frames.

Decision

Split by responsibility, not by layer:

  • Core (core/, TypeScript on Node 24, pnpm): the only writer of specs; schema and semantic validation; change sets and undo; dependency graph; samplers (pattern → instance); compiler (EpisodeIR → Timeline) with the framing solver and the film-grammar validators; audio mix plan and ffmpeg; the showrunner agent (official Anthropic SDK); the MCP server; the reelwright CLI; all provider adapters.
  • Engine (engine/, Godot 4.7, statically typed GDScript): builders (character, set, prop, FX, graphics), style shaders, the timeline player, the frame server and Movie Maker capture, model sheets and previews, and the editor plugin UI (chat dock, timeline panel, preview viewports).
  • Contract: the JSON Schemas in schemas/. TypeScript types and GDScript typed data classes are generated from them, never hand-written. The engine reads only core-validated, resolved inputs.

The rule of thumb is that the core decides and the engine draws.

Alternatives considered

  1. Everything in GDScript.
    • For: one runtime and install; closest to the brief's wording.
    • Against: hand-maintained LLM client and agent loop; a JSON Schema validator written from scratch; weak mocking and fixture tooling; no MCP; JSON.parse quirks at every edge.
    • Rejected. It spends the budget on plumbing instead of the product.
  2. Python core.
    • For: the best ML ecosystem, which matters for the M9 segmentation and vectorizing and for local TTS.
    • Against: packaging and typing are weaker for the orchestration-heavy core.
    • Kept for optional adapters only: Kokoro TTS and future SAM or VTracer tools run as uv subprocesses behind adapter interfaces.
  3. Godot .NET (C#) for everything.
    • For: one process, and official SDKs exist.
    • Against: a separate Godot build, the .NET SDK, known issues reloading editor-plugin assemblies, and it departs further from the brief's GDScript preference.
    • Rejected.

Consequences

  • Users install Node 24 alongside Godot. The editor plugin starts reelwright serve automatically. A single-file binary can come later (Node SEA).
  • MCP comes almost for free, so Claude Code or Claude Desktop can drive world-building from M3, before the in-editor chat panel is done.
  • Two test suites (Vitest and gdUnit4) and a small cross-language conformance suite (seeds, PCG32, hashing).
  • Spec semantics live in exactly one place, because only the core reads raw specs.