WikiMind is a personal LLM-powered knowledge OS. Drop in articles, papers, PDFs, or YouTube links. The LLM compiles them into structured wiki articles. Ask questions against the wiki. The system detects contradictions, orphans, and knowledge gaps. Synthesis generates cross-cutting analyses across sources.
Backend: FastAPI + PostgreSQL + Redis + ARQ workers. Frontend: React + TypeScript + Vite. Deployed on Fly.io with Docker.
Drop URLs, PDFs, or text. Each source is fetched, cleaned, chunked, and compiled into a wiki article by the LLM. Real-time progress via WebSocket.
Full processing pipeline: Fetch → Extract → Clean → Compile. Shows author, token count, ingestion time, and compiled articles.
| Format | Endpoint | Details |
|---|---|---|
| Web URL | POST /api/ingest/url | Articles, blog posts, documentation. Readability extraction. |
| YouTube | POST /api/ingest/url | Auto-detects YouTube URLs, extracts transcript. |
POST /api/ingest/pdf | Upload up to 50 MB. Docling extraction for tables and figures. | |
| Plain text | POST /api/ingest/text | Paste or send raw text content. |
| RSS feeds | POST /api/capture/rss/feeds | Subscribe to feeds. Auto-poll for new items. |
$ curl -X POST http://localhost:7842/api/ingest/url \
-H "Content-Type: application/json" \
-d '{"url":"https://arxiv.org/abs/1706.03762"}'
{
"source_type": "url",
"title": "Attention Is All You Need",
"source_url": "https://arxiv.org/abs/1706.03762",
"id": "393d1cac-83d0-4ec9-88a3-8b43b0f607bc",
"ingested_at": "2026-05-18T19:28:27",
"compiled_at": null ← compiling in background
}
Browse articles with concept facets. Filter by topic, confidence level, page type. Full-text search with ranking.
Structured articles with Summary, Key Claims (with confidence), Analysis, Open Questions, Related links, and Sources. Table of contents, backlinks, and concept tags in sidebar.
[[wiki links]]) resolved across articlesArticles rendered with full rich content support: extracted PDF figures and tables, LaTeX math, syntax-highlighted code blocks, and sanitized HTML. Images extracted via Docling are embedded inline with captions.
5 figures extracted from "The Geometry of Forgetting" (arxiv 2604.06222) rendered in the article's Figures & Tables panel with filter tabs and lightbox zoom.
Figures extracted from PDFs via Docling/pymupdf, stored in Postgres, served via authenticated API.
Tables from PDFs preserved and rendered as styled HTML with zebra rows.
KaTeX for LaTeX math. Syntax-highlighted code blocks with GitHub theme.
Ask questions against your wiki. RAG-powered answers with citations. Conversation threading with history. Fork conversations to explore tangents.
$ curl -X POST http://localhost:7842/api/query \
-H "Content-Type: application/json" \
-d '{"question":"How does BERT differ from GPT?"}'
{
"answer": "BERT uses bidirectional attention...",
"citations": [
{"article": "BERT: Pre-training of...",
"claim": "BERT pre-trains deep bidirectional
representations..."}
],
"conversation_id": "abc123"
}
# Streaming via SSE
POST /api/query/stream
# CLI
$ wikimind ask "How does BERT differ from GPT?"
Guided wizard: choose type (Comparative, Chronological, Thematic, Gap Analysis), select articles, add guidance, review draft.
System detects synthesis opportunities: shared concepts, active contradictions, same topic from different sources. One-click create.
POST /api/wiki/synthesis/preview
{
"article_ids": ["bert","gpt","transformer"],
"synthesis_type": "thematic",
"guidance": "Focus on attention"
}
Returns draft without saving
POST /api/wiki/synthesis/refine
{
"draft_content": "<previous>",
"article_ids": [...],
"guidance": "More detail on
cross-attention"
}
Iterates with feedback
POST /api/wiki/synthesis/confirm
{
"title": "Attention Mechanisms",
"draft_content": "...",
"article_ids": [...]
}
Saves as real wiki article
POST /api/wiki/synthesize
{ "query": "Compare transformer architectures", "synthesis_type": "comparative",
"article_ids": ["bert-id", "gpt-id", "transformer-id"] }
{
"title": "Comparative Analysis of Transformer Architectures: BERT, GPT-3, and Original Transformer",
"themes": ["Bidirectional vs. Autoregressive Models", "Attention Mechanisms", "Task Versatility"],
"source_count": 3,
"page_type": "synthesis"
}
Download as Markdown, Download as JSON, Copy as Markdown. Appears on every article detail page.
Create public share links with configurable expiry: 1 day, 7 days, 30 days, or never. Track view count per link.
# Markdown export
GET /api/wiki/articles/{id}/export?format=markdown
HTTP/1.1 200 OK
content-type: text/markdown; charset=utf-8
content-disposition: attachment; filename="bert-...md"
---
title: "BERT: Pre-training of Deep Bidirectional..."
concepts: [language representation, NLP, transformers]
---
## Summary
BERT is a language representation model...
# Share link with 7-day expiry POST /api/wiki/share-links { "article_id": "d65e8c6b-...", "expires_in_days": 7 } { "token": "o8K1dltPkbfFT-c48...", "expires_at": "2026-05-25T19:29:53", "view_count": 0, "article_title": "BERT: Pre-training..." } # Full wiki export POST /api/wiki/export/wiki Formats: obsidian, markdown_json
Force-directed graph of articles linked by relationships: contradicts, supersedes, extends, synthesizes, references. Filter by concept, confidence, page type. Click nodes to navigate.
| ▬ | contradicts | Conflicting claims between articles |
| ▬ | supersedes | Newer article replaces older |
| ▬ | extends | Builds on another article |
| ▬ | synthesizes | Cross-cutting analysis |
| ▬ | references | Backlinks / wikilinks |
GET /api/wiki/graph
{ "nodes": [...], "edges": [...] }
Used by frontend GraphView component
Automated wiki quality checks run on demand or via background jobs. Detects contradictions, orphaned articles, stale content, and missing links.
LLM analyzes overlapping claims across articles. Surface conflicting statements with article context for resolution.
Finds articles with no inbound links. Suggests connections to related articles.
Identifies articles not recompiled recently. Flags when source content has changed.
POST /api/lint/run # Trigger lint GET /api/lint/reports # List reports GET /api/wiki/contradictions # List contradictions with status PATCH /api/wiki/contradictions/{id} # Resolve or dismiss
Exposes WikiMind as an MCP server for Claude Desktop, Cursor, and other AI agents. Two transports: stdio (local) and HTTP (JWT-authenticated remote).
wiki_overview | Stats |
wiki_list_articles | Browse |
wiki_list_concepts | Taxonomy |
wiki_search | Full-text |
wiki_get_article | Read |
wiki_ask | Q&A |
wiki_ingest_url | Add URL |
wiki_ingest_text | Add text |
wiki_get_source_status | Progress |
wiki_synthesize | Analyze |
wiki_get_health | Health |
wiki_list_sources | Sources |
wiki_get_graph | Graph |
wikimind://index | Article TOC |
wikimind://articles/{slug} | Article content |
wikimind://sources/{id} | Source metadata |
wiki_onboarding | Orientation |
research_topic | Research workflow |
compare_articles | Comparison |
knowledge_gaps | Gap analysis |
OAuth 2.1 Authorization Server for Claude Desktop. JWT tokens for HTTP transport. Per-user access control.
# Start MCP server $ wikimind mcp serve $ wikimind mcp serve --transport http # Claude Desktop config $ wikimind mcp config
System overview: users, articles, sources, concepts, claims, backlinks, orphans, compile rate. Content breakdown by page type, source type, status, and confidence. Operational health: queue depth, stuck sources, LLM traces.
GET /admin/stats # System statistics GET /admin/orphans # Orphaned articles GET /admin/stuck-sources # Stuck in compilation POST /admin/retry-stuck/{id} # Retry POST /admin/sweep # Link sweep POST /admin/reindex # Rebuild search GET /admin/docling-status # PDF extractor status GET /admin/traces # LLM trace logs GET /health/deep # DB + service health
6 providers supported: Anthropic (Claude), OpenAI (GPT), Google (Gemini), Ollama (local), OpenAI-compatible, Mock (testing). Automatic fallback routing. Per-user cost tracking with monthly budget limits.
Real-time spend tracking per provider. Budget enforcement prevents runaway costs. API call counting and breakdown by task type (compilation, query, synthesis, lint).
auth: 5/minute
query: 30/minute
ingest: 10/minute
Request 6: HTTP 429
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded:
5 per 1 minute"
}
}
$ wikimind status # Check server and auth $ wikimind login # Magic link login $ wikimind whoami # Show authenticated user $ wikimind ingest url https://arxiv.org/abs/1706.03762 # Ingest URL $ wikimind ingest file paper.pdf # Ingest PDF $ wikimind ingest text "Some content" # Ingest text $ wikimind ask "How does BERT work?" # Ask against wiki $ wikimind ask --conversation abc123 "And GPT?" # Continue conversation $ wikimind wiki list # List articles $ wikimind wiki list --concept transformers # Filter by concept $ wikimind wiki show bert-pre-training-of... # View article $ wikimind wiki delete some-article # Delete (with confirmation) $ wikimind mcp serve # Start MCP server (stdio) $ wikimind mcp serve --transport http # HTTP transport $ wikimind mcp config # Print Claude Desktop config
| Area | Count | Key Endpoints |
|---|---|---|
| Wiki Management | 13 | GET/PATCH /articles/{id}, GET /concepts, GET /search, GET /graph |
| Content Ingestion | 11 | POST /ingest/url|pdf|text, GET /sources/{id}/detail, RSS feeds |
| Ambient Capture | 7 | POST /capture/{kind}, POST /capture/{id}/ingest|discard |
| Query & Conversations | 8 | POST /query, POST /query/stream, GET /conversations/{id}, fork, file-back |
| Synthesis | 6 | POST /synthesize, preview, refine, confirm, GET /suggestions |
| Quality / Linting | 8 | POST /lint/run, GET /contradictions, PATCH /contradictions/{id} |
| Drafts & Schemas | 8 | GET /sources/{id}/draft, POST /draft/approve|reject, CRUD schemas |
| Tags & Searches | 8 | POST /tags, POST /saved-searches, execute |
| Export & Sharing | 6 | GET /articles/{id}/export, POST /share-links, GET /public/articles/{token} |
| Jobs | 5 | GET /jobs, POST /jobs/compile/{id}, lint, reindex |
| Settings & Auth | 17 | OAuth, magic-link, API keys, MCP tokens, LLM config, cost tracking |
| Admin | 9 | GET /admin/stats, orphans, stuck sources, traces, sweep, reindex |
3 arxiv papers ingested and compiled
Articles with concept facets
Export, Share, Edit buttons. Backlinks sidebar.
Markdown, JSON, clipboard copy
1 day, 7 days, 30 days, Never
4-step guided synthesis creation
Conversational Q&A with history
Articles connected by synthesis links
Processing pipeline: Fetch → Extract → Clean → Compile
System stats, content breakdown, operational health
LLM providers and cost tracking
Token management and cost dashboard
5 figures from arxiv PDF in Figures & Tables panel
Docling-extracted figures with captions
Styled tables, KaTeX math, syntax-highlighted code
Automated test of 138 API endpoints. Idempotent script creates test data and cleans up after itself. Endpoints that trigger LLM calls, require browser OAuth, or are destructive are skipped intentionally.
Run: ./api-test.sh | View script source | Standalone results page
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /health | 200 |
| PASS | GET | /health/deep | 200 |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /auth/me | 200 |
| PASS | POST | /auth/magic-link | 200 |
| PASS | GET | /auth/tokens | 200 |
| PASS | GET | /auth/tokens.js | 200 |
| SKIP | OAuth login, callback, magic-link verify, create token, logout, delete account | browser/destructive |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/ingest/sources | 200 |
| PASS | GET | /api/ingest/sources/{id} | 200 |
| PASS | GET | /api/ingest/sources/{id}/detail | 200 |
| PASS | GET | /api/ingest/sources/{id}/content | 200 |
| PASS | GET | /api/ingest/sources/{id}/images | 200 |
| PASS | POST | /api/ingest/text | 200 |
| PASS | GET | /api/ingest/sources/{pdf_id}/images | 200 |
| PASS | GET | /api/ingest/sources/{pdf_id}/images/picture-1.png | 200 |
| SKIP | Ingest URL, ingest PDF, get original, delete source | LLM cost/destructive |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/ingest/sources/{id}/draft | 404 |
| SKIP | Approve draft, reject draft | requires pending draft |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/wiki/articles | 200 |
| PASS | GET | /api/wiki/articles?page_type=source&limit=5 | 200 |
| PASS | GET | /api/wiki/articles/{slug} | 200 |
| PASS | GET | /api/wiki/articles/{id} | 200 |
| PASS | GET | /api/wiki/articles/{slug}/relationships | 200 |
| PASS | GET | /api/wiki/articles/{id}/tags | 200 |
| PASS | GET | /api/wiki/articles/random | 200 |
| PASS | GET | /api/wiki/search?q=transformer | 200 |
| PASS | GET | /api/wiki/search/facets?q=transformer | 200 |
| PASS | GET | /api/wiki/wikilinks/resolve?q=attention | 200 |
| PASS | GET | /api/wiki/graph | 200 |
| SKIP | Wiki health, create stub, edit, refresh, recompile | deprecated/mutating |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/wiki/concepts | 200 |
| PASS | GET | /api/wiki/concepts/{name} | 200 |
| PASS | GET | /api/wiki/concepts/{name}/articles | 200 |
| SKIP | Rebuild taxonomy | LLM call |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/wiki/contradictions | 200 |
| PASS | GET | /api/wiki/contradiction-resolutions | 200 |
| SKIP | Get/resolve contradiction | none found / mutating |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/wiki/articles/{id}/export?format=markdown | 200 |
| PASS | GET | /api/wiki/articles/{id}/export?format=json | 200 |
| PASS | GET | /api/wiki/articles/{id}/export?format=csv | 422 |
| SKIP | Export PDF, full wiki export | heavy operation |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/wiki/share-links | 200 |
| PASS | POST | /api/wiki/share-links | 201 |
| PASS | GET | /public/articles/{token} | 200 |
| PASS | GET | /public/articles/{token}/json | 200 |
| PASS | GET | /api/wiki/share-links?article_id={id} | 200 |
| PASS | GET | /public/articles/nonexistent-token | 404 |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/wiki/synthesis | 200 |
| PASS | GET | /api/wiki/synthesis/suggestions | 200 |
| PASS | GET | /api/wiki/synthesis/suggestions?limit=3 | 200 |
| PASS | POST | /api/wiki/synthesis/preview | 200 |
| SKIP | Refine, confirm, create (direct) | LLM call / persistent |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/query/conversations | 200 |
| PASS | GET | /api/query/history?limit=5 | 200 |
| PASS | GET | /api/query/conversations/{id} | 200 |
| PASS | GET | /api/query/conversations/{id}/export | 200 |
| SKIP | Ask, stream, fork, file-back, crystallize | LLM call |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/tags | 200 |
| PASS | POST | /api/tags | 201 |
| PASS | POST | /api/wiki/articles/{id}/tags | 201 |
| PASS | GET | /api/tags/{id}/articles | 200 |
| PASS | DELETE | /api/wiki/articles/{id}/tags/{tag_id} | 204 |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/saved-searches | 200 |
| PASS | POST | /api/saved-searches | 201 |
| PASS | POST | /api/saved-searches/{id}/execute | 200 |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/compilation-schemas | 200 |
| PASS | POST | /api/compilation-schemas | 201 |
| PASS | GET | /api/compilation-schemas/{id} | 200 |
| PASS | PATCH | /api/compilation-schemas/{id} | 200 |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/capture | 200 |
| PASS | GET | /api/capture/rss/feeds | 200 |
| PASS | POST | /api/capture/clipboard | 200 |
| SKIP | Ingest capture, subscribe RSS, poll RSS | compilation/external |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/jobs | 200 |
| PASS | GET | /api/lint/reports | 200 |
| PASS | GET | /api/lint/reports/latest | 404 |
| SKIP | Trigger compile/lint/reindex, dismiss finding | LLM call / mutating |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/settings | 200 |
| PASS | GET | /api/settings/llm/cost | 200 |
| PASS | GET | /api/settings/llm/cost/breakdown | 200 |
| PASS | GET | /api/settings/onboarding-status | 200 |
| SKIP | Set provider, update settings, test LLM | config change / external |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/settings/api-keys | 200 |
| PASS | GET | /api/settings/mcp-tokens | 200 |
| PASS | GET | /.well-known/oauth-authorization-server | 200 |
| SKIP | Set/delete API key, create/revoke MCP token, OAuth flow | secrets / browser |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/admin/stats | 200 |
| PASS | GET | /api/admin/orphans | 200 |
| PASS | GET | /api/admin/concepts/eligible | 200 |
| PASS | GET | /api/admin/stuck-sources | 200 |
| PASS | GET | /api/admin/docling-status | 200 |
| PASS | GET | /api/admin/traces | 200 |
| SKIP | Retry stuck, sweep, reindex | mutating |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | POST | /auth/magic-link | 429 |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | GET | /api/nonexistent | 200 |
| PASS | GET | /api/wiki/articles/nonexistent-slug | 404 |
| PASS | POST | /api/ingest/text (empty body) | 422 |
| Status | Method | Path | Code |
|---|---|---|---|
| PASS | DELETE | /api/wiki/share-links/{id} | 204 |
| PASS | DELETE | /api/tags/{id} | 204 |
| PASS | DELETE | /api/saved-searches/{id} | 204 |
| PASS | DELETE | /api/compilation-schemas/{id} | 204 |
| PASS | POST | /api/capture/{id}/discard | 200 |
| PASS | DELETE | /api/ingest/sources/{id} | 200 |