Your second brain. Self-hosted. Bring your own model.
Lectio is an open-source capture-first knowledge app. You throw links and text in — and an LLM working in the background organizes, connects, and makes it all searchable in natural language.
No folders. No tags to maintain. No structure to design. Just capture. Lectio figures out the rest.
Alpha software. Works well for personal use, rough edges remain. See the ship checklist for known gaps.
- Capture-first. Zero friction. Paste a link, type a thought, share from any app. Done.
- Self-hosted. Your notes live on your server, not ours.
- Bring your own model. Anthropic or OpenAI for cloud, Ollama for fully local. Mix providers per task.
- Mobile-first PWA. Install on your phone home screen. Works offline — captures sync when you reconnect.
- Rich-text + Markdown. Tiptap editor with task lists and checkboxes; everything still round-trips as plain Markdown.
- Pin what matters. Pin captures, tags, or saved searches to your home page for one-tap recall.
- Inbox tabs. Pin tags as tabs across the top of your inbox to triage by topic, not just by date.
- Addendums. Append follow-up notes to a capture over time — enrichments are versioned, so the history stays intact.
- Plain JSON/Markdown export — and import. Full Lectio JSON round-trip (captures, enrichments, addendums, pins, inbox tabs) plus a Markdown ZIP. If Lectio disappears tomorrow, you keep readable files. Forever.
- MCP server built-in. Plug Lectio into Claude Desktop, Cursor, or any MCP client. Your second brain, reachable from your AI coding environment.
git clone https://github.com/ricalamino/lectio
cd lectio
cp .env.example .env
# Edit .env — set ADMIN_PASSWORD, AUTH_SECRET, and at least one LLM key
docker compose up -dOpen http://localhost:3000 and log in with admin + the password
you set. That's it.
POSTGRES_PASSWORD=change-me
MINIO_ROOT_PASSWORD=change-me
AUTH_SECRET=change-me-32-char-random-string
ADMIN_PASSWORD=your-admin-password
ANTHROPIC_API_KEY=sk-ant-...
LECTIO_ENRICH_PROVIDER=anthropic
LECTIO_ENRICH_MODEL=claude-haiku-4-5
LECTIO_SEARCH_PROVIDER=anthropic
LECTIO_SEARCH_MODEL=claude-haiku-4-5
# No embeddings = lexical search only (still works great)POSTGRES_PASSWORD=change-me
MINIO_ROOT_PASSWORD=change-me
AUTH_SECRET=change-me-32-char-random-string
ADMIN_PASSWORD=your-admin-password
OLLAMA_BASE_URL=http://host.docker.internal:11434
LECTIO_ENRICH_PROVIDER=ollama
LECTIO_ENRICH_MODEL=llama3.2
LECTIO_SEARCH_PROVIDER=ollama
LECTIO_SEARCH_MODEL=llama3.2
LECTIO_EMBED_PROVIDER=ollama
LECTIO_EMBED_MODEL=nomic-embed-text
# nomic-embed-text outputs 768 dimensions — see Embedding note belowEmbedding note: The DB vector column defaults to 1536 dimensions (OpenAI
text-embedding-3-small). If you switch to a different embedding model, you must drop and recreate theembeddingcolumn with the correct dimension before running the worker. Mixing models after existing embeddings exist will cause the vector index to silently produce wrong similarity results.
- Capture — type, paste, or share from any app. Stored raw.
- Enrich — LLM extracts title, summary, tags, entities, suggested actions, a reference date, and a vector embedding. Runs in the background. Add an addendum later and the capture is re-enriched — old enrichment versions are kept.
- Recall — natural-language search across everything you ever captured, with cited sources. Filter by tag chips, browse by date on the calendar, or pin your favorite searches.
On links: today Lectio enriches the text you paste, not the page behind the URL. So a link works best when you drop a sentence of context alongside it ("Why I'm saving this:"). Automatic URL fetch + readability extraction is on the roadmap.
![]() Capture — text or links, processed in the background. |
![]() Search — natural-language answers with cited sources. |

