A bedtime ritual, not a content app

fairytaile

Personalised bedtime stories that remember every character your child meets.

A child profile, a nightly story, and a living world that grows with every night — co-created by a parent, a child, and a thoughtful AI.

Pre-alpha · daily changes · founding-member signup open.

The bedtime gap

Parents run out of stories. Children never run out of bedtimes.

The bedtime story is the most consistent shared ritual a child has with their parents — and the one parents most reliably feel guilty about. By age five, the average parent has told the same six stories more than two hundred times. The library on the shelf grows; the energy at 8:47pm does not.

The market’s answer so far has been streaming audio for kids. That is content delivery, not co-creation. We think bedtime is a creative ritual, not a media slot.

2 hr 14 min

average parent bedtime routine, US, 2025 (Common Sense Media).

74%

of parents report repeating the same stories most nights.

38%

of children aged 3–6 fall asleep with a passive screen on. Up from 22% in 2019.

The window

The first generation of parents who trust the model.

Two curves crossed in 2025. LLM quality became good enough to write a bedtime story a tired parent will actually read aloud. And these parents — the ones who have been using AI at work for three years — became willing to let one co-write their child’s inner world.

That second curve is the rare one. It will not last forever, and the brand that earns the bedtime ritual first is the brand that holds it.

Quality crossed the line

A 600-word bedtime story is the perfect form for current-generation models: short enough to control, long enough to matter, and read aloud, where small flaws disappear into a parent’s voice.

Trust crossed the line

42% of US parents under 40 have asked an AI for parenting advice in the last 90 days (Pew, 2026). The taboo is gone. The expectation of care is the new bar.

Distribution is wide open

No incumbent at the parent–child–bedtime intersection. Storytelling apps optimise for solo screen time; sleep apps for adults. We are building for the four feet between the parent’s chair and the child’s pillow.

What we’re building

Three layers,
one bedtime.

Most “AI bedtime story” tools generate a fresh story every time and forget the child by morning. Fairytaile remembers. It builds a quiet developmental profile of the child, suggests lessons worth telling stories about, and keeps every character and place the family invents across every night that follows.

“About Eli.”

Layer 1

Child Profile

A quick onboarding survey about personality, temperament, and development goals. The answers feed a small, evidence-aware AI report: who this child is right now, and which lessons would be worth weaving into stories with them. Earned, not given. The full report unlocks once the parent has done the work.

“Tonight’s story.”

Layer 2

Nightly Story

Three small choices: a lesson (from the report or free-text), a few characters and places (from the world or invented fresh), and a mood (adventurous, cosy, funny, mysterious). The AI weaves a story that calls the child by name, hits the chosen lesson, and reads aloud in 5–8 minutes.

“A new friend has joined the world.”

Layer 3

Living World

Every character and place that appears in a story is saved. The fox who became a friend on night three will appear on night seven if the family invites her back. The treehouse from the cosy story becomes the setting for the brave one. The world is the retention moat — and the source of warmth.

Plenty of products do one of these. None do all three. Child development intelligence without a persistent world feels clinical. A persistent world without intelligence is just an asset library. The combination is the bet.

The state of the app

Live today. Shipping this week. (No roadmap theatre.)

Everything below either runs in production at fairytaile.app right now or is in the active branch list. Items move between columns daily — three of the “live now” items shipped in the last 48 hours.

Last updated 2026-05-14. Numbers verified at build time.

Live now / production

The full nightly ritual. Sign up → onboarding (child name + DoB) → survey → Child Report → lesson selection → 3-step co-creation (characters, places, mood) → paginated story reader → save to world.
The Child Report and lesson cards. AI-written profile in the brand voice; five lesson recommendations with priority pips, each tappable to seed a story.
The Living World. Persistent characters and places, deduplicated case-insensitive, auto-extracted from each story (with the parent confirming before save). World viewer + per-element editor live.
Illustrations for every user. Gemini 2.5 Flash Image rendering character portraits, place portraits, and scene illustrations — gated through a feature flag, canary allowlist, and runbook, then rolled out to everyone. (Phase C.1 → C.6, shipped this week.)
Stripe Founding Members tier. Checkout with 30-day trial, customer portal, webhook-driven entitlement, founding-slots sweep (500 cap), trial-nurture email at day 5.
PWA. Web app manifest, iOS splash screens at all sizes, OG share card, favicon.
Observability + analytics. Sentry (errors), PostHog (product analytics), both EU region.
Account hygiene. Self-serve subscription portal, account deletion, data export, privacy + terms pages.
Quality gates. Vitest unit + integration (real Postgres via WASM pglite), Playwright E2E (chromium), four GitHub Actions workflows including a Claude code-review pipeline.

Shipping next / active branches

Turborepo monorepo — done this week. apps/web/ (Next.js) + packages/shared/ (pure-TS: types/, db/, prompts/, domain/). Seven sequential phases, seven PRs (#50–#56), all merged. The plan and the result are in docs/superpowers/plans/2026-05-13-monorepo-restructure.md. This unlocks the iPad app without rewriting the schema or prompt templates.
Expo iPad reader app. Reads packages/shared/db types, talks to the existing web API. Two-week build, sequenced after the Apple Reader-App entitlement comes through (in flight).
Family Plan. $99.99/yr for three children — same data model, additional children rows under one subscription.
Read-aloud audio. Text-to-speech for the story reader, sequenced after illustrations settle.
Weekly pulse survey. One small developmental question per week, drips into the Child Report; quiet ambient growth, never a dashboard.
Printed book ordering. $24.99–$34.99 one-off, all tiers, high margin. Available to families with a rich world.
Android (Play Store). Parallel to iOS.

Getting in

It’s live. It’s also pre-alpha. Both things are true.

Fairytaile is deployed at fairytaile.app. Founding-member signup is open. The app has not been announced to the market, and daily changes are still landing — expect rough edges, and tell me about the ones that aren’t already on the list.

fairytaile.app
Founding Members tier is the only paid option open right now. Card upfront, 30-day trial.
  1. 1Visit https://fairytaile.app.
  2. 2Sign up (Clerk-hosted auth, light theme on the brand). Founding Members tier is the only paid option open right now.
  3. 3Card upfront, 30-day trial. The trial is structured to never interrupt a story in progress — paywall moments live at boundaries (dashboard, post-story), not mid-ritual.
  4. 4Onboarding takes ~3 minutes: child name, date of birth, then the 10-question survey. The Child Report unlocks at the end.
Founding Members
$39.99 / year
Full access. Locked at this price for life. First 500 slots only.

Once Founding Members fills (or once we move out of alpha), the public launch tiers come online: Free (text-only, manual entry every night, no profile/memory), Monthly $8.99/mo, Annual $59.99/yr. Founding members keep their $39.99 forever. The free tier exists because the app should be useful even when nothing is paid. It is intentionally effortful — manual entry every night — so the trial-to-paid moment feels like fatigue lifting, not a wall.

What you’ll actually hit in pre-alpha

  • The brand voice is locked. The UI is mostly locked.
  • Illustrations are on for every user as of this week; image consistency across re-renders is the open problem and where most of the daily fixes are landing.
  • The /world page just lost its paid-gate; iteration on that view is daily.
  • Story generation is reliable; story length and pacing are still being tuned per age band.
  • The Day-5 trial email exists and is being refined.

If something breaks: open an issue (or just tell me at our next coffee). The faster the feedback, the faster it lands — most fixes ship the same day.

The unit economics

Nineteen paid users. That is the whole math.

Fairytaile is built on a fixed cost base small enough to fit on a postcard. The free tier exists to introduce the ritual; the paid tier exists because the ritual, once felt, is worth a coffee a month. We are not selling tokens. We are selling a moment.

Now

Founding

$39.99/yr · locked for life

First 500 subscribers. 30-day trial.

Free

$0

Text stories. Manual entry every night. No memory.

Monthly

$8.99/mo

Profile · report · world memory · illustrations.

Annual

$59.99/yr

Same as monthly. Save $47. The default offer.

Phase 3

$9.99 / $74.99

After conversion validated. Existing subs grandfathered.

Family

$99.99/yr

Up to 3 children. Phase 3.

$125/mo

fixed cost base, today.

19users

paid subscribers to break even.

2.9%

conversion rate at break-even. Target 40–60%.

The Day-5 trial email is a personalised summary of the world the family has built so far. Loss aversion, not discount aversion. We do not discount.

The build

Plan, lock, ship. Repeat.

Fairytaile is a solo build. The “team” is me plus Claude Code plus a co-founder doing UX and marketing. The way I get away with that — and the reason the audit trail will hold up — is a disciplined planning loop. Every workstream is a numbered ADR. Every phase is a separate PR. Every commit is conventional.

// verified 2026-05-14

180

commits on main
git log --oneline | wc -l

14

planning documents
in docs/superpowers/ — 10 plans, 3 specs, 1 session handoff

4

GitHub Actions workflows
unit + integration, Playwright E2E, Claude trigger, Claude code-review

9

conventional commit groups
top: feat (46), fix (23), feat(db) (13)…

1

monorepo restructured this week
apps/web + packages/shared

A vignette — Workstream 5 (the monorepo migration)

The 23KB plan doc is at docs/superpowers/plans/2026-05-13-monorepo-restructure.md. The plan defined seven phases:

PhaseWhat it didPR
WS5-P1Turborepo foundation — move app into apps/web/#51
WS5-P2Extract pure-TS types to @fairytaile/shared#52
WS5-P3Extract Drizzle pgTable + client to @fairytaile/shared/db#53
WS5-P4Extract LLM prompt templates to @fairytaile/shared/prompts#54
WS5-P5Extract pure domain helpers to @fairytaile/shared/domain#55
WS5-P6(Reserved — folded into P5/P7 during execution)
WS5-P7Monorepo conventions + shim cleanup, WS5 complete#56

Seven PRs, one day, every one green on CI before the next started. The riskiest single PR in the project’s history — every import path in the repo changed — landed without a behaviour regression because the plan separated the file move from the package extraction. ADR 2 of the plan defined the rule: nothing in packages/shared/* may import server-only or any web/Node global. The boundary is enforced by what compiles, not by hope.

How a phase actually runs

  1. Plan first. A markdown plan with ADRs goes into docs/superpowers/plans/. Decisions are locked, alternatives evaluated, success criteria stated, risk noted.
  2. Subagents do the work. The plan is handed to Claude Code (/skill execute-plan). Independent slices run in parallel where the dependency graph allows.
  3. Each phase is one PR. Conventional commit message, scoped (feat(db), chore(ws5-p3), spike(illustrations)). PR description references the plan doc by relative path.
  4. CI is the gate. Vitest (with a real Postgres via WASM pglite), Playwright E2E, and the Claude code-review workflow all have to be green.
  5. Session handoffs are written. When a phase pauses, a session doc captures state in docs/superpowers/sessions/ so the next session starts cold-readable, not cold-blind.
feat(illustrations): C.6 — drop the gate, illustrations on for everyone (#48)
feat(illustrations): Phase C.5 — broader UI integration (dashboard / wizard / story detail) (#47)
feat(illustrations): Phase C.4 — canary user allowlist + rollout runbook (#44)
feat(illustrations): Phase C.3 — UI integration behind flag (#42)
feat(illustrations): Phase C.2 — lib/illustrations module behind flag (#41)
feat(illustrations): Phase C.1 — schema + R2 wiring (#40)

A six-step rollout of AI illustrations from “schema + storage” to “on for everyone”, every step its own reviewable PR with its own runbook in the plan doc. The canary allowlist and the rollout runbook are the part I’d never have written by hand — they exist because the plan doc demanded them.

Under the hood

One slide. Versioned. Boring on purpose.

Choices that don’t fight Vercel, don’t fight Postgres, and don’t pretend to be more interesting than they are. Every version below is from apps/web/package.json on main.

Hosting & runtime
  • Verceldeploy + cron
  • Node22.x
  • npm11.12.1
Framework
  • Next.js14.2.35
  • React18
  • TypeScript5
Monorepo
  • Turborepo2.5
  • npm workspaces
  • apps/web/ + packages/shared/ (types, db, prompts, domain) — no server-only imports.
Data
  • Supabase Postgrespooler
  • Drizzle ORM0.45.2
  • drizzle-kit0.31.10
  • supabase-js2.101.1
  • pglite0.4.5
Auth
  • Clerk6.39.1
  • Webhook-driven user provisioning, hosted sign-in / sign-up.
Payments
  • Stripe17.7.0
  • Svix1.93.0
  • Checkout, Customer Portal, webhooks. Card-upfront trial.
AI
  • Anthropic SDK0.82.0
  • Google GenAI2.0.1
  • Claude for story + report + world extraction; Gemini 2.5 Flash Image for illustrations.
Storage
  • Cloudflare R2via S3 SDK 3.1045.0
  • Illustration assets, public-read via custom domain.
UI
  • Tailwind3.4.1
  • Radix primitivesdialog, toast
  • lucide-reacticons
  • Brand tokens authoritative — cssVariables: false. shadcn/ui pattern, per-primitive only.
Email
  • Resend6.12.3
  • react-emailtemplates
Observability & analytics
  • Sentry@sentry/nextjs 10.52.0
  • PostHogjs 1.372 / node 5.21
  • Both EU region.
Data fetching
  • TanStack Query5.96.2
  • React cache()server dedup
Testing
  • Vitest4.1
  • Playwright1.59 (chromium)
CI
  • GitHub Actions4 workflows
  • test.yml · e2e.yml · claude.yml · claude-code-review.yml

The path not taken

Five decisions that could have gone the other way.

Tech stacks read confident. Decisions don’t get to. Each item below names what was evaluated, what was chosen, and what changes if the chosen path turns out wrong.

1

ORM — Drizzle, not hand-written Supabase queries (and not Prisma)

Considered
The starting point was supabase.from('table').select(...).eq(...) with hand-typed Mapped<T> interfaces in lib/supabase/types.ts. Prisma was a candidate.
Chosen
Drizzle ORM 0.45.2. Schema-as-source in packages/shared/db/schema.ts. drizzle-kit generate produces migrations from diffs. Compile-time typed queries. Zero runtime overhead over the postgres driver.
Why not Prisma
Heavier client, separate schema language, slower start on serverless cold-paths, less idiomatic with Postgres-specific features.
Why not stay
Query strings have no compile-time validation. Every column rename was a manual lib/supabase/types.ts edit. Joins read like magic strings. The cost of switching is bearable; the cost of not switching grew per migration.
Decision lock
Supabase CLI stays authoritative for migrations (RLS + RPC bodies are hand-written and live in supabase/migrations/). Drizzle Kit emits to a separate drizzle/migrations/ directory; DDL gets hand-ported once before supabase db push. Duplication is the price; the benefit is preserving RLS + RPC history and avoiding a collision.

Plan doc: docs/superpowers/plans/2026-05-08-drizzle-adoption.md

2

Illustrations — Gemini 2.5 Flash Image, after a spike

Considered
The CLAUDE.md blocker was explicit: illustration consistency is an unsolved problem; test multiple providers. A Phase A spike on 2026-05-11 ran the candidate against the consistency criteria.
Spike result
With reference-image conditioning, Gemini 2.5 Flash Image preserved all identity markers (fur, eyes, pendant, ear tufts) across three re-renders of the same character. Place consistency held across mood variants. Multi-reference composites — a character on a known place — also held. Cost: ~$0.04/image (~$0.51 worst-case for a 10-beat story). Latency: 12s mean (async, not inline).
Chosen
Gemini for portraits + scene illustrations. Negative prompting reserved for child-safety only (no sexual / violence / political); identity is reinforced positively via backstory.
If wrong
The lib layer (apps/web/lib/illustrations/) is provider-agnostic by interface; swapping providers is a per-call replacement, not a re-architecture. The feature flag and canary allowlist already exist (Phase C.4) — rollback is one config flip.

Plan doc: docs/superpowers/plans/2026-05-11-illustrations.md (spike findings in the same file)

3

Monorepo — restructured at week 6, not week 1

Considered
Greenfield monorepo from day one (apps/web + packages/shared from the first commit). Flat Next.js repo until the mobile app makes the boundary necessary.
Chosen
Flat for the first 51 PRs. Restructured as Workstream 5 over seven sequential PRs (#50–#56) in May 2026, once the Drizzle schema and prompt templates had stabilised enough that extracting them was a refactor, not a redesign.
Why not earlier
Monorepo ceremony before there’s a second consumer is overhead for nothing. Vercel project setup, Turborepo task graph, package-boundary linting — all of it pays back when there’s an apps/mobile reading from packages/shared/db. Before then, it’s drag.
Why not later
Doing it after apps/mobile exists means a chained refactor across two trees with no green-build checkpoint in between. The “right moment” was when there was still only one consumer of every import path.

Plan doc: docs/superpowers/plans/2026-05-13-monorepo-restructure.md — ADR 1 covers Turborepo vs. Nx vs. pnpm-only.

4

Trial — card upfront, not no-card

Considered
No-card trial (lower friction, higher trial-start volume) vs. card-upfront trial (higher friction, much higher trial→paid conversion).
Chosen
Card upfront, 30-day trial. The Founding Members tier is the only paid option open right now, $39.99/yr locked for life, capped at 500.
Why
The economics work at low volume. Break-even is ~19 paid users at blended ARPU around $79. A card-upfront cohort converts at 40–60% historically; a no-card cohort converts at 2–7%. The signal value of the card matters more than the trial-start count when the goal is to validate the report quality and the conversion mechanics, not to maximise top-of-funnel.
If wrong
A no-card free tier is already designed (Free: $0, text-only, manual entry every night, no memory/profile) and lives in the pricing model. Switching is a Stripe config change, not a code rewrite.
5

Paid tier — text-only at launch, not illustrations-day-one

Considered
Launch paid with illustrations (richer perceived value, but unsolved consistency risk) vs. launch paid text-only and add illustrations once consistency is reliable.
Chosen at launch
Paid was text-only. The bet was that the brand voice, the Child Report, and the Living World carry the paid tier on their own.
Chosen now
Illustrations are live for every user — the consistency problem was solved by the Phase A spike (reference-image conditioning) and the rollout was gated through a feature flag + canary allowlist + runbook before the gate dropped in Phase C.6.
The point
“Text-only paid” was the right answer in March. “Illustrations for everyone” was the right answer in May. The decision wasn’t to pick one — it was to write the spike, the flag, and the runbook so the answer could change without rewriting the product.

Your turn

Try it. Then tell me what to fix.

If your child has ever asked you to tell the same story for the eleventh time, you already understand the shape of the opportunity. We would love to show you the rest. This is where it is on a Thursday evening in May 2026 — live URL, 180 commits in, illustrations on for everyone, monorepo this week, and a long list of rough edges I haven’t gotten to yet. The fastest way to make it better is for some trusted alpha testers to spend ten minutes inside it and tell me what’s off.

Pieter (technical) & Lieschke (UX & marketing)

Made for parents, by parents. Sleep tight.

Made with Claude Code. Last verified 2026-05-14.