System overview
3ngram consists of three services sharing a single PostgreSQL database:Tech stack
| Layer | Technology |
|---|---|
| Frontend | Next.js 16, React 19, TanStack Query, Tiptap/Novel editor |
| API | FastAPI, psycopg3 (async), Pydantic v2 |
| MCP | FastMCP, psycopg3 (sync, ConnectionPool), Streamable HTTP |
| Database | PostgreSQL 16, pgvector, Alembic migrations |
| Embeddings | OpenAI text-embedding-3-small (1536-dim) |
| Auth | JWT (API), OAuth 2.0 (MCP) |
| CI | GitHub Actions (ruff, mypy, pytest, Playwright, Bandit) |
Core principles
- MCP-first: AI tools are the primary interface; the web app is for overview and data portability
- Structured memories: Commitments, decisions, blockers, and context have lifecycle semantics
- User isolation is mandatory: All queries filter by
user_id. RLS policies enforce this at the database layer - Module isolation:
engram.mcpandengram.apinever import each other - Services own business logic: Routers handle HTTP concerns only
- Self-contained memories: Every memory makes sense in isolation, months later
- Auth can be disabled:
AUTH_ENABLED=falsefor local single-user mode - LLM consent is opt-in: Memory consolidation via external LLM defaults to off
Data model
3ngram stores three types of data:| Store | Table | Description |
|---|---|---|
| Documents | documents | Tiptap JSON. User notes edited through the web UI. Never split into chunks. |
| Memories | memories | Structured recall. 6 types: decision, commitment, blocker, preference, pattern, context. |
| Content chunks | content_chunks | Indexed markdown with 1536-dim embeddings. Derived index, rebuildable. |
Deployment
| Service | Platform | Trigger |
|---|---|---|
| Backend (API + MCP) | Railway | Auto-deploy on merge to main/staging |
| Frontend | Vercel | Auto-deploy on merge to main/staging |
| Database | Railway (PostgreSQL) | Managed |