amarnai

agent
Guvenlik Denetimi
Basarisiz
Health Uyari
  • License — License: AGPL-3.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 6 GitHub stars
Code Basarisiz
  • Hardcoded secret — Potential hardcoded credential in apps/api/src/__tests__/ai-classify.test.ts
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

Open-source, self-hostable AI email triage assistant for Gmail. Sorts your inbox into a custom taxonomy; drafts require approval, never auto-sends.

README.md

Amarnai

Gmail-first AI email triage assistant.

Prerequisites

  • Node.js 24+ (see .nvmrc — run nvm use). The Lingui 6 i18n CLI requires Node 24.2 or newer.
  • pnpm (npm install -g pnpm)
  • Docker (for local Postgres and Redis)

Environment

.env is the base env file at the monorepo root. All apps read from it automatically.
.env.local is for local overrides and is never committed.

cp .env.example .env              # base config (fill in secrets)
cp .env.local.example .env.local  # local overrides (optional)

Values in .env.local take precedence over .env.

Local Ollama testing

Amarnai can use an Ollama instance running on your machine.

# 1. Install Ollama if needed
# https://ollama.com/download

# 2. Start Ollama
ollama serve

# 3. Pull the local models
ollama pull qwen3:14b         # LLM (used at runtime)
ollama pull qwen3-embedding   # embeddings (used for sorting)

# 4. Copy local overrides
cp .env.local.example .env.local

Make sure .env.local contains:

AI_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=qwen3:14b
ENABLE_DEV_TOOLS=true

Check that Ollama is reachable:

curl http://localhost:11434/api/tags

If port 11434 is already in use, Ollama is probably already running. In that case, skip ollama serve and continue with ollama pull qwen3:14b.

Production LLM + embeddings

Set the following in .env (or your deployment secrets):

# LLM
AI_PROVIDER=frontier
FRONTIER_LLM_PROVIDER=openai
FRONTIER_LLM_API_KEY=<your key>
FRONTIER_LLM_MODEL=<model name>

# Optional: use a lighter model for email routing and a larger model for drafts.
# Both fall back to FRONTIER_LLM_MODEL if unset.
ROUTING_LLM_MODEL=
DRAFT_LLM_MODEL=

# Embeddings (any provider — Gemini shown as an example)
EMBEDDING_PROVIDER=frontier
FRONTIER_EMBEDDING_PROVIDER=gemini
FRONTIER_EMBEDDING_API_KEY=<your Google AI Studio key>
FRONTIER_EMBEDDING_MODEL=text-embedding-004

Get a Gemini API key from Google AI Studio. You can also use OpenAI embeddings (FRONTIER_EMBEDDING_PROVIDER=openai) or any OpenAI-compatible endpoint via FRONTIER_EMBEDDING_BASE_URL.

Authentication setup

Amarnai supports two sign-in methods:

  • Google — one-step signup: Google OAuth grants both app identity and gmail.readonly inbox access simultaneously. The default workspace is created and connected automatically.
  • Email + password — sign up with any email address, verify it, then connect a Gmail inbox separately from Settings.

Google OAuth credentials

Required for both Google sign-in and Gmail inbox connection:

  1. Go to Google Cloud Console → APIs & Services → Credentials
  2. Create an OAuth 2.0 Client ID (Web application)
  3. Add http://localhost:3000 to authorised JavaScript origins
  4. Add both of the following to authorised redirect URIs:
    • http://localhost:3000/api/auth/callback/google — NextAuth sign-in
    • http://localhost:3000/api/gmail/callback — Gmail inbox connection
  5. Copy the client ID and secret into .env:
AUTH_GOOGLE_ID=<your client id>
AUTH_GOOGLE_SECRET=<your client secret>

Also generate random secrets:

openssl rand -base64 32   # paste as AUTH_SECRET
openssl rand -hex 32      # paste as INTERNAL_API_SECRET
openssl rand -hex 32      # paste as GMAIL_TOKEN_ENCRYPTION_KEY

Email auth (local dev)

Verification and password reset emails are captured by Mailpit — no real emails are sent. Start Mailpit with docker compose up -d mailpit and open the inbox at http://localhost:8025.

For production, configure an SMTP provider (e.g. AWS SES) via:

[email protected]
SMTP_HOST=email-smtp.us-east-1.amazonaws.com
SMTP_PORT=587
SMTP_USER=<SES SMTP username>
SMTP_PASS=<SES SMTP password>

Gmail inbox setup

Amarnai lets each workspace connect one Gmail inbox for email triage. The connection requests only gmail.readonly access — it cannot send or modify email.

Real-time sync (Gmail Push Notifications)

By default, Amarnai polls Gmail every 5 minutes for new messages. To get near-zero latency — Gmail notifies Amarnai the instant a message arrives — enable Gmail Push Notifications via Google Cloud Pub/Sub.

One-time GCP setup:

# 1. Enable APIs
gcloud services enable gmail.googleapis.com pubsub.googleapis.com

# 2. Create a Pub/Sub topic
gcloud pubsub topics create amarnai-gmail-push

# 3. Grant the Gmail service account publish rights on the topic
gcloud pubsub topics add-iam-policy-binding amarnai-gmail-push \
  --member="serviceAccount:[email protected]" \
  --role="roles/pubsub.publisher"

# 4. Generate a webhook secret and note it — you'll set it as GMAIL_PUBSUB_WEBHOOK_SECRET
openssl rand -hex 32

# 5. Create a push subscription pointing at your API's webhook endpoint
gcloud pubsub subscriptions create amarnai-gmail-sub \
  --topic=amarnai-gmail-push \
  --push-endpoint="https://api.yourdomain.com/webhooks/gmail?token=<your-secret>" \
  --ack-deadline=30

Set the env vars:

GMAIL_PUBSUB_TOPIC=projects/<project-id>/topics/amarnai-gmail-push
GMAIL_PUBSUB_WEBHOOK_SECRET=<your-secret>

When these are set, Amarnai automatically registers each connected inbox with Gmail's push API on connection and renews the registration daily (Gmail watches expire after 7 days). Polling continues as a fallback for any missed events.

Notes:

  • The Pub/Sub push endpoint (/webhooks/gmail) must be reachable from the public internet — this is a Google → your server call.
  • Self-hosters who prefer not to set up GCP can leave both vars unset and rely on polling.

Local development:

Run pnpm tunnel in a separate terminal alongside pnpm dev. It starts a Cloudflare quick tunnel exposing your local API and automatically updates the Pub/Sub push endpoint:

pnpm tunnel

Requires cloudflared and gcloud on your PATH. Quick tunnel URLs are ephemeral — re-run pnpm tunnel each dev session (the script updates the push endpoint automatically each time).

Google sign-in users: inbox access is granted during sign-up as part of the same OAuth consent — no extra step needed.

Email/password users: after verifying your email, go to Settings in the sidebar and click Connect Gmail. Google will ask you to grant read-only access to the inbox you want to sort. Once connected, the workspace shows the linked Gmail address and last verification time.

Required APIs — enable these in your Google Cloud project:

  • Gmail API (gmail.googleapis.com)

Env vars:

Variable Description
GMAIL_OAUTH_CALLBACK_URL Redirect URI registered in Google Cloud Console. Default: http://localhost:3000/api/gmail/callback
GMAIL_TOKEN_ENCRYPTION_KEY 64-char hex string (32 bytes) used to AES-256-GCM-encrypt stored refresh tokens. Generate with openssl rand -hex 32. Falls back to a key derived from AUTH_SECRET when unset — always set this explicitly in production.
GMAIL_PUBSUB_TOPIC Optional. Pub/Sub topic for real-time push notifications. Format: projects/<project-id>/topics/<topic-name>. See Real-time sync.
GMAIL_PUBSUB_WEBHOOK_SECRET Optional. Secret token verified on incoming Pub/Sub push requests. Generate with openssl rand -hex 32. Required when GMAIL_PUBSUB_TOPIC is set.

Google Cloud Console checklist for Gmail:

  1. APIs & Services → Library → enable Gmail API
  2. APIs & Services → Credentials → open your OAuth client → add http://localhost:3000/api/gmail/callback to authorised redirect URIs (in production, add your production URL)

Dev seed account

Running pnpm db:seed creates a local dev user and workspace:

Field Value
Email [email protected]
Name Amarnai Dev User
Workspace Default Workspace

This seed user is attached to the mock taxonomy and sample email threads used for local testing and AI sorting tests. It is not created in production signups.

Self-hosting

Amarnai can be self-hosted on any machine with Docker and Docker Compose. All services (web, API, worker, Postgres, Redis) start with a single command.

Prerequisites

  • Docker 24+ with the Compose plugin (docker compose version)
  • A Google Cloud project with OAuth 2.0 credentials (see Authentication setup)
  • An AI API key — OpenAI, any OpenAI-compatible provider, or Gemini for embeddings

Setup

# 1. Clone the repo
git clone https://github.com/amarnai/amarnai.git
cd amarnai

# 2. Create your env file from the self-host template
cp .env.selfhost.example .env

# 3. Fill in every value marked <required>:
#    AUTH_SECRET, AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, INTERNAL_API_SECRET,
#    GMAIL_TOKEN_ENCRYPTION_KEY, FRONTIER_LLM_API_KEY, FRONTIER_EMBEDDING_API_KEY,
#    SMTP_HOST / SMTP_USER / SMTP_PASS, EMAIL_FROM
#    Update AUTH_URL, CORS_ORIGIN, and GMAIL_OAUTH_CALLBACK_URL to your domain.

# 4. Build images and start all services
#    First boot runs database migrations automatically before the API starts.
docker compose -f docker-compose.selfhost.yml up -d --build

The web UI is available at http://localhost:3000 (or your configured domain).

Service Default port
Web 3000
API 3001
Postgres internal
Redis internal

Postgres and Redis are not exposed externally by default. If you need direct access (e.g. for backups), add ports entries to docker-compose.selfhost.yml.

Upgrading

git pull
docker compose -f docker-compose.selfhost.yml up -d --build

Migrations run automatically on each deploy via the migrate service.

Reverse proxy

For production HTTPS, put Nginx or Caddy in front and proxy port 3000. Example Caddyfile:

mail.yourdomain.com {
    reverse_proxy localhost:3000
}

Update AUTH_URL, CORS_ORIGIN, and GMAIL_OAUTH_CALLBACK_URL in .env to match your domain, then re-run docker compose -f docker-compose.selfhost.yml up -d.

Local development

# 1. Copy environment config
cp .env.example .env

# 2. Fill in secrets (see Authentication setup above):
#    AUTH_SECRET, AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, INTERNAL_API_SECRET, GMAIL_TOKEN_ENCRYPTION_KEY
#    SMTP vars default to Mailpit (127.0.0.1:1025) — no changes needed for local email auth

# 3. Start Postgres, Redis, and Mailpit
docker compose up -d postgres redis mailpit

# 4. Install dependencies
pnpm install

# 5. Generate Prisma client
pnpm db:generate

# 6. Run database migrations
pnpm db:migrate

# 7. Seed the database
pnpm db:seed

# 8. Start all apps
pnpm dev

Database scripts

Script Description
pnpm db:generate Generate Prisma client from schema
pnpm db:migrate Run pending migrations (dev)
pnpm db:seed Seed the database
pnpm db:reset Drop, re-migrate, and re-seed (dev only)

Development

pnpm dev

Starts all apps in parallel:

App URL
Web http://localhost:3000
API http://localhost:3001
Worker

Mobile app

apps/mobile is the Amarnai Android app (Expo + Expo Router), a readonly triage
companion. It is intentionally kept out of pnpm dev so web/API/worker
contributors aren't forced into the React Native toolchain.

To run it on a physical phone (recommended) or an emulator with Expo Go:

# 1. Install the Expo Go app on your Android phone, on the SAME Wi-Fi as your
#    dev machine. (Or have an Android emulator running.)

# 2. Start the backend (api on 3001 + worker + web) in one terminal:
pnpm dev

# 3. Start the app's Metro bundler in another terminal:
pnpm mobile

# 4. Scan the QR code shown in the terminal with Expo Go.

The app auto-detects your dev machine's LAN IP from the Metro connection and
points the API at http://<that-ip>:3001, so there is nothing to configure. The
home screen shows a connectivity indicator (green API OK when the phone
reaches your local API). To override the API URL, set EXPO_PUBLIC_API_URL (see
apps/mobile/.env.example).

See apps/mobile/README.md for troubleshooting and notes
on push notifications (which require a development build rather than Expo Go).

Other commands

pnpm typecheck   # type-check all packages
pnpm lint        # lint all packages
pnpm test        # run tests

Testing

Running tests

pnpm test                  # all packages
pnpm test:sorting          # AI sorting tests only (fast, no DB)

AI embedding fixtures

The embedding sorter tests in packages/ai use pre-computed vectors stored in
packages/ai/src/__tests__/fixtures/embedding-vectors.json. These are real
qwen3-embedding embeddings (committed to the repo) so the test suite runs
offline without Ollama and stays deterministic in CI.

When to regenerate: if you change a taxonomy node's name or description, add
new test emails to sorting-fixtures.ts, or switch the embedding model.

How to regenerate:

# Requires Ollama running locally with qwen3-embedding
ollama pull qwen3-embedding

pnpm --filter @amarnai/ai seed:embeddings

This calls Ollama once, embeds all taxonomy nodes and test email threads, and
overwrites embedding-vectors.json. Commit the updated file alongside your
taxonomy or fixture changes.

To use a different Ollama base URL or model:

OLLAMA_BASE_URL=http://my-host:11434 OLLAMA_EMBEDDING_MODEL=qwen3-embedding:0.6b \
  pnpm --filter @amarnai/ai seed:embeddings

Fine-tuning sorter constants

The sorter uses several numeric thresholds (THETA_MIN, CROSS_BRANCH_MARGIN, etc.). A grid-search benchmark sweeps 4,096 constant combinations against the labeled fixtures and ranks them by score:

# Requires embedding-vectors.json to be current (run seed:embeddings first)
pnpm --filter @amarnai/ai benchmark:constants

The output shows the top-ranked configurations with a per-email breakdown and a recommendation. If a configuration beats the current defaults, update the constants at the top of packages/ai/src/embedding/sorter.ts. Re-run pnpm test afterwards to confirm no regressions.

Structure

apps/
  web/      Next.js frontend
  api/      Hono API server
  worker/   Background jobs
  mobile/   Expo Android app (readonly triage companion)
packages/
  shared/     Shared types and constants
  config/     Environment config
  db/         Database schema and client
  ai/         AI provider abstraction
  tokens/     Framework-agnostic design tokens (web + mobile)
  api-client/ Transport-agnostic typed API client (web + mobile)

License

Copyright (C) 2026 Azgard LLC

Amarnai is free software licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only). See LICENSE for the full text.

Contributions are accepted under a Contributor License Agreement — see CLA.md and CONTRIBUTING.md.

Yorumlar (0)

Sonuc bulunamadi