Personal knowledge base
Search Obsidian, Logseq, Zettelkasten or plain Markdown vaults by meaning, not by filename.
Soma · Local-first semantic search
A semantic search engine for your own documents, PDFs, images, audio and video. Every model runs on your machine. 100% offline, no cloud, no API keys — one single binary.
Windows x64 · macOS ARM64 · Linux x64 — free and open source
Requests are authenticated at the gateway: the JWT is verified, then the session is resolved against the user store before routing downstream.
Every request is treated as untrusted; identity is re-established per hop, and authorization decisions are made at the edge proxy.
“…so login goes through the gateway now — the token refresh is the part that still breaks after a deploy.”
Whiteboard diagram showing client → gateway → auth service → user store, with a dashed line for token refresh.
bytes leaving your machine
single native binary
search modes: hybrid · lexical · vector
file families indexed, from PDF to video
Private by design
Cloud “AI search” understands what you mean — after you upload your notes, contracts, research papers and meeting recordings to somebody else’s server. Soma keeps all of it, and all of the intelligence, here.
Indexing, embedding, reranking and searching all happen on-device. There is no telemetry, no account and no background daemon you didn’t ask for.
Soma bundles a local inference stack — llama.cpp and whisperfile — and downloads open-weight models. No OpenAI key. No subscription.
Export every model and tool as one reproducible ZIP on a connected machine, then --import it on an isolated one. Zero HTTP at runtime.
Soma never modifies your source files. The index is fully derived state — if it ever breaks, soma sync rebuilds it.
Mental model
That’s the whole product. Point Soma at a folder, let it read and understand the contents once, then ask questions in plain language — or hunt for an exact phrase.
# 1. point Soma at a folder $ soma project add ~/notes # 2. index + extract + embed (fully local) $ soma sync # 3. ask in plain language $ soma search "how does auth work" --limit 3 1. soma://notes/api/authentication.md @a1b2c3 Requests are authenticated at the gateway: the JWT is verified, then the session is resolved against the user store before routing downstream. 2. soma://notes/runbooks/login-failures.md @d4e5f6 ...
Features
Lexical BM25 + dense embeddings + a HyDE passage, fused with Reciprocal Rank Fusion and reranked by a local LLM. Best relevance, out of the box.
Prefix matching, "quoted phrases", -exclusions and per-project scoping. BM25 ranked — fast, deterministic, no models involved.
Unicode NFKC normalization, camelCase / snake_case / path tokenization, plus CJK unigram + bigram indexing so 1–2 character queries still work.
soma server serves a single-file browser interface on localhost:8181 — search, projects, status and documents.
JSON / CSV / Markdown / paths output and a JSON-RPC-style POST /api/run endpoint that mirrors the CLI. One contract to learn.
EmbeddingGemma for embeddings, QMD for query expansion, Qwen3 Reranker, Qwen3-VL for images and Whisper for speech — all via llama.cpp / whisperfile, on CPU or GPU.
Run soma init to keep config and index inside ./.soma/ so the index travels with the folder. Attach descriptive hints to a path to sharpen relevance and snippets.
Search modes
A local LLM expands your query into lexical keywords, dense
retrieval sentences and a HyDE passage. Every signal is fused with RRF, then reranked locally.
Override any channel by hand with --lex, --vec,
--hyde, or add background with --intent.
$ soma search "how does auth work" $ soma s "performance" --intent "web page load times" $ soma search hybrid --lex "CAP theorem" \ --vec "consistency tradeoffs"
BM25 ranked, no embeddings, no LLM — fast and deterministic.
word — prefix match (perf → performance)"phrase" — exact phrase-word / -"phrase" — exclude$ soma search lexical "CAP theorem consistency" $ soma search lexical '"machine learning" -"deep learning"' $ soma search lexical "auth -oauth -saml" --line-number
Embeds your query directly and searches by meaning — no expansion, no HyDE, no reranking. The leanest semantic path.
$ soma search vector "what happens when a pod crashes" $ soma s v "login failures" --intent "auth troubleshooting"
Write what a good matching document would say, and search with that. Great when you remember the shape of the answer but none of the words in the file.
$ soma search --hyde "The rate limiter uses a sliding window with a 60-second window. Clients exceeding 100 requests per minute receive 429 Too Many Requests."
All search and get commands support
-f text|json|csv|md|paths — pipe straight into scripts, editors or AI agents.
How it works
Run soma sync: pull → scan → extract → embed → clean.
.gitignore awareExpansion, embedding, retrieval and reranking — every stage runs on your hardware.
Supported file types
Multimedia extraction is optional — text-only indexing runs happily on a modest machine.
Indexed directly, with camelCase / snake_case / path-aware tokenization.
Text-layer extraction, page by page, then chunked and embedded.
Converted to Markdown via Pandoc, then chunked and embedded.
OCR text plus a vision-LLM description, so a whiteboard photo becomes findable.
FFmpeg + Whisper transcription. Transcribe once, then search what was actually said.
Audio track extracted and transcribed, timestamps kept for jump-to-moment snippets.
Web UI & HTTP API
soma --help already knows the API.$ soma server --auto-sync # http://localhost:8181 $ soma server --port 8080
GET / | Built-in web interface |
|---|---|
GET /health | Health check |
GET /assets/… | Raw file under a project root |
POST /api/run | JSON RPC mirroring the CLI |
$ curl -s localhost:8181/api/run \ -H 'Content-Type: application/json' \ -d '{"command":"search.hybrid", "args":["how does auth work"], "options":{"limit":5,"format":"json"}}' { "success": true, "requestId": "xxx", "durationMs": 124, "exitCode": 0, "data": { ... }, "stdout": "", "stderr": "", "error": null }
Perfect for local RAG, coding assistants, MCP-style tooling and automation — with no vector database to operate.
Soma vs. other search tools
| Soma | grep / ripgrep | Spotlight / Windows Search | Cloud AI search | |
|---|---|---|---|---|
| Natural-language questions | ✓ | ✕ | ✕ | ✓ |
| Exact keyword / phrase (BM25) | ✓ | ✓ regex | partial | varies |
| PDF / Office / EPUB content | ✓ | ✕ | partial | ✓ |
| Images (OCR + vision) | ✓ | ✕ | partial | varies |
| Audio / video transcripts | ✓ | ✕ | ✕ | varies |
| Runs fully offline | ✓ | ✓ | ✓ | ✕ |
| Data leaves your machine | never | never | never | yes |
| Scriptable JSON output + HTTP API | ✓ | ✓ | ✕ | ✓ |
| Setup | one binary | one binary | built in | account + upload |
Use cases
Search Obsidian, Logseq, Zettelkasten or plain Markdown vaults by meaning, not by filename.
Semantic search across hundreds of papers and books, by meaning.
Find “where is retry logic handled” without knowing the function name.
Transcribe recordings once, then search what was actually said — down to the timestamp.
OCR plus vision descriptions make years of screenshots and photos findable.
A private retrieval layer with JSON output and an HTTP API. No vector DB to run.
Legal, medical, defense and finance environments where cloud search is simply not an option.
Get Soma
A single GraalVM native binary. No Python, no Docker, no vector database service. Pick your platform.
# macOS (Apple Silicon) · Homebrew $ brew install AwesomeDog/tap/soma $ soma --version
# Windows x64 · winget > winget install AwesomeDog.soma > soma --version
# Linux x64 · npm — the launcher preloads libm for you $ npm install -g @awesomedog/soma $ soma --version
Prefer the standalone binary? Download soma-linux-x64
from Releases and run it with
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libm.so.6 (or your distro's libm.so.6
path).
# On a machine with internet $ soma system pull --export soma-artifacts.zip # On the air-gapped machine (no HTTP performed) $ soma system pull --import soma-artifacts.zip
The export is reproducible — identical package hashes produce a byte-identical ZIP — and covers every supported platform.
Tech specs
syncsync or system pullllama.cpp · whisperfilesqlite-vec vectors$XDG_CONFIG_HOME/soma/<ws>.yml$XDG_STATE_HOME/soma/<ws>.sqlite$XDG_STATE_HOME/soma/caches/$XDG_STATE_HOME/soma/{logs,locks}/$XDG_DATA_HOME/soma/soma ├── project add <root> · list (ls) · files <path> · update · remove · rename · show ├── sync # pull → scan → extract → embed → clean ├── search (s) [hybrid (h)] · lexical (l) · vector (v) │ --lex --vec --hyde --intent · -p/--project · --limit · --no-limit │ --full · --line-number · -f/--format [text|json|csv|md|paths] ├── get @docid | soma://project/path | project/path | ./file │ --start-line · --max-lines · --line-number · --max-size · -f/--format ├── server [http] [--port <n>] [--auto-sync] # web UI + HTTP API ├── context list (ls) · set <path> <text> · remove <path> [-p/--project] ├── status # workspace, index and artifact status ├── init # create directory-local workspace (.soma/) └── system pull [--refresh | --export | --import] · scan · extract · embed [-p] · clean GLOBAL: -w/--workspace | -v/--verbose [SOMA_VERBOSE=1] --no-color [NO_COLOR=1] | -h/--help | -V/--version WORKSPACE: -w/--workspace > directory-local > SOMA_DEFAULT_WORKSPACE > XDG 'main'
FAQ
soma sync / soma system pull), which you can also do offline via
--export / --import.llama.cpp, whisperfile) and
downloads open-weight models.ripgrep?ripgrep matches literal strings and regexes in text files. Soma additionally
understands meaning, and can search inside PDFs, Office documents, images, audio and video.-f json from the CLI or POST /api/run over HTTP. The API
mirrors the CLI, so there is only one contract to learn.soma init in a folder to keep config and
index in ./.soma/, so the searchable index travels with the directory.soma sync for the normal cycle, soma system scan for a full re-read of
every file, soma status for diagnostics.Add a project, run sync,
and start asking questions.