Inspiration
Reading a screenplay properly is really four different jobs at once. Someone tracks structure. Someone checks continuity. Someone builds a shot list. Someone writes the pitch. In most workflows, one person does all four, sequentially, slowly, and inconsistently.
I wanted to see what happens when you give each of those jobs to its own AI agent instead of asking one model to do everything in a single pass. Not just for speed, but for honesty. If an agent flags a continuity issue, I want to see why it flagged it, not just trust a black box.
What it does
Script Room takes a raw screenplay or treatment and runs it through four sequential Gemini-powered stages: Parser, Continuity, Shot List, and One-Pager. Each stage does one job, hands its output to the next stage, and explains its own reasoning as it goes. The result is a full production package: structure, flagged issues, a shot-by-shot breakdown, and a pitch-ready logline and synopsis, downloadable as a single JSON file.
How we built it
The stack is a PNPM monorepo: a React 19 frontend built with Vite, an Express 5 API, PostgreSQL through Drizzle ORM, and Gemini via the @google/genai SDK in Vertex AI mode on Google Cloud. The whole thing was built and deployed using Replit Agent, from the first scaffold through rate limiting, retry logic, and observability, and it's hosted live as a Replit Autoscale Deployment.
Every stage schema requires a reasoning field, and every system prompt explicitly instructs the model to explain itself with specifics from the input, not generic filler. That single design decision shaped almost everything else about the project.
Challenges we ran into
The hardest bug wasn't in my own pipeline logic, it was in something I assumed would just work: IP-based rate limiting. Google Cloud's frontend infrastructure rotates through a pool of its own IPs in front of the app, so every request looked like it came from a different visitor, no matter what proxy hop count I configured. Rate limiting was silently doing nothing. The fix was reading the original client IP from the front of the x-forwarded-for chain directly, instead of trusting Express's default IP resolution.
A close second: I spent an hour debugging a job that looked permanently stuck, only to find out my workspace and my live deployment were quietly writing to two completely separate databases the whole time. Nothing was actually broken, I was just looking at the wrong data.
Both of these taught me the same lesson from different angles: verify against the real, deployed environment, not the one that's convenient to check.
Accomplishments that we're proud of
The retry and fallback system genuinely works under real failure, not just in theory. Every stage retries with backoff, and if it still can't recover, it degrades to a safe default instead of failing the whole job, so a user always gets a complete, downloadable package even when something upstream goes wrong. I verified this with a full code audit, tracing every fallback object against its schema and confirming no path can skip the safety net.
What we learned
That agentic reliability is less about the model and more about everything around it: schema validation, retry design, and being honest in the UI about what's a clean result versus a recovered one. And that testing against a live, deployed URL surfaces problems that testing in a dev environment never will.
What's next
PDF upload support, a shareable read-only results link, and eventually a lightweight review layer so a real script coordinator could confirm or override what each agent flagged.
Built With
- drizzle-orm
- esbuild
- express.js
- gemini
- gemini-2.5-flash
- google-cloud
- google-cloud-vertex-ai
- google-genai
- neon
- node.js
- pino
- pnpm
- postgresql
- react
- replit
- replit-agent
- tailwindcss
- tanstack-query
- typescript
- vite
- zod


Log in or sign up for Devpost to join the conversation.