Jargon is an AI-managed zettelkasten that parses articles, papers, and videos into index card-sized key ideas. It summarizing sources, extracts ideas, links related concepts, and collapses duplicates. Semantic embeddings surface connections across the library.
Each source is parsed in context of existing cards, generating new insights that link back to the original material. The result is a knowledge base of interlinked ideas that can be explored directly or used as a RAG to answer questions. Questions also pull results from the web, which flow through the same extract/summarize/link pipeline before being synthesized with library content.
- Ingest — Articles, PDFs, and YouTube videos are scraped and parsed
- Summarize — LLM distills each source into a concise summary
- Extract — Key ideas become standalone insight cards with source links
- Connect — Embeddings find related insights; duplicates collapse automatically
- Thread — Each node gets research questions that search the web for more sources
Academic papers and PDFs are automatically downloaded and converted to text using pdftotext. Jargon follows "full text" and DOI links from abstracts.
YouTube URLs are detected and transcripts are fetched directly from YouTube's API. Speakers are extracted from video titles when available.
Key findings are extracted as standalone insights with titles, explanations, and source snippets. Insights are independently searchable and linkable.
Articles and insights are embedded using OpenAI's text-embedding-3-small model. Embeddings power similarity search and automatic clustering.
Similar articles (syndicated content, republished pieces) are automatically grouped using vector similarity and title matching. Similar insights cluster into themes.
Each insight can spawn research threads—questions that trigger web searches via Exa to find related articles. Discovered articles are automatically ingested and indexed.
Ask a question or enter a topic to search your library. Jargon finds relevant insights using semantic similarity and displays them alongside the source articles.
Augment library results with fresh content from the web. Results are fetched via Exa's neural search and automatically ingested into your library.
- Rails and Hotwire
- Falcon - Async Ruby application server with fiber-based concurrency
- async-job - Background job processing without a separate worker process
- RubyLLM - Unified interface to OpenAI, Anthropic, Gemini, and OpenRouter
- ruby_llm-schema - Structured JSON output from LLMs via schema definitions
- pgvector - Vector similarity search in PostgreSQL
- Exa - Neural search API for finding related content
- crawl4ai - Fallback web scraper with browser rendering
- pdftotext - Text extractor for PDF content
Copy .env.example to .env and configure:
Set API keys for the providers you want to use. RubyLLM supports OpenRouter, OpenAI, Anthropic, and Google Gemini:
OPENROUTER_API_KEY=your-key # OpenRouter (default, proxies all providers)
OPENAI_API_KEY=your-key # Direct OpenAI access
ANTHROPIC_API_KEY=your-key # Direct Anthropic access
GEMINI_API_KEY=your-key # Direct Google Gemini accessOverride default models and providers via environment variables:
LLM_MODEL=google/gemini-2.5-flash # Chat model (default)
LLM_PROVIDER=openrouter # Chat provider (default)
EMBEDDING_MODEL=openai/text-embedding-3-small # Embedding model (default)
EMBEDDING_PROVIDER=openrouter # Embedding provider (default)Provider must match the API key you're using. OpenRouter model names use provider/model format.
Set SECRET_KEY_BASE instead of using config/master.key:
SECRET_KEY_BASE=secret-key-baseFallback crawler when Exa is unavailable. Install via pip:
pip install crawl4ai
crawl4ai-setup # Downloads browser dependenciesUsed for extracting text from PDF documents (academic papers, etc.). Install via poppler:
# macOS
brew install poppler
# Ubuntu/Debian
apt-get install poppler-utilsRun Jargon with Docker Compose using the published image from GitHub Container Registry.
Create a docker-compose.yml:
services:
jargon:
image: ghcr.io/schoblaska/jargon:latest
ports:
- "3000:80"
env_file: .env
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/jargon
REDIS_URL: redis://redis:6379/0
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: pgvector/pgvector:pg17
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: jargon
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:Create a .env file with your secrets:
SECRET_KEY_BASE=secret-key-base
OPENROUTER_API_KEY=your-openrouter-key
EXA_API_KEY=your-exa-keyStart the stack:
The app will be available at http://localhost:3000.
- replace Exa with Brave search and use crawl4ai to ingest
- do parallel searches across multiple LLM-generated queries?
- refactor IngestArticleJob
- define schemas inline where they're used
- export markdown to clipboard
- full text search
- generate search query async
- don't show superseded insights in autocomplete
- youtube thumbnails as article image
- visual distinction between articles and ideas






