- Development:
pnpm dev - Build:
pnpm build - Lint:
pnpm lint - Run all tests:
pnpm test - Run AI tests:
pnpm test-ai - Run single test:
pnpm test __tests__/test-file.test.ts - Run specific AI test:
pnpm test-ai ai-categorize-senders - Type-check build (skips Prisma migrate):
pnpm --filter inbox-zero-ai exec next build - Do not run
devorbuildunless explicitly asked - Run
pnpm installbefore running tests or build if not already done - Before writing or updating tests, review
.claude/skills/testing/SKILL.md. - When adding a new workspace package, add its
package.jsonCOPY line todocker/Dockerfile.prodanddocker/Dockerfile.local.
- TypeScript with strict null checks
- Path aliases:
@/for imports from project root - NextJS app router with (app) directory, tailwindcss
- Only add comments for "why", not "what". Prefer self-documenting code.
- Logging: avoid duplicating logger context fields from higher in the call chain. Use
logger.trace()for PII fields (from, to, subject, etc.). - Tests should use the real logger implementation (do not mock
@/utils/logger). - Helper functions go at the bottom of files, not the top
- All imports at the top of files, no mid-file dynamic imports
- Co-locate test files next to source files (e.g.,
utils/example.test.ts). Only E2E and AI tests go in__tests__/. - Don't export types/interfaces only used within the same file
- No re-export patterns. Import from the original source.
- Prefer the
EmailProviderabstraction; only use provider-type checks (isGoogleProvider,isMicrosoftProvider) at true provider boundary/integration code. - Infer types from Zod schemas using
z.infer<typeof schema>instead of duplicating as separate interfaces - Avoid premature abstraction. Duplicating 2-3 times is fine; extract when a stable pattern emerges.
- No barrel files. Import directly from source files.
- Colocate page components next to their
page.tsx. No nestedcomponents/subfolders in route directories. - Reusable components shared across pages go in
apps/web/components/ - One resource per API route file
- Env vars: add to
.env.example,env.ts, andturbo.json. Prefix client-side withNEXT_PUBLIC_.
- Prefer the simplest, most readable change; only keep backwards compatibility when explicitly requested.
- Do not optimize for migration paths: refactor call sites directly, including larger coordinated changes when clarity improves.
- Use shadcn/ui components when available
- Use
LoadingContentcomponent for async data:<LoadingContent loading={isLoading} error={error}>{data && <YourComponent data={data} />}</LoadingContent>
See .claude/skills/fullstack-workflow/SKILL.md for full examples and templates.
- API route middleware:
withError(public, no auth),withAuth(user-level),withEmailAccount(email-account-level). Export response type viaAwaited<ReturnType<typeof getData>>. - Mutations: use server actions with
next-safe-action, NOT POST API routes. - Validation: Zod schemas in
utils/actions/*.validation.ts. Infer types withz.infer. - Data fetching: SWR on the client. Call
mutate()after mutations. - Forms: React Hook Form +
useActionhook. UsegetActionErrorMessage(error.error)for errors. - Loading states: use
LoadingContentcomponent.
- When a task is completed and ready for PR, invoke the
reviewersub-agent before opening the PR.