Toast
Toast
Product Requirements Document
TL;DR
We're building a Ghost-killer: open source, agentic native publishing platform on a modern tech stack.
Principles: Open source, easy to change, feature-competitive, AI-native.
Stack: Hono, Drizzle, PostgreSQL, TipTap, React, pnpm.
Architecture: Multi-tenant from day one. Structured content. Events as product surface. Lazy loading. PostgreSQL does everything.
Day 1: Repo exists. API runs. POST /content works.
Week 1: Login -> create content -> publish -> view on public URL.
The Problem
Ghost is being out-shipped. Competitors went from zero to $30M ARR in four years by shipping constantly - users ask for things and get them days later.
The root cause is friction. Ghost's 2013-era architecture creates resistance on every change. A new entrant starting today would simply move faster.
This is that new entrant: architected for 2026.
Open source, self-hosting, and data ownership are non-negotiable. Done right, these are our competitive advantage - not constraints to work around.
What We're Building
An open-source publishing platform with four defining qualities:
1. Radically Open
Not open-core. Not source-available. Genuinely open source.
What this means:
- Same codebase runs Ghost(Pro) and self-hosted installations
- Zero proprietary dependencies - runs anywhere Node.js runs
- Self-hosting setup in under 10 minutes: clone, configure, run
- Complete data ownership - export everything, take it anywhere
- Permissive licensing that doesn't restrict commercial use
The competitive edge: Beehiiv and Substack can't offer this. For creators who care about ownership, we're the only serious option.
2. Easy to Change
The architecture makes change cheap. This is the point.
What this means:
- Small blast radius - changing one thing doesn't break unrelated things
- Fast feedback - tests in seconds, hot reload that works, types that catch errors as you type
- Consistent patterns - if you've seen one endpoint, you've seen them all
- Local reasoning - understand a piece of code without understanding the whole system
- AI-workable - TypeScript strict mode, explicit over implicit, schemas as source of truth
- Monorepo with clear boundaries - packages have explicit dependencies, ESLint enforces them, no circular imports
The test: Someone unfamiliar with the codebase (human or AI) can make a meaningful change in under 30 minutes.
The competitive edge: We can ship features in days, not weeks. We can respond to what users need instead of maintaining a backlog.
3. Feature-Complete
Feature parity with what's making competitors win, built on open infrastructure.
What this means:
- Core publishing (content that becomes articles, emails, pages) - table stakes
- Audience growth (recommendations, referrals) - not just "here's your RSS feed"
- Revenue diversification (subscriptions, products, sponsorships) - not just Stripe tiers
- Automation and workflows - if this, then that, without Zapier
- Analytics that tell you what to do, not just what happened
The competitive edge: Creators get better functionality with Ghost's ownership model.
4. Agentic Native
AI agents can operate the platform. Not AI writing - AI running the publishing business.
What this means:
- API completeness - if a human can do it in Admin, AI can do it via API
- API discoverability - an AI can read the OpenAPI spec and correctly use the platform
- Semantic content - structured data with meaning (topics, entities, tone), not just HTML blobs
- Rich events - external systems react to everything meaningful that happens
- Actions, not disguised CRUD -
POST /content/:id/publishwith declared side effects
The competitive edge: Creators can delegate operations to AI. One person runs what used to require a team.
Architectural Foundations
Five decisions that ripple through everything.
1. Multi-Tenancy
A site is the tenant. Every install can host multiple sites - Ghost(Pro)'s tens of thousands or a self-hosted agency's fifty client publications.
Key decisions:
site_idon every table from day one- Composite same-site foreign keys for tenant-scoped entity references (e.g.
(site_id, user_id)) - Row Level Security as defense in depth - bugs become "missing data" not "data leak"
- AsyncLocalStorage for ambient tenant context
- Schema is shard-ready: UUIDs, no cross-tenant foreign keys
Self-hosting experience: Solo blogger creates one site, never thinks about multi-tenancy. The architecture supports it invisibly.
2. Content Model
Content is structured data, not HTML blobs. The editor produces JSON. Rendering to HTML/email/API happens at read time.
Key decisions:
- TipTap/ProseMirror JSON as storage format - parseable, transformable, AI-readable
- Card system is extensible - new cards don't require core changes
- Semantic metadata derived on save - topics, entities, reading time, tone
- Embeddings generated for AI reasoning about content
Why this matters: AI can understand and work with content without reading everything. Search, recommendations, and personalisation become possible.
3. Event System
Events are product surface, not internal plumbing. External systems (including AI) build automations we haven't imagined.
Key decisions:
- Rich, typed payloads - self-contained enough to act without additional API calls
- Multiple delivery: webhooks, SSE stream, event log with cursor pagination
- Event taxonomy is product design - emit events for automations you haven't built yet
- Audit trail - who/what triggered each event (human, AI, automation)
Implementation: Durable queue-backed delivery behind an abstraction. Start with a Postgres-backed driver (e.g. pg-boss or equivalent), add Redis/BullMQ as an optional driver later if needed.
4. Module System
Boot fast, load lazily. Don't assume everything might be needed.
Key decisions:
- Clean package boundaries with explicit dependencies
- Lazy loading for optional services (email providers, payment processors)
- Separate processes for separate concerns (API, renderer, workers)
5. Database Architecture
PostgreSQL as the foundation. Use its full capabilities to avoid bolt-on infrastructure.
Key decisions:
- Separate read and write connections from day one - enables read replicas without code changes
- Use PostgreSQL's native features aggressively:
pgvectorfor embeddings - semantic search, content similarity, recommendations- Partitioning for large tables (events, analytics) - query performance at scale
- Materialized views for expensive aggregations - analytics without an OLAP database
- JSONB for flexible metadata - schemaless where it makes sense
- Drizzle ORM with escape hatch to raw SQL when needed
Database seam (intentional):
- Treat the database layer as an application seam, not an accident
- Drizzle is the interface for that seam (types, queries, contracts)
- PostgreSQL is the default and only first-class target for now
- We are not prioritising multi-database support, but we keep boundaries deliberate so choices are considered rather than arbitrary
Redis (optional acceleration layer):
- Job queue backend alternative (BullMQ driver)
- Rate limiting
- Session cache
- Real-time features (pub/sub for SSE)
What we're avoiding: Separate analytics databases, external vector stores, caching layers that duplicate PostgreSQL. One database that does it all.
Execution Gates
These gates turn architecture intent into explicit shipping criteria.
Gate A: Durable Event + Job Runtime
Requirement: Event-driven side effects and scheduled operations must survive restarts and run across multiple API instances.
Must ship:
- Durable queue runtime under the existing event abstraction
- Default production path uses a Postgres-backed queue driver
- Retry policy with bounded backoff
- Dead-letter handling for terminal failures
- Idempotency strategy for event/job handlers
Definition of done:
- A scheduled publish still executes after API process restart
- Failed delivery attempts are retried and observable
- Duplicate processing does not create duplicate side effects
Redis/BullMQ can be added as an alternative driver later, but the abstraction boundary must remain stable.
Gate B: Multi-Tenant Data Safety + Scale Posture
Requirement: Tenant isolation and read scalability must be operational, not only schema-level intent.
Must ship:
- Row Level Security policies on tenant-scoped tables
- Composite tenant-consistency foreign keys on tenant-scoped relationship tables
- Request-scoped tenant context set for database access
- Read/write DB connection split in runtime config
- Public/read-heavy paths use read connection by default
Definition of done:
- Cross-tenant reads are blocked by DB policy even if app filtering is missed
- Read replica can be introduced without code refactor
Gate C: Operational Baseline
Requirement: Production-grade safeguards and observability are available from day one.
Must ship:
- Rate limiting with consistent API and in-memory fallback for simple deployments
- OpenTelemetry traces for API + DB + queue boundaries
- Request correlation across logs and traces (requestId, siteId)
- Health/readiness endpoints include queue and DB dependency checks
Definition of done:
- Hot paths are traceable end-to-end
- Abuse-prone endpoints are rate-limited with predictable behavior
- Operational regressions are diagnosable without ad hoc logging
Gate D: Members Domain as Shipped Product Surface
Requirement: Members are not "future schema"; they are a working product capability.
Must ship:
- Member signup/auth flows (magic link for users without admin permissions)
- Free/paid tier model via
member_profilestable with gated content checks - Unified user model: admins are users with permissions, not a separate entity — no shadow member accounts needed (ADR-012)
- Defense-in-depth security stack: PermissionService isolation, ESLint guard rules, RLS policies, admin domain separation (ADR-012)
Definition of done:
- Users with admin permissions can read members-only content without a separate account
- Permission-based access control prevents privilege escalation (architectural test: all non-public routes declare
requirePermission()) - Core member journeys are test-covered and usable in UI/API
Development Infrastructure
Required for the velocity we're targeting. Build this first.
CI Pipeline: Runs in under 5 minutes - types, lint, tests, build. If it's slow or flaky, people ignore it.
Preview Deployments: Non-negotiable. Every PR gets a running instance. You can't review editor changes from code.
Seed Data: Preview deployments need realistic content - articles in every state, members across tiers, edge cases, volume (50+ pieces). An empty publication tells you nothing.
Test Coverage: Critical paths covered, tests run in under 60 seconds. Not percentage - confidence.
Generated Docs: OpenAPI from Zod schemas. Can't drift.
Technical Wants
Specific improvements over current Ghost that we don't want to lose track of:
Unified User Model:
- Single
userstable — every person (reader, author, admin) is a user. Permissions determine what they can do, not which table they're in (ADR-012) - No shadow member accounts — admins can read members-only content because they're users too
- Member-specific data (subscriptions, tiers, Stripe) lives in a related
member_profilestable - Security isolation through defense-in-depth: PermissionService, ESLint guard rules, RLS policies, admin domain separation (ADR-012, ADR-013)
Developer Experience:
- Environment validation at startup with clear error messages - fail fast, not mysteriously
- F5 debugging works out of the box in dev containers
make dev,make test,make clean- universal interface via Makefile- Health endpoints (
/healthz,/healthz/ready) for orchestration
Operational:
- Rate limiting works without Redis for simple deployments - in-memory fallback, same API
- Structured logging with request ID and site ID correlation
- Audit logging for security-relevant operations - who did what, when, queryable
Contributor Experience:
- 25% of issues labeled
good-first-issue - 48-hour response time target for new contributor PRs
- ADRs in
docs/decisions/explaining non-obvious choices
Technology Choices
| Concern | Choice |
|---|---|
| Runtime | Node.js 24.x |
| API Framework | Hono |
| Database | PostgreSQL (default) via Drizzle seam |
| Validation | Zod (schemas as source of truth) |
| Auth | Better Auth |
| Editor | TipTap |
| Jobs | Durable queue (behind driver abstraction; Postgres first) |
| Admin | React 19 |
| Monorepo | pnpm + Turborepo |
| Testing | Vitest |
Milestones
Phase 0: Foundation
Goal: Prove the architecture. One vertical slice.
Deliverable: Log in -> create content -> publish -> view on public URL. Events fire. Infrastructure works.
Includes: Dev containers, CI pipeline, preview deployments, seed data. You can't build features without infrastructure.
Phase 1: Content + Runtime Reliability
Goal: Usable content management with durable scheduling path.
Content types, drafts, scheduling, taxonomy, settings, SEO metadata.
Must include before Phase 1 exit:
- Gate A baseline for scheduling-critical jobs (durable queue path, Postgres-backed first)
- Gate C baseline (rate limiting + trace/log correlation for core routes)
Phase 2: Public Site + Data Safety Posture
Goal: Looks like a real publication, safely multi-tenant at DB level.
Theme system (basic), homepage, navigation, RSS, content API.
Must include before Phase 2 exit:
- Gate B baseline (RLS on core tenant tables + request tenant context + read/write split)
Phase 3: Members
Goal: Reader relationships.
Signup (magic link for users without admin permissions), tiers via member_profiles, gated content, member management, Stripe.
Must include before Phase 3 exit:
- Gate D complete (unified user model with permission-based access control and defense-in-depth security stack)
Phase 4: Email
Goal: Newsletter functionality.
Configuration, content-to-email, sending, analytics.
Phase 5: Evaluate
Goal: Answer the experiment's questions.
Polish, documentation, final evaluation.
Review Checkpoints
Explicit pauses to evaluate trajectory. Not tied to specific dates - trigger these when the relevant phase completes.
After Phase 1: Architecture Check
- Is the blast radius small? How many files touched for typical changes?
- Is the feedback loop fast? Time from code change to seeing it running?
- Is AI assistance effective? What percentage of generated code works first try?
- Are the architectural foundations holding up or fighting us?
- Gate A: Are queue-backed scheduled operations durable across restarts?
- Gate C: Can we trace and rate-limit critical paths consistently?
Decision: Continue, adjust approach, or stop early.
After Phase 2: Velocity Check
- Can we articulate specifically why development feels different? Not "it's faster" but "I can do X that was impossible before."
- What's our actual shipping pace? Features per week?
- How does contribution friction feel? Could someone new make a meaningful change quickly?
- Gate B: Is tenant isolation enforced at DB policy level, not only in app code?
Decision: Based on velocity so far, estimate time to Ghost feature parity. Is this trajectory competitive?
After Phase 4: Threat Check
- If a YC company launched this tomorrow with $10M, would Ghost leadership lose sleep?
- What's missing that would make it a real competitor?
- What did we learn about AI-assisted development?
- What patterns should we adopt in current Ghost regardless of experiment outcome?
- Gate D: Is the unified user model with permission-based access control shipped and usable end-to-end?
Decision: What happens next - parallel development, incremental adoption, or shelve?
What This Is Not
- Not production-ready - this is signal, not product
- Not backwards compatible - no migration from existing Ghost
- Not API compatible - existing integrations won't work unchanged
- Not the current theme system - exploring alternatives
- Not a multi-database portability project (PostgreSQL is the first-class target)
Team
- John O'Nolan - Product direction, hands-on development
- Hannah Wolfe - Architecture, hands-on development
- Claude Code - AI coding assistant
Reference Material
Technical References
Projects to study for architectural patterns, not features:
- n8n - Workflow automation. TypeScript monorepo, custom Express decorators, TypeORM fork, pnpm + Turborepo.
- Cal.com - Scheduling. Next.js, Prisma, tRPC. Good example of open-source SaaS with self-hosting story.
- Dub - Link management. Next.js + Hono, Prisma. Clean monorepo structure.
- PostHog - Product analytics. Python/TypeScript, Django + React. Interesting hybrid approach.
- Payload CMS - Headless CMS. TypeScript-first, config-driven schema, good admin UI patterns.
- Strapi - Headless CMS. Plugin architecture, content-type builder.
- Directus - Headless CMS. Database-first approach, instant REST/GraphQL.
- Trigger.dev - Background jobs. Modern alternative to traditional job queues.
- Novu - Notifications infrastructure. Multi-channel delivery patterns.
- Vercel AI SDK - AI infrastructure patterns for streaming, tool use, structured output.
Product References
Competitors and adjacent products to understand positioning:
- Beehiiv - Direct threat. Newsletter platform expanding to "operating system for creator economy." Zero-fee monetization, AI website builder, podcast hosting. $33M Series B, 55k+ creators.
- Kit (ConvertKit) - Email-first creator platform. Rebrand signals shift from email tool to creator OS. Strong monetization infrastructure (paid recommendations, digital products).
- Substack - The incumbent. Network effects, discovery, but closed platform with limited customization.
- Buttondown - Indie newsletter tool. Small but beloved. Worth understanding why people choose it over Ghost.
- Owner.com - Vertical AI website builder for restaurants. Interesting because they chose opinionated defaults over flexibility - "sales first, style second." $1B valuation.
- Framer - AI-native website builder. $2B valuation. Wireframer generates layouts from prompts. Proves you can be design-opinionated AND AI-first.
- Model Context Protocol (MCP) - Anthropic's open standard for AI-to-tool integration. Now under Linux Foundation with OpenAI adoption. Critical for the "agentic native" pillar - this is how AI agents will interact with publishing platforms.
This document evolves as the experiment progresses.