3.6 KiB
CLAUDE.md
Stack
Cloudflare Worker (TypeScript + Hono) + React 18 + Vite + Tailwind + shadcn/ui + Cloudflare D1 + remote MCP server (@hono/mcp) + OAuth for claude.ai connectors (@cloudflare/workers-oauth-provider, KV-backed).
Package manager: pnpm. Never use npm commands.
Key Commands
pnpm run dev # Worker backend :8787
pnpm run dev:web # React frontend :5173 (proxy /api → :8787)
pnpm run db:migrate:local # apply D1 migrations locally
pnpm run deploy # build:web + db:migrate:remote + wrangler deploy
pnpm run test # unit tests (workers pool)
pnpm run fixtures:pull # pull real mails from remote D1 → test/fixtures/*.eml (gitignored)
pnpm run test:mail # deterministic regression on real-mail fixtures (free, no LLM)
pnpm run test:eval # live LLM classification eval on fixtures (costs API calls)
Architecture Boundaries — Never Violate
isPromotionalEmail()must run before any LLM call in the email handler (src/email/handler.ts).- Every incoming email →
raw_mails. Only AI-extracted results →code_mails. Never skipraw_mails. ASSETSis required for the frontend. There is no legacy HTML fallback.- DOMPurify + sandboxed iframe on all email HTML rendering. Do not relax.
- Auth boundaries: middleware in
src/app.ts(sessionAuthon/api/*,requireAdminon/api/admin/*,apiKeyAuthon/mcpforaik_keys) plus theOAuthProviderwrapper insrc/index.ts(validates OAuth tokens on/mcp, thenoauthPropsAuthre-fetches the user from D1 — never trust props beyonduserId). Do not move or bypass either layer; the only allowed provider bypasses inindex.tsareBearer aik_pre-routing and the whole-provider skip whenOAUTH_KVis unbound (OAuth is an optional feature). visibleMails()(src/services/mail.ts) is the only mail permission layer — REST and MCP both query through it. Never add a parallel filter path.- Sensitive categories (
password_reset,account_security) are default-deny for users;legacyand raw email bodies are admin-only on every interface. - All AI calls go through
callProvider()(src/services/classify.ts). Do not add per-provider methods alongside it. - Schema changes = new numbered file in
migrations/. Never edit applied migrations.
Env Vars
Required: AI_BASE_URL, AI_API_KEY, AI_API_FORMAT (openai|responses|anthropic), AI_MODEL, JWT_SECRET (Cloudflare secret, signs session JWTs; local dev reads it from gitignored .dev.vars).
Optional binding: OAUTH_KV KV namespace (name mandated by workers-oauth-provider; stores OAuth tokens/grants/clients). Present → OAuth enabled on /mcp; absent → OAuth fully bypassed, /mcp accepts aik_ keys only and /oauth/* returns 404.
Optional fallback: AI_FALLBACK_BASE_URL, AI_FALLBACK_API_KEY, AI_FALLBACK_API_FORMAT, AI_FALLBACK_MODEL (all four or none).
Optional Bark push: UseBark, barkUrl, barkTokens.
Frontend Component Rules
- UI components: shadcn/ui only. No new UI libraries without discussion.
- Colors: CSS variables in
web/src/index.css. No hardcoded hex except table hover states. - Use
text-muted-foregroundfor secondary text.text-mutedis a background color — never use as text. - All grid children need
min-w-0to prevent overflow.
Compact Instructions
When compressing, preserve in priority order:
- Architecture decisions (NEVER summarize)
- Modified files and their key changes
- Current verification status (pass/fail)
- Open TODOs and rollback notes
- Tool outputs (can delete, keep pass/fail only)