A modular, API-first productivity platform — notes, writing, bookmarks, recipes, budget tracking, and AI-powered search, all in one place. Built as a web app, PWA, and future iOS shell, with a programmable API for agents, automations, and CLI tooling.
Sidekick is designed to evolve safely: every feature is isolated into its own package, all mutations flow through a central API layer, and security is enforced structurally rather than by convention.
| Layer | Choice |
|---|---|
| Frontend | Next.js 16 App Router |
| Language | TypeScript (strict) |
| Database | Supabase PostgreSQL |
| ORM | Drizzle ORM |
| Styling | Mantine |
| Editor | Tiptap |
| AI | Vercel AI SDK + Anthropic Claude |
| Monorepo | Turborepo + pnpm |
| Hosting | Vercel |
- Node.js 18+
- Corepack enabled:
corepack enable
pnpm installpnpm devOpens apps/web at http://localhost:3000.
pnpm buildpnpm lintpnpm typecheckpnpm formatapps/
web/ # Next.js 16 App Router — main web application
cli/ # CLI tool — authenticated API access from terminal
packages/
core/ # Shared server infrastructure: Supabase, Drizzle, API guard, RLS
ui/ # Shared React components (Mantine-based)
copy/ # Centralized copy (text strings) shared across all apps
eslint-plugin-sidekick/ # Custom ESLint rules (no-mantine-style-props)
features-registry/ # Master feature manifest list (ALL_FEATURES)
feature-notes/ # Notes feature — schema, repository, API routes
feature-writing/ # Writing feature
feature-bookmarks/ # Bookmarks feature
feature-recipes/ # Recipes feature
feature-budget/ # Budget tracking feature
feature-ai-chat/ # AI chat feature
docs/
learn/ # Explainers for every technology and decision in this codebase
decisions/ # Architecture decision records
progress/ # Phase-by-phase progress log
The most important rule in this codebase:
packages/*must never import fromapps/*.
The only allowed dependency direction is:
apps/* → packages/features/* → packages/core
This rule is automatically enforced by ESLint (eslint-plugin-boundaries). Violations fail the lint pipeline immediately.
- Create a folder under
packages/your-package-name/ - Add
package.jsonwith name@sidekick/your-package-name - Add
tsconfig.jsonextending../../tsconfig.base.json - Add
src/index.ts - Run
pnpm installfrom the repo root to register it in the workspace
Follow the same steps above, then:
- Define your schema in
schema.ts - Add a Drizzle config in
drizzle.config.ts - Register the feature in
packages/features-registry - Add API routes in
apps/web/src/app/api/your-feature/ - All routes must use
withApiGuard()
Copy .env.example to .env.local and fill in values:
cp .env.example .env.localSee .env.example for all required variables and which phase they are needed in.
.env.local lives at the repo root, not inside apps/web. Scripts that need it (e.g. db:generate, db:migrate) prefix with dotenv -e ../../.env.local --. Never create a separate .env.local inside apps/web.
- Set all environment variables in the Vercel dashboard before building
- Set the build command to
next buildin Vercel (bypasses thedotenv -eprefix inpackage.json, which is only needed locally) DATABASE_DIRECT_URLis NOT needed in Vercel — migrations run locally, never on the Vercel build serverNEXT_PUBLIC_*variables are baked into the browser bundle at build time — they must be set in Vercel before building, not after