Amarnai
Architecture

Monorepo Structure

How the Amarnai codebase is organised across apps and packages.

amarnai/
├── apps/
│   ├── web/         Next.js 16 frontend (builds with --webpack)
│   ├── api/         Hono API server (the only DB writer)
│   ├── worker/      Background job runner (BullMQ)
│   ├── site/        Marketing site (Next.js 16, Cloudflare via OpenNext)
│   ├── extension/   Browser side-panel extension (Chrome + Firefox, MV3)
│   ├── docs/        This documentation site (Fumadocs)
│   └── mobile/      Expo Android app (shelved/paused)
├── packages/
│   ├── db/          Prisma schema, migrations, client
│   ├── ai/          AI providers, prompts, embedding sorter, validation
│   ├── mail/        Provider-neutral mail seam (MailProvider interface)
│   ├── gmail/       Gmail API client, OAuth, token encryption
│   ├── outlook/     Outlook provider over Microsoft Graph (read-only)
│   ├── auth/        Credentials, JWT/Bearer, connection guards
│   ├── billing/     Stripe subscriptions and cleanup
│   ├── email/       Transactional email (Resend or SMTP)
│   ├── core/        Framework-free view-model logic
│   ├── ui/          Shared React components + email templates
│   ├── tokens/      Framework-agnostic design tokens + theme
│   ├── i18n/        Lingui catalogs (16 locales)
│   ├── api-client/  Transport-agnostic typed API client
│   ├── queue/       BullMQ job definitions
│   ├── shared/      Shared types and Zod schemas
│   └── config/      Environment config
├── docker-compose.yml             Local development
├── docker-compose.selfhost.yml    Self-hosting
└── .env.example                   Environment variable template

Clients and surfaces

Amarnai has three active clients: the web app (apps/web), the browser extension (apps/extension, a Chrome/Firefox MV3 side-panel), and the marketing site (apps/site). All three share logic through framework-free packages (@amarnai/core, @amarnai/api-client, @amarnai/tokens, @amarnai/i18n). The mobile app (apps/mobile) is shelved; see the repo CLAUDE.md.

apps/web

The Next.js 16 frontend. Uses the App Router, React Server Components, and server actions for data mutations. Server actions call the Hono API over HTTP using a shared internal secret rather than talking to the database directly, which keeps the API as the single source of truth for writes. It builds with --webpack (not Turbopack).

apps/api

A Hono server that handles all write operations and data queries that require business logic. It is the only service that writes to the database. The web app and worker both communicate with it.

apps/worker

Runs background jobs via BullMQ. The worker handles:

  • Inbox polling: periodically fetching new threads from connected inboxes (Gmail or Outlook)
  • Thread triage: sending threads through the AI pipeline and applying labels
  • Backfill jobs: processing large batches of existing inbox threads

packages/db

Prisma schema and all database migrations. Other packages import the generated Prisma client from here. Running pnpm db:migrate applies pending migrations; pnpm db:generate regenerates the client after schema changes.

packages/ai

Provider abstraction over LLMs and embedding models. Supports:

  • Frontier: a hosted API (production). Gemini is the default via its OpenAI-compatible endpoint; any OpenAI-compatible provider also works.
  • Ollama: local models for development
  • Mock: deterministic responses for testing

All AI output goes through Zod validation before it is acted on. The package also contains the embedding-based sorter, the draft generator (approval-only output), and the test fixtures.

packages/mail, gmail, outlook

packages/mail defines the provider-neutral seam: a MailProvider interface (refreshAccessToken, listChangesSince, listThreadsPage, getThreadSnapshot, registerWatch, and so on) and a create-mail-provider factory that switches on connection.provider. packages/gmail implements it over the Gmail API (OAuth refresh, history polling, thread fetch, label management, AES-256-GCM token encryption). packages/outlook implements the same interface over Microsoft Graph (GraphClient, microsoft-oauth, normalize-graph-thread). Both are read-only. The factory selects the adapter per connection, so nothing downstream is Gmail-specific.

packages/queue

BullMQ job type definitions and queue setup. Centralising these here means both the API (which enqueues jobs) and the worker (which processes them) share the same type-safe job contracts.

Other shared packages

auth (credentials, JWT/Bearer for the extension and native clients, connection guards), billing (Stripe subscriptions, cancellation, cleanup), email (transactional send over Resend or SMTP), core (framework-free view-model logic for emails, taxonomy, and identity, enforced React-free by an ESLint boundary), ui (shared web React components and email templates), tokens (design tokens and light/dark theme), i18n (Lingui catalogs for 16 locales), and api-client (a transport-agnostic typed client used by web and native surfaces).

On this page