1 Setup
AgenticMail edited this page 2026-05-17 21:47:24 -04:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Setup (for operators)

The hosted App at github.com/apps/agenticmail runs on Netlify Functions. The same code can be re-deployed under any other GitHub App by setting the env vars below — the function itself is infrastructure-agnostic (any platform that delivers Request/Response and supports context.waitUntil works).


Architecture in one diagram

GitHub webhook delivery
   │
   ▼
POST /api/github/webhook
   ├─ HMAC-SHA256 verify (constant-time)
   ├─ dedup on X-GitHub-Delivery UUID (5-min TTL)
   ├─ 202 Accepted in <100ms
   │
   ├─ context.waitUntil(processWebhook(...))
   │      ├─ branch by event
   │      ├─ rate-limit check (paid verbs)
   │      ├─ plan check (paid verbs)
   │      ├─ fetchPRFiles (if PR + relevant verb)
   │      ├─ generateReply via Anthropic
   │      │     └─ writeUsage(account, tokens, cost)
   │      ├─ post comment OR state-changing action
   │      └─ writeAudit(status, latency, error)
   │
   └─ writeAudit(accepted)

The function never blocks on agent work. GitHub gets its 202 in under 100ms; the LLM call runs in context.waitUntil() so Netlify keeps the function alive for up to 15s of background work.


GitHub App settings

When you register the App at Settings → Developer settings → GitHub Apps:

  • Webhook URL: https://<your-host>/api/github/webhook
  • Webhook secret: strong random string (set on the App and in env as GITHUB_WEBHOOK_SECRET)
  • Subscribe to events: issue_comment, pull_request_review_comment, issues, pull_request, installation, marketplace_purchase

Permissions

Scope Access Why
Issues Read + write Read thread context, post comments, react, close
Pull requests Read + write Summarize, post review comments, post formal reviews
Contents Read + write Required for @agenticmail merge (modifies default branch)
Metadata Read Required by GitHub for any App

Drop Contents: write if you don't need the merge verb — it's the only feature that touches branch state.


Environment variables

Required

Var Purpose
GITHUB_APP_ID Numeric App ID from settings
GITHUB_APP_PRIVATE_KEY PEM-encoded RSA private key (escaped \n ok)
GITHUB_WEBHOOK_SECRET HMAC secret matching the App's webhook config
ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY At least one — see below

The function reads ANTHROPIC_AUTH_TOKEN first (Claude OAuth surface, sk-ant-oat01-…); if absent it falls back to ANTHROPIC_API_KEY (classic sk-ant-api03-…). OAuth tokens require model claude-haiku-4-5 or higher — earlier-generation aliases like claude-3-5-haiku-latest are not visible on the OAuth surface and return 404.

Var Purpose
ADMIN_AUDIT_TOKEN Enables /api/github/audit, /usage, /billing
SENDGRID_API_KEY Outbound email (welcome + ops notifications)
SENDGRID_FROM_EMAIL Verified sender address on SendGrid
AGENTICMAIL_OPS_EMAIL Where install/uninstall notifications land
AGENTICMAIL_SEND_URL Custom email endpoint (fallback if no SendGrid)
AGENTICMAIL_API_KEY API key for the custom endpoint

If no email provider is configured, the function continues working — ops notifications just don't fire.


Netlify Blob stores

The function uses six independent Blob stores:

Store Purpose Key TTL
github-webhook-dedup GitHub delivery UUID → seen-at-ms UUID 5 min
github-installations Installation metadata <installation-id> install lifetime
github-webhook-audit One entry per delivery (accepted, processed, errored, etc) <YYYY-MM-DD>/<UUID> none (forever)
github-rate-limit Per-installation token bucket <installation-id> 1 hour window
github-billing Plan record per Marketplace customer account <account-login-lowercased> until cancelled
github-usage Per-call token + cost telemetry <YYYY-MM-DD>/<account>/<UUID> none (forever)

Delete a store from the Netlify dashboard (Project → Blobs) only if you understand what it does. Deleting github-webhook-dedup is safe (might cause one duplicate reply). Deleting github-billing flips all paid accounts back to Free until the next marketplace_purchase webhook re-populates them.


Admin endpoints

All three require x-admin-token: <ADMIN_AUDIT_TOKEN> header.

GET /api/github/audit

GET /api/github/audit?day=YYYY-MM-DD&limit=100&installs=1

Returns the day's delivery entries + (with installs=1) the full installations list. Use it to answer "did GitHub's reviewer event arrive?" or "why didn't the bot reply to X?".

GET /api/github/usage

GET /api/github/usage?account=<login>&range=30

Rolls up Anthropic token usage by account. Returns per-verb breakdown

  • USD cost estimate at the current claude-haiku-4-5 rate. Use it to sanity-check unit economics before/after pricing changes.

GET | POST | DELETE /api/github/billing

# Inspect plan for one account
GET /api/github/billing?account=<login>

# Comp an account onto a paid plan without a real subscription
POST /api/github/billing  body: {"account":"<login>","planName":"Pro"}

# Clear a stale plan record
DELETE /api/github/billing?account=<login>

The marketplace_purchase webhook handler is the primary writer; this endpoint is an escape hatch for comps and corrections.

Note on propagation: Netlify Blob writes can take up to ~60s to be visible to function instances in other regions. After a DELETE, the gate may briefly still see "paid" for in-flight requests.


Deploy

The frontend repo (agenticmail/frontend) is wired to Netlify with auto-deploy on push to main. Workflow:

  1. Make changes locally, commit, push to main.
  2. Netlify picks up the push, runs next build, deploys functions.
  3. Health endpoint comes up at https://<your-host>/api/github/health in ~3–5 minutes.

For env var changes (no source change), trigger a redeploy from the Netlify dashboard — env var updates do not auto-trigger a deploy.