Docs
Introduction

Introduction

Ship AI SaaS is a production-ready boilerplate built on the Orchestrator → Agent → Tool paradigm.

Ship AI SaaS is a Vertical SaaS boilerplate that ships a complete, production-ready AI execution engine. Unlike generic chat kits, it routes every user message to a specialized agent, executes tool workflows autonomously, and auto-persists all outputs as typed assets — no manual wiring required.

The Core Architecture

Every request flows through three layers:

  1. Orchestrator (lib/ai/orchestrator.ts) — A fast gpt-4o-mini semantic router. It reads the user's message and classifies which agent should handle it. This is one deterministic LLM call, temperature: 0.
  2. Agents (lib/ai/agents/) — Hyper-specialized workflows. Each agent uses a ToolLoopAgent that autonomously calls tools in a loop until it decides to respond.
  3. Tools (lib/ai/tools/shared/) — Atomic, Zod-enforced functions. Each tool has a strict input schema and returns a typed output that is automatically saved to the database.

Built-in Agents

Seven agents ship out of the box:

Agent IDNameTools Used
generalGeneral AssistantNone — text only
content-creationContent Strategistweb_search, web_extract, generate_outline, format_post, generate_image, memory
reel-generatorReel Generatorweb_search, web_extract, generate_reel_script, format_reel, generate_image, memory
script-writerScript Writerweb_search, web_extract, generate_script_outline, format_script, memory
thumbnail-creatorThumbnail Creatorgenerate_thumbnail_concept, generate_image, memory
receipt-scannerReceipt Scannerextract_receipt_data
legal-analyzerLegal Analyzerread_document, analyze_legal_document, send_analysis_email

Tech Stack

LayerTechnology
FrameworkNext.js 16 (App Router)
AIVercel AI SDK + OpenAI / Anthropic
DatabasePostgreSQL (Supabase or Neon) + Drizzle ORM
Background JobsUpstash QStash
AuthBetter-Auth
PaymentsStripe
EmailResend + React Email
StorageSupabase Storage
StylingTailwind CSS v4 + shadcn/ui

Coding Conventions

Kebab-case agent IDs — All agent IDs use kebab-case (content-creation, reel-generator). This is what the orchestrator routes on, what the API accepts in agentId, and how agents are keyed in AGENT_REGISTRY. Pick one form and stay consistent.

Zod .describe() on every tool field — Every field in a tool's inputSchema must have a .describe() string. The LLM reads these when deciding what values to pass. A field without a description gets guessed.

globals.css as the single source of truth for design — All colors come from the CSS custom property system defined in styles/globals.css. Use semantic tokens (bg-background, text-foreground, bg-muted, bg-primary, border, etc.) rather than Tailwind palette classes. This keeps the entire app themeable from one file and prevents one-off color decisions from fragmenting the design.