SearchScribe AI Studio
One topic becomes a researched, structured draft with SEO metadata, exported as sanitised HTML or Markdown.
- Solo
- Free public beta
- MIT, open source
- FastAPI · Pydantic · SQLAlchemy 2 · Postgres · Next.js 16 · Gemini · Tavily
The problem
Getting from a topic to something publishable means research, drafting, metadata and safe HTML: four chores, each with a way to ship something wrong or unsafe.
Constraints
Model output is untrusted. The model never writes HTML and never retypes a source. It returns data that code checks and renders.
One deadline for everything. Research, retries, one fallback and the SEO repair share a 100-second budget, and nothing keeps generating after it expires.
Free-tier hosting. Vercel, Render and Neon Postgres, with the limits and cold starts that come with them.
Architecture
Topic
Plan research
Tavily search
Source records
Select evidence
Check passage IDs
Write article
Validate
Render
Sanitise
New version
Preview
Decisions
The model returns JSON; a template writes the HTML.
- A structured article (title, sections, paragraphs, bullets) validated by Pydantic, rendered by Jinja2 with autoescape, sanitised by nh3 and previewed in a sandboxed iframe.
- Sanitising HTML the model wrote: sanitiser bypasses exist, and there’s no output contract.
- The model has no way to write markup, so a whole class of injection risk is gone.
The model cites passages by ID.
- The server numbers each source passage and keeps its text. The model returns passage IDs; an unknown or cross-source ID stops the run before anything is saved.
- Letting the model retype or paraphrase its quotations.
- It is model-assisted source selection, not proof of accuracy, and the docs say so.
Cookies behind a same-origin proxy.
- Next.js proxies /api to the backend, so HttpOnly refresh cookies stay same-origin and rotate on use, with theft detection.
- Bearer tokens in localStorage, which hands token theft to any XSS bug.
A modular monolith, on purpose.
- One FastAPI app: routers, then services, then repositories. No broker, workers or agent framework.
- Celery workers from day one, or a service per feature.
- A status field already marks long generations, so they can move behind a queue later without changing routes.
Outcome
- Live as a free, noncommercial beta with password and Google sign-in.
- 286 backend test functions (pytest) and 141 front-end and end-to-end tests (Vitest, Playwright), counted on 15 October 2026. Ruff, mypy and builds gate CI too.
- Six architecture decision records, each naming the alternatives it rejected.
What I’d change next
Turn on draft review in the live beta once it passes its quality gate, so every paragraph is checked against the excerpts it came from before a draft is saved. Then persistent daily quotas and rehearsed backup restores.