
Your website is getting roasted tonight.
An AI agent that audits your site with the energy of a Filipino senior dev — four beers deep, completely out of patience, and brutally correct.
Roasi is the AI agent at the heart of this product. She is a Filipino senior developer, four beers deep at 2am, voluntold to review yet another website at a hackathon. Exhausted, brutally honest, and completely out of patience for people who think buying a domain is the same as building a product.
Her voice never changes. Whether she's roasting or teaching, she stays Roasi — tired, exasperated, code-switching. She explains LCP like she cannot believe she has to. She walks through render-blocking resources while muttering under her breath. The teaching is real. The warmth is not.
Every line she writes is data-driven. Scores, audit failures, exact metrics — if a number isn't in the report, she doesn't invent it. Vague roasts are for people who are also bad at their jobs.
Her code-switching is structural. Every paragraph contains exactly one Filipino sentence or phrase — not a dropped word, but a full expression that lands like punctuation on the worst thing she just said. The expressions escalate: mild in paragraph one, nuclear by paragraph four.
The roast is four paragraphs, no headers:
- React to what the site is trying to be — start mid-thought
- Specifics — exact audit failures, exact scores, exact metrics
- Pull back — who built this and what do they think they built
- Find the one thing that almost worked, name it sincerely, then dismantle it
Roasi does not modify code, write files, or touch the user's codebase. She scans, analyzes, teaches, and guides.
User submits a URL
│
▼
┌─────────────────────────────────────────────┐
│ Roasi Agent Loop │
│ │
│ 1. Scan → Unlighthouse audit │
│ 2. Analyze → Priority-tier categorization │
│ 3. Roast → Brutal, structured critique │
│ 4. Guide → Actionable recommendations │
└─────────────────────────────────────────────┘
│
▼
Results stream in real time via SSE
| Tool | Purpose | |
|---|---|---|
| Turborepo | Task orchestration, build caching | |
| pnpm workspaces | Package management | |
| Biome | Formatting + linting | |
| TypeScript | Shared configs via packages/typescript-config |
/
├── apps/
│ ├── web/ # Next.js 16 main application
│ └── design-system/ # Vite-based component explorer
├── packages/
│ ├── ai/ # LLM agent, tools, prompts
│ ├── ui/ # Shared React components (shadcn/ui)
│ ├── sprite-animations/ # Pixi.js Roasi mascot animations
│ ├── eslint-config/ # Shared ESLint rules
│ └── typescript-config/ # Shared tsconfig presets
POST /api/roast
└─ ToolLoopAgent (Vercel AI SDK)
├─ planTool / updateStep — declare & track workflow steps
├─ scanSite — Unlighthouse audit (4 modes)
├─ analyzeScanReport — priority-tier categorization
├─ memoryTool — persistent core/notes/conversation storage
└─ loadSkill / bash — dynamic skill execution
Roasi's behavior is defined in prompt files under packages/ai/src/agents/roasi/prompts/:
| File | Purpose |
|---|---|
PERSONALITY.md |
Voice, tone, code-switching rules, roast structure, profanity guidelines |
AGENT.md |
Workflow, tools, audience calibration, output format, content guard |
Responses stream via SSE (Server-Sent Events). The client uses the Vercel AI SDK useChat hook, and tool results render with custom per-type components as they arrive — no batching.
Supabase is the primary persistent store:
| Table | Contents |
|---|---|
scrape_cache |
Scraped site data and roast metrics |
ai_response_cache |
LLM response cache (deduplication middleware) |
| chat memory | Conversation history via memory tools |
Filesystem (.workspace/ locally, /tmp in production) handles ephemeral state:
.workspace/
├── .memory/
│ ├── core.md # Facts injected into every agent turn
│ ├── notes.md # Archival notes
│ └── conversations/
│ ├── {chatId}.jsonl # Message history (JSONL per chat)
│ └── titles/{chatId}.txt # Chat titles for sidebar
└── .reports/{timestamp}/ # Lighthouse HTML reports (served via /api/reports)
| Mode | Pages | Description |
|---|---|---|
default |
1 | Homepage only |
targeted |
Custom | Specific paths |
smart |
~20 | Sitemap-guided |
full |
200 | Full crawl |
SSRF protection blocks all private/local hosts and cloud metadata endpoints.
| Tier | Audits |
|---|---|
| 🔴 1 — Critical | is-crawlable, meta-description, LCP, CLS, TTI |
| 🟠 2 — High impact | color-contrast, image-alt, WebP images, render-blocking, unused JS/CSS |
| 🟡 3 — Enhancements | Everything else |
- Node.js >= 20
- pnpm 9.x
pnpm installCopy .env.example to apps/web/.env and fill in your values:
# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
# AI
MISTRAL_API_KEY=your_key_here
# Web scraping
FIRECRAWL_API_KEY=your_key_here
# Supabase (scrape cache, AI response cache, chat memory)
SUPABASE_URL=your_supabase_url
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
SUPABASE_DB_PASSWORD=your_db_password
# Upstash Redis (rate limiting)
UPSTASH_REDIS_REST_URL=your_redis_url
UPSTASH_REDIS_REST_TOKEN=your_redis_token
# Bot protection (Cloudflare Turnstile) — optional
# NEXT_PUBLIC_TURNSTILE_SITE_KEY=your_site_key_here
# TURNSTILE_SECRET_KEY=your_secret_key_herepnpm devOpens at http://localhost:3000.
pnpm buildshadcn components are added to packages/ui:
pnpm dlx shadcn@latest add button -c apps/webImport from the shared package:
import { Button } from "@roaster/ui/components/button";