All case studies AI Game Master platform

Party Lore: 288 hand-written migrations → 1 generated baseline

Java / Kotlin / TypeScript / MetaObjects

288 hand-maintained database migrations collapsed into one generated baseline, ~1,900 lines of hand-built LLM prompts became typed contracts, and the model made removing dead schema mechanical — 29 tables and 49 columns gone in nine days, each proven safe by a clean recompile.

partylore.com ↗

288 → 1
hand-written migrations → one baseline
116 tables, 524 indexes, generated
78
dead tables + columns removed in 9 days
29 tables · 49 columns, compile-proven
~1,900
lines of prose prompt-building, retired
→ 45 typed prompt + 23 output templates
655
typed object + template declarations
one model, 50 YAML files
~4:1
generated : metadata leverage
build-verified floor
16
upstream releases in 7.5 weeks
the flywheel with Draagon AI

Party Lore is a large AI Game Master platform across Java, Kotlin, and TypeScript. Its schema drifted across hundreds of hand-written migrations, its LLM prompts were roughly 1,900 lines of string-building, and dead code was invisible — a manual audit once flagged 13 live files as dead. Moving to one metadata model collapsed 288 migrations into a single generated baseline, turned the prompts into typed contracts, and made removing dead schema mechanical: 29 tables and 49 columns deleted in nine days, each proven safe by a clean regenerate-and-recompile.

The challenge: drift you can't see, and dead code you can't safely delete

Party Lore drives a Discord experience, a web console, a React UI, and an LTI education mode across three languages, with 655 typed shapes in play. Three problems compounded. The database schema had accreted 288 hand-written migrations, with the JVM and TypeScript sides kept in agreement by hand. The 100+ LLM prompts were assembled by hand — an internal audit counted roughly 1,900 lines of prose append() calls across ten Java builders — untyped enough that one prompt shipped a routing bug (it logged one model's name while silently running on another), and one live prompt path had no test at all.

Worst of all, dead code was undeletable in practice: an early-2026 manual audit mis-flagged 13 live files as dead, so no one trusted deletions and the cruft just stayed. You can't safely remove what you can't prove is unused.

The solution: one model, generated from — schema, surfaces, and prompts

The domain is now declared once as 655 typed declarations across 50 YAML files, and every consumer is generated from it. The MetaObjects Maven plugin generates the JVM domain (Kotlin / Exposed); meta gen generates the TypeScript surfaces (a Drizzle console, a React UI); and both draw from the same model. The 288 migrations collapsed into a single generated baseline — 116 tables, 183 foreign keys, 196 checks, 524 indexes — guarded by a boot-time drift validator. The prompts became 45 typed prompt templates plus 23 output contracts, migrated in 107 byte-identical steps and gated three ways: the Maven build verifies them, a CI workflow checks codegen drift, and a test bans raw hand-written prompt files.

Results

Before

Delete a dead entity

Guess from a manual audit that once flagged 13 live files as dead — so nobody deletes, and the cruft stays forever.

After

Delete a dead entity

Remove its YAML, regenerate, recompile. If it compiles, nothing live pointed at it — proof, not hope.

What became newly possible

  • Schema hygiene is now routine, not risky. Because the generated code is canonical, "is this used?" is answered by the compiler — dead shapes get removed continuously instead of accreting for years.
  • Cross-language drift is a build failure. A metadata-drift workflow runs codegen and docs drift on every push; the JVM and TypeScript sides can't silently disagree.
  • A two-way flywheel with the toolchain. Party Lore was MetaObjects' first adopter — its needs drove upstream fixes (the Kotlin codegen fix the baseline required, prompt-as-metadata, a docs surface later shipped upstream), and hardening from the sibling Draagon AI adoption flowed back in. Sixteen upstream releases were consumed in about seven and a half weeks.

288 hand-written migrations collapsed into one generated baseline — and then the model started finding the bodies: 29 dead tables and 49 dead columns, deleted in nine days because a clean recompile proved nothing needed them.

— verified in-repo: baseline generated June 2026, dead-shape sweep over nine days

Party Lore's source is private — for a clone-and-read version of the same pattern, see Wizards of Odd, or Draagon AI for the sibling story.

Where it is now

Since 2026-09-09 it has run the stable release on both toolchains it coordinates — npm 1.0.0 and Maven Central 8.0.0, the JVM line running a higher major by design on the same minor and patch. The two-toolchain cost named above is what paying for that looks like.

What wasn't clean

All case studies

Considering MetaObjects for your next platform?

Doug works directly with teams evaluating MetaObjects. Tell us what you're building and we'll tell you, honestly, whether MetaObjects fits.

Email doug@dougmealing.com