NovelFlame
A multi-agent creative pipeline that turns a one-line prompt into an illustrated, multi-chapter interactive story: an art director agent, per-genre editors, character-consistency tracking, and cinematic video at climactic beats.
Why this exists
NovelFlame is an interactive fiction platform: readers pick a genre and premise, and the app generates a branching story with inline images and a cinematic video, choice by choice. I run it solo, end to end. The hard engineering here is the AI itself, not a wrapper around someone else’s model: choosing and routing models by measured story quality, keeping a cast visually consistent across an illustrated multi-chapter arc, making the branching choices feel meaningful instead of formulaic, and layering editorial and art-direction agents so it doesn’t read or look like generic AI. The infrastructure, release pipeline, and safety systems around it are what let a team of one keep all of that running in production.
Billing was a smaller side of the work than the AI. It shipped on a pay-per-story token model billed through CCBill, which I implemented straight from their docs. Their sales team never came back to onboard me, CCBill’s checkout is higher-friction for users than Stripe, and competitor reviews named per-generation currency counting as the category’s top complaint, so within a few weeks I switched to Stripe and a flat unlimited subscription.
Architecture
Five views, because the request path, the generation pipeline, the money, the release pipeline, and the operations are genuinely different machines; flattening them into one diagram buries the parts a production app is actually judged on.
The request path: five gates before a model
Nothing reaches a model until a request clears five gates in order: the Cloudflare edge (DNS, CDN, Turnstile on auth forms, CSP headers, all managed as OpenTofu code instead of dashboard clicks), Supabase SSR auth, per-surface rate limits on Upstash Redis (story generation, signup, purchases, and feedback each have their own cap), the subscription gate (free tier is 3 completed stories per 30 days, answered with a 402 paywall; Plus is unlimited), and the input safety gate: a CSAM blocklist, the OpenAI Moderation API, and a prompt-injection filter covering the places user-typed text reaches an LLM. The response streams back over SSE with a 15-second heartbeat and hard timeouts, so a stuck generation fails visibly instead of hanging the reader.
The generation pipeline: a relay of specialists
Each beat is a relay of specialists, and the model is named per stage because the routing is the point. gpt-5.5 writes the narrative (it won the blind persona eval); the editorial agent reruns the prose against genre style guides and a banned-patterns list so it doesn’t read like AI; a deterministic classifier picks the shot; the art director authors the image prompt on Grok, which doesn’t soften the story’s own action the way the narrative model did; identity locks and reference portraits keep the cast recognizable across chapters, with a vision-QA loop grading the results; and the climax beat gets a generated video in the same art style. A trigger-warning classifier then tags sensitive categories so readers can opt out before they hit them. Anthropic’s Claude sits outside this live path on purpose: it serves as a cross-family judge in the eval harness that gates model swaps, so no model grades its own family. Utility calls (summaries, choice fallbacks, prompt extraction) run on a cheaper tier, which is what moved cost per story down 30%.
Payments: one live door, one dormant lane
Payments deliberately live outside the story path. Stripe’s hosted Checkout is the live door: a signature-verified webhook writes activations, renewals, and cancellations into one entitlements store in Postgres, and the only place billing touches the reading experience is the subscription gate at story creation, the same gate in the request-path diagram above. Every transition fires PostHog analytics and Loops.so lifecycle email events, so a cancellation or a paywall hit is a measurable funnel step, not a mystery. The Apple lane is real code, deliberately dormant: I took it all the way to the edge of launch (StoreKit products, server-side receipt validation, App Store Server Notifications, the full App Store application with screenshots and pricing tiers, Apple Pay tested on my own phone) and then made the web-first call in the mobile story below instead of shipping. The lane stays in the diagram because it stays in the codebase, waiting for a native app that earns its keep.
Ship to production: governance as code
Everything between me and production is codified. A PR gets CodeRabbit’s assertive review (with gitleaks, actionlint, and slop detection wired in) and a CI run that aggregates lint, type checks, tests, the build, an OpenTofu plan, and an eval-prompt regression gate into a single required “CI Status” check, and the branch protection requiring that check is itself OpenTofu-managed, enforced for admins too, so repo governance survives even a full repo recreation. Merging to main applies infrastructure changes (Cloudflare DNS, R2, Turnstile, CSP headers, Supabase, GitHub config, with state encrypted at rest in R2), deploys the 3-stage Docker image to Railway with production migrations, and refreshes staging behind a Playwright smoke suite. If I changed something in a dashboard by hand, the next plan would show it as drift.
Operations: two Discord servers, on purpose
Two Discord servers, split by who’s talking. Machine signals run down the left: the app writes structured JSON logs and named production events (silent identity-anchor drops, SSE timeouts, moderation blocks) through Railway’s log drain into Axiom, and hourly GitHub Actions monitors query Axiom for generation failures, anchor-drop spikes, 5xx bursts, and dead-man staleness; a synthetic probe also creates a real story end to end every two hours. What they find lands as embeds in an alerts server and as deduplicated GitHub incident issues, auto-assigned to me with the Axiom query attached. Human signals run down the right: the in-app feedback button posts through a second webhook into a separate feedback server, so a reader complaint never drowns in machine noise. This telemetry isn’t decoration: the 621 silent identity-lock drops in the character-consistency story below were found by exactly this pipeline. Langfuse traces every model call for cost forensics, PostHog holds the product funnel, Sentry catches errors, and Loops.so runs lifecycle email off the same event stream.
What shipped
189 specs took NovelFlame from a forked prototype to a live, solo-operated product. The work I’m proudest of is the applied-AI engineering: routing narrative to the model that won a blind persona eval while keeping image-prompt authoring on a provider that didn’t soften the story’s own action, holding character appearance consistent across an illustrated multi-chapter story when production telemetry showed it silently breaking, and layering genre editorial agents and an art director on top of raw generation so it doesn’t read or look like generic AI. The infrastructure-as-code, CI/CD, and content-safety work underneath is what lets a solo operator keep all of that running in production.
The throughline across all of it is the same: a solo operator’s infrastructure has to be legible enough that 1 person can trust it, and honest enough to change course when a shipped feature turns out to be the wrong bet.


