Personal coding knowledge base — Obsidian-style pages + grep + semantic search.
Upload notes, PDFs, lecture slides, docs, and code snippets. Query everything with:
recall "transformer positional encoding"- Next.js 16 (App Router)
- Supabase (Auth + Storage + Postgres)
- Prisma (ORM + pgvector)
- TipTap (Notion-style editor)
- OpenAI (embeddings + agent answers)
- Nested folders
- Editable pages (rich text + code blocks)
- File uploads with text extraction (PDF, DOCX, markdown, code)
- Keyword search (ILIKE + pg_trgm)
- Semantic search (pgvector + OpenAI embeddings)
- Agent mode — ask questions scoped to a folder or your entire library
- Copy env vars:
cp .env.example .env.local-
Create a Supabase project:
- Enable Email auth
- Copy URL + anon key + service role key into
.env.local - Copy Postgres connection strings for
DATABASE_URLandDIRECT_URL
-
Install and migrate:
npm install
npx prisma migrate dev --name init- Run the SQL setup scripts (Supabase SQL editor):
# prisma/setup.sql — pgvector + search indexes
# prisma/setup-storage.sql — private "documents" bucket + RLS- Start dev server:
npm run devOpen http://localhost:3000, sign up, and start building your library.
Pro subscriptions are handled by Lemon Squeezy as merchant of record (tax/VAT included).
- Create a Lemon Squeezy account and add a subscription product for Pro ($12/mo or your price).
- Copy your API key, Store ID, and Pro Variant ID into
.env.local. - Register a webhook pointing to:
Subscribe to:
https://YOUR_DOMAIN/api/webhooks/lemonsqueezysubscription_created,subscription_updated,subscription_cancelled,subscription_expired,subscription_resumed,subscription_payment_failed. - Set the webhook signing secret as
LEMONSQUEEZY_WEBHOOK_SECRET. - Set
NEXT_PUBLIC_APP_URLto your public URL (e.g.http://localhost:3000in dev).
Users upgrade from Settings → Plans (/settings/plan). Cancellations are done in the Lemon Squeezy customer portal; access continues until the period ends.
Use Lemon Squeezy test mode while developing.
All app emails — auth (confirm, reset, magic link) and workspace invites — go through Resend with matching templates.
- Create a Resend account and verify your sending domain.
- Add to
.env.local:
RESEND_API_KEY=re_...
EMAIL_FROM=recall <invites@yourdomain.com>
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Optional subject overrides
INVITE_EMAIL_SUBJECT={{inviter}} invited you to {{library}} on recall
AUTH_EMAIL_SUBJECT_SIGNUP=Confirm your recall account
AUTH_EMAIL_SUBJECT_RECOVERY=Reset your recall passwordRoute auth emails through the same Resend setup (instead of Supabase’s default mailer):
- Supabase Dashboard → Authentication → Hooks
- Create a Send Email hook (HTTPS)
- URL:
https://YOUR_DOMAIN/api/webhooks/supabase-auth-email - Generate a secret and add to
.env.local:
SEND_EMAIL_HOOK_SECRET=v1,whsec_...- Enable the hook. Supabase will call your app for confirm/reset/magic-link emails; your app sends them via Resend.
In dev, expose localhost with ngrok/cloudflared and use that URL for the hook.
Without the hook configured, Supabase still sends its own auth emails — invites still use Resend when RESEND_API_KEY is set.
| Action | How |
|---|---|
| New folder | Sidebar → folder icon |
| New page | Sidebar → + |
| Upload file | Drag onto home or use file picker |
| Search | Click recall button → grep mode |
| Ask agent | recall terminal → agent mode |
| Scope search | Choose "Entire app" or current folder |
| Endpoint | Description |
|---|---|
POST /api/recall |
{ query, folderId? } → search results |
POST /api/agent |
{ question, scope, folderId? } → AI answer + sources |
POST /api/pages |
Create page |
PATCH /api/pages/:id |
Update page (auto-reindexes) |
POST /api/documents |
Upload file (multipart) |
POST /api/folders |
Create nested folder |