Mobile PWA — installable on the home screen, captures sync when you reconnect.
| Provider | Chat/JSON | Streaming | Embeddings | Status |
|---|---|---|---|---|
| Anthropic | ✅ | ✅ | ❌ | Supported |
| OpenAI | ✅ | ✅ | ✅ | Supported |
| Ollama | ✅ | ✅ | ✅ | Supported |
| ❌ | ❌ | ❌ | Not implemented yet | |
| OpenRouter | ❌ | ❌ | ❌ | Not implemented yet |
| OpenAI-compatible | ❌ | ❌ | ❌ | Not implemented yet |
Configure via .env — see .env.example for all variables and
docs/cost-guide.md for approximate per-capture costs.
- Text capture
- Enrichment pipeline (title, summary, tags, entities, actions, reference date)
- Versioned enrichments + capture addendums
- Semantic + lexical hybrid search with streaming answers
- Tag-filtered search (chips in /search; AND across tags)
- Inbox tabs (pin tags as filtered inbox views)
- Pins (captures, tags, and saved searches on home)
- Calendar view by reference date
- Rich-text editor with task lists / checkboxes (Tiptap)
- PWA with share target + offline capture queue
- MCP server
- Export (JSON + Markdown ZIP) and Lectio JSON import
- Delete / edit captures + retry enrichment
- Automatic URL fetch + readability extraction for link captures
- Weekly digest
- Multi-user
- Plugin system
These paths are scaffolded in the codebase but haven't been end-to-end tested. Treat them as experimental hooks for contributors, not features.
- Voice note transcription (Whisper)
- Image / OCR capture (OpenAI Vision)
- Bulk import (WhatsApp, Notion API, Logseq, Apple Notes, Markdown ZIP)
Items needed before a public Reddit post. Tackled in order.
- Screenshots / demo GIF — inbox, capture, search, mobile, and end-to-end demo GIF in docs/screenshots/.
- Embedding dimension flexibility —
LECTIO_EMBED_DIMENSIONSenv var + clear mismatch error. See.env.examplefor Ollama config. - First-run onboarding — setup banner shows on first login when provider keys are missing, with actionable error messages.
- Better worker error surfacing — enrichment error code + detail shown on capture detail page above the Retry button.
- Honest provider table — provider support table in README shows Google/OpenRouter/OpenAI-compatible as "Not implemented yet".
- Cost documentation — see docs/cost-guide.md for per-capture and per-search estimates per provider/model.
- Backup / restore guide — see docs/backup-restore.md.
- Rate limiting / cost guardrails —
LECTIO_MAX_ENRICH_PER_DAYenv var caps daily enrichments; jobs stay queued for tomorrow. - Troubleshooting guide — see docs/troubleshooting.md.
- Voice + image + import scope tightened — moved to "Not yet" section in roadmap; removed from hero copy. Code remains for contributors but is not claimed as a working feature.
- Comparison table — see docs/comparison.md for honest comparison vs Obsidian, Notion, Logseq, Mem.ai.
- Markdown editor with preview — tabbed Preview/Edit panel with
markdown rendering via
marked(lazy-loaded). - Rich-text editor — Tiptap-based editor with task lists and checkbox items; persists as plain Markdown.
- Lectio JSON import — full round-trip restore of captures, enrichments, addendums, pins, and inbox tabs.
- Mobile navigation polish — fixed sidebar header, tap-to-open inbox rows on small screens, refined layout padding.
- Background Sync PWA — registers a
sync-capturestag on enqueue; SW messages open clients to flush on reconnect. - Architecture diagram — ASCII diagram added to docs/architecture.md.
- Weekly digest — email/push summary of what you captured and which tags were most active.
- Alpha disclaimer — prominent alpha notice added at top of README.
- Reddit post draft — see docs/reddit-post-draft.md for r/selfhosted, r/PKMS, and r/LocalLLaMA drafts + timing notes.
- docs/cost-guide.md — per-capture and per-search cost estimates
- docs/backup-restore.md — how to back up and restore
- docs/troubleshooting.md — common issues and fixes
- docs/comparison.md — comparison with Obsidian, Notion, Logseq, Mem.ai
- docs/architecture.md — package layout and data flow
- docs/llm-providers.md — provider configuration details
PRs welcome. Open an issue first for non-trivial changes.
MIT. Do whatever you want. Forks encouraged.



