AI growth tool for X with account analysis, voice-aware drafting, reply discovery, and a companion browser extension.
Portfolio Case Study · Build-in-public post
Most AI writing tools can generate posts, but they usually don't understand the person they're writing for.
Xpo is built around learning a creator's account, source material, previous content, and positioning so it can help with strategy, drafting, replies, and engagement without flattening everything into the same generic AI voice.
- Analyzes an X account and builds an initial creator strategy
- Grounds AI outputs in source material, previous posts, and account positioning
- Supports ideation, drafting, revision, replies, and post analysis
- Finds and ranks good reply opportunities
- Generates context-aware replies through a companion browser extension
- Includes authentication, billing, entitlements, and persistent creator workspaces
X account + source material
↓
creator profile
↓
strategy + voice context
↓
AI workspace
↙ ↘
drafting replies
↓
browser extension
- Built a structured AI runtime for planning, drafting, revision, reply generation, and post analysis
- Grounded outputs in creator-provided facts, stories, playbooks, and previous content
- Designed persistent chat threads, memories, source materials, onboarding runs, and product events
- Built APIs for browser-extension authentication, opportunity ranking, and reply generation
- Added Stripe checkout, billing state, webhooks, and entitlement controls
- Implemented multiple onboarding data-source paths with production-safe fallback behavior
- Used Inngest functions for deferred X scraping, context priming, and historical backfill work
Next.js 16 · React 19 · TypeScript · Tailwind CSS 4 · PostgreSQL · Prisma · Supabase · Groq · Stripe · Inngest
The browser extension adds Xpo directly to the browsing workflow.
It can inspect visible X posts, evaluate which conversations are worth joining, and request reply drafts using the creator's existing voice and account context.
The extension communicates with the main Xpo application through authenticated APIs for:
- opportunity ranking
- reply options
- reply generation
- extension sessions
- interaction logging
The shipped application currently runs as a single Next.js deployment in apps/web.
Browser
↓
Next.js UI + API routes
↓
Domain logic
├── AI runtime
├── onboarding
├── creator memory
├── billing
├── Inngest jobs
└── extension workflows
↓
Prisma
↓
PostgreSQL
External services provide authentication, model inference, billing, deferred job execution, and X data access.
For a deeper technical breakdown:
The original Stanley for X prototype came from seeing Stan experiment publicly with hiring engineers through build-in-public challenges.
So I made something instead of sending another application.
That prototype eventually became Xpo.
Repo structure
The active application lives in apps/web.
.
├── README.md
├── apps/
│ └── web/
│ ├── app/ # App Router pages and API routes
│ ├── components/ # Shared UI and providers
│ ├── lib/ # AI, onboarding, billing, auth, Inngest, extension logic
│ ├── prisma/ # Schema and migrations
│ ├── public/
│ ├── scripts/
│ ├── package.json
│ └── .env.example
└── docs/
├── app-architecture.md
├── app-diagrams.md
└── product-notes/
Run locally
cd apps/web
pnpm install
cp .env.example .env
pnpm devMinimum environment variables:
DATABASE_URL
DATABASE_MIGRATION_URL
SUPABASE_URL
SUPABASE_ANON_KEY
SESSION_SECRET
GROQ_API_KEY
Useful commands:
pnpm build
pnpm dev:inngest
pnpm inngest:dev
pnpm lint
pnpm test:ui
pnpm test:e2e
pnpm test:v2
pnpm test:extensionImplementation notes
- Primary persistence is Prisma on PostgreSQL
- Authentication uses Supabase identity with a custom application session
- The current LLM gateway uses the Groq SDK
- Stripe handles checkout, portal access, webhooks, and entitlement state
- Inngest handles deferred onboarding, context-primer, and historical X backfill jobs through
apps/web/app/api/inngest ONBOARDING_MODEsupports scrape, X API, mock, and automatic fallback paths- Production mock fallback is guarded explicitly
- Product and operator handoff notes live under
docs/product-notes
