Obsidian Hybrid Search
Servidor MCP local-first para pesquisar vaults privados do Obsidian com recuperação híbrida de texto completo, fuzzy, semântica e de grafo de wikilinks.
Documentação
Obsidian Hybrid Search
Seu cofre do Obsidian já contém suas melhores ideias. O Obsidian Hybrid Search torna essas ideias mais fáceis de encontrar, reutilizar e incorporar ao trabalho assistido por IA.
Ele dá ao seu cofre um único mecanismo de recuperação e três formas práticas de usá-lo. O plugin nativo do Obsidian oferece busca rápida, pré-visualizações, notas semelhantes, descoberta de links e visualizações de grafo enquanto você escreve. O servidor MCP permite que agentes de IA pesquisem e leiam suas notas por meio de chamadas de ferramenta. A CLI oferece aos usuários avançados o mesmo mecanismo para indexação, filtragem, reordenação, leitura e script.
A busca entende como cofres reais são construídos. Ela combina busca semântica, texto completo BM25, correspondência difusa de títulos e aliases, tags, pastas, frontmatter, wikilinks, backlinks e consulta de notas semelhantes. Você pode pesquisar por ideia, frase, título, relacionamento ou metadados sem precisar lembrar as palavras exatas que escreveu.
Isso transforma o Obsidian em um sistema de conhecimento pessoal mais forte e em um melhor ponto de partida para o trabalho com IA. Os agentes podem começar pelas suas próprias notas, extrair contexto citado dos arquivos de origem, seguir material relacionado e trabalhar com conhecimento em que você já confia. O OHS roda localmente por padrão com SQLite, FTS5, sqlite-vec, ranqueamento RRF e APIs de embeddings opcionais compatíveis com OpenAI.
Qualidade da busca
Avaliado no cofre Obsidian Help (171 notas, 58 consultas, modelo local):
| OHS (este projeto) | qmd | |
|---|---|---|
| nDCG@5 | 0.733 | 0.659 |
| MRR | 0.788 | 0.665 |
| Hit@1 | 0.724 | 0.500 |
| Tempo médio de consulta | 571 ms ¹ | 754 ms ² |
| Download do modelo | ~117 MB | ~2.2 GB |
¹ CPU (Apple Silicon), modo híbrido, sem reordenação. ² GPU (Apple Silicon Metal), expansão de consulta por LLM + reordenação.
O OHS usa Xenova/multilingual-e5-small. Como reproduzir → · Benchmark completo →
Benchmark de cofre de conhecimento real
O OHS também é avaliado nas notas públicas evergreen de Andy Matuschak, convertidas em um cofre do Obsidian com nomes de arquivo baseados em títulos, URLs de origem no frontmatter, anexos locais e 5,000+ links internos de notas em 1,357 notas.
O conjunto dourado curado inclui 78 consultas avaliadas manualmente abrangendo busca de itens conhecidos, paráfrases, fragmentos de citações, tópicos ambíguos, busca de citações e evidências em múltiplas notas.
Usando o modelo de embeddings local padrão, o OHS apresenta desempenho forte nessa rede densa de notas.
| Métrica | Valor |
|---|---|
| nDCG@5 | 0.722 |
| nDCG@10 | 0.753 |
| MRR | 0.874 |
| Hit@1 | 0.795 |
| Hit@5 | 0.974 |
| Recall@10 | 0.972 |
| AllRel@10 | 0.949 |
O benchmark exercita a recuperação em um cofre de conhecimento real altamente conectado, incluindo consultas que não simplesmente repetem títulos de notas.
JSON de resultados · Reproduzir e interpretar →
Benchmark de memória em larga escala
Para testar a recuperação em um conjunto de dados público maior, o LongMemEval-S foi convertido em um cofre no estilo Obsidian com 22,419 notas e 470 consultas de recuperação. Usando embeddings baai/bge-m3, o OHS classificou fortemente as notas que contêm as respostas:
| Métrica | Valor |
|---|---|
| nDCG@5 | 0.895 |
| MRR | 0.920 |
| Hit@1 | 0.889 |
| Hit@5 | 0.968 |
| Recall@10 | 0.950 |
| AllRel@10 | 0.904 |
Para este benchmark, cada consulta usa o haystack fornecido pelo LongMemEval como escopo de busca. Isso torna o resultado reproduzível e fácil de inspecionar consulta por consulta, ao mesmo tempo em que exercita a recuperação em um grande cofre de memória gerado.
JSON de resultados · Reproduzir e interpretar →
Recursos
- Busca híbrida
- BM25 + título difuso + embeddings semânticos, fundidos com RRF
- Busca por alias
- notas com
aliases:no frontmatter são indexadas e pesquisáveis por qualquer alias; correspondências de alias são reforçadas no BM25 (peso 5×) e na pontuação de título difuso
- notas com
- Quatro modos de busca
hybrid,semantic,fulltext,title(para consultas de texto)
- Consulta de notas semelhantes
- passe
--pathpara encontrar notas semanticamente relacionadas usando embeddings de trechos armazenados, com fallback de título + conteúdo
- passe
- Travessia de grafo
--path --relatedmostra notas vinculadas em profundidade configurável; filtre por--direction outgoing|backlinks|both
- Links e backlinks
- cada resultado inclui links de saída e backlinks
- Filtragem de escopo
- restrinja a subpasta(s); suporta múltiplos valores e exclusões (
-notes/dev/)
- restrinja a subpasta(s); suporta múltiplos valores e exclusões (
- Filtragem por tags
- filtre por tag(s); suporta múltiplos valores e exclusões (
-category/cs)
- filtre por tag(s); suporta múltiplos valores e exclusões (
- Controle de trechos
--snippet-lengthdefine a janela de contexto; trechos vazios sempre recorrem ao conteúdo da nota
- Saída estendida
--extendedadiciona uma coluna TAGS/ALIASES à tabela da CLI mostrando tags do frontmatter (#tag) e aliases
- Indexação incremental
- reindexa apenas arquivos alterados; observa edições em tempo real
- Fan-out de múltiplas consultas
- passe múltiplas consultas de uma vez (
ohs "q1" "q2"ouqueries[]no MCP); os resultados são mesclados via RRF, então uma nota que se classifica bem em qualquer consulta sobe para o topo; útil quando a nota pode usar vocabulário diferente da consulta
- passe múltiplas consultas de uma vez (
- Reordenação por cross-encoder
--rerankre-pontua resultados combge-reranker-v2-m3(ONNX int8, download único de ~570 MB); melhora a precisão para consultas conceituais e multilíngues; aplicado após a mesclagem de múltiplas consultas
- Embeddings locais
- funciona offline via
@huggingface/transformers(sem necessidade de chave de API); modelo padrão: Xenova/multilingual-e5-small, 100+ idiomas
- funciona offline via
- Embeddings remotos
- API compatível com OpenAI (OpenRouter, Ollama, etc.)
- Leitura de notas
readbusca uma ou mais notas por caminho relativo ao cofre; retorna o conteúdo completo com título, aliases, tags, links e backlinks; em caso de caminho não encontrado, retorna as 3 principais sugestões difusas
- Padrões de ignorar
- exclua pastas, extensões ou arquivos específicos
- Plugin do Obsidian
- modal de busca nativo dentro do Obsidian alimentado pela mesma CLI; veja obsidian-hybrid-search-plugin
Instalação
npm install -g obsidian-hybrid-search
Uso da CLI
Início rápido
A configuração recomendada é definir OBSIDIAN_VAULT_PATH uma vez em ~/.zshrc ou ~/.bashrc. Isso permite executar a CLI de qualquer diretório.
export OBSIDIAN_VAULT_PATH="/path/to/your/vault"
Abra um novo terminal e indexe o cofre uma vez.
ohs reindex
Agora você pode pesquisar de qualquer diretório.
ohs "zettelkasten"
Executar a partir de um cofre
Alternativamente, execute a CLI sem variável de ambiente a partir de qualquer diretório dentro do seu cofre. Ela encontra a raiz do cofre subindo até a pasta .obsidian/ mais próxima.
cd /path/to/your/vault
ohs reindex
ohs "zettelkasten"
Fora do cofre, defina OBSIDIAN_VAULT_PATH ou passe --db /path/to/vault/.obsidian-hybrid-search.db explicitamente.
Embeddings remotos opcionais
Por padrão, a CLI usa o modelo local Xenova/multilingual-e5-small. Ele funciona offline sem chave de API, baixa cerca de 117 MB no primeiro uso e suporta mais de 100 idiomas.
Para usar uma API remota, adicione suas configurações ao seu perfil de shell.
export OPENAI_API_KEY="sk-..."
# Override the default API base for another provider
# export OPENAI_BASE_URL="https://openrouter.ai/api/v1" # OpenRouter
# export OPENAI_BASE_URL="http://localhost:11434/v1" # Ollama (no key needed)
# export OPENAI_BASE_URL="http://localhost:1234/v1" # LM Studio (no key needed)
# Override the default text-embedding-3-small model
# export OPENAI_EMBEDDING_MODEL="text-embedding-3-small"
Modos de busca
A CLI suporta quatro modos de busca chamados hybrid, fulltext, semantic e title, além de travessia de grafo para notas vinculadas. Os comandos abaixo mostram como usá-los, aplicar filtros, reordenar resultados e controlar a saída.
# Hybrid search (default)
ohs "zettelkasten atomic notes"
# Fulltext BM25 search
ohs "permanent notes" --mode fulltext
# Fuzzy title search (fast, typo-tolerant)
ohs "zettleksten" --mode title
# Semantic / vector search
ohs "how to build a knowledge graph" --mode semantic
# Limit results and set a score threshold
ohs "productivity systems" --limit 5 --threshold 0.3
# Restrict to a subfolder
ohs "daily review" --scope notes/periodic/
ohs "daily review" --folder notes/periodic/ # alias for --scope
# Restrict to multiple subfolders (OR)
ohs "productivity" --scope notes/pkm/ --scope notes/2024/
# Exclude a subfolder
ohs "programming" --scope notes/ --scope -notes/archive/
# Filter by tag
ohs "productivity" --tag pkm
ohs "machine learning" --tag note/basic/primary
# Filter by multiple tags (AND include, exclude with -)
ohs "learning" --tag pkm --tag work
# Filter by frontmatter / properties (exact match, case-insensitive)
ohs "notes" --frontmatter status:todo
ohs "notes" --prop priority:high # --prop is alias for --frontmatter
# Filter by multiple frontmatter fields (AND)
ohs "notes" --frontmatter status:todo --frontmatter priority:high
# Exclude by frontmatter value
ohs "notes" --frontmatter -status:done
# Filter-only mode: no query, just filters (returns all matching notes sorted by title)
ohs --frontmatter status:todo
ohs --folder notes/2024/
ohs --tag pkm
ohs --frontmatter status:done --tag archived
# Unlimited results in filter-only mode (default limit is 10)
ohs --folder notes/ --limit 0
# Find semantically similar notes
ohs --path notes/pkm/zettelkasten.md
# Graph traversal: show notes linked to/from this note
# Results show depth: -1/-2 = backlinks, 0 = source, +1/+2 = outgoing links
ohs --path notes/pkm/zettelkasten.md --related
ohs --path notes/pkm/zettelkasten.md --related --depth 2
# Only outgoing links (what this note references)
ohs --path notes/pkm/zettelkasten.md --related --direction outgoing
# Only backlinks (who references this note)
ohs --path notes/pkm/zettelkasten.md --related --direction backlinks
# Traverse standard Markdown note links instead of Obsidian wikilinks
ohs --path notes/pkm/zettelkasten.md --related --link-type markdown
# Traverse both wikilinks and standard Markdown note links
ohs --path notes/pkm/zettelkasten.md --related --link-type all
# Longer context around each link
ohs --path notes/pkm/zettelkasten.md --related --snippet-length 500
# Rerank results with a cross-encoder model (improves precision, ~1-3s extra latency)
# Downloads bge-reranker-v2-m3 ONNX (~570 MB) on first use, cached in ~/.cache/huggingface/
ohs "zettelkasten atomic notes" --rerank
# Show tags and aliases alongside results
ohs "zettelkasten" --extended
# JSON output (for scripting)
ohs "spaced repetition" --json
# Output only paths (one per line) — useful for piping into read
ohs --frontmatter id:OHS-4 --only-paths
ohs read ${(f)"$(ohs search --frontmatter status:todo --only-paths)"} # zsh: read all matching notes
# Output absolute filesystem paths
ohs "zettelkasten" --only-absolute-paths
# Open results in Obsidian (each in a new tab)
ohs "zettelkasten" --open
# Reindex the vault
ohs reindex
# Force full reindex
ohs reindex --force
# Reindex a single file
ohs reindex notes/pkm/zettelkasten.md
# Retry only the notes whose chunks failed to embed
ohs reindex --errors
# Show indexing status
ohs status
# Show recent indexing activity
ohs status --recent
# Show chunks that failed to embed
ohs status --errors
# Read a note by path (outputs body content without frontmatter)
ohs read notes/pkm/zettelkasten.md
# Read raw file from vault (with frontmatter, like cat)
ohs read notes/pkm/zettelkasten.md --raw
# Read multiple notes (separator between each)
ohs read notes/pkm/zettelkasten.md notes/pkm/evergreen-notes.md
# Cap content length
ohs read notes/pkm/zettelkasten.md --snippet-length 2000
# Structured output with all metadata
ohs read notes/pkm/zettelkasten.md --json
Aliases de shell
Adicione ao seu ~/.zshrc ou ~/.bashrc para acesso rápido:
alias ohss='ohs --mode semantic'
alias ohst='ohs --mode title'
alias ohsf='ohs --mode fulltext'
alias ohsr='ohs read'
alias ohsi='ohs reindex'
alias ohsst='ohs status'
Em seguida, recarregue (source ~/.zshrc) e use:
ohs "zettelkasten" # hybrid search
ohss "how to build a knowledge graph" # semantic
ohst "zettelkasten" # fuzzy title (typo-tolerant)
ohsf "permanent notes" # fulltext BM25
ohsr "notes/pkm/zettelkasten.md" # read note by path
ohsi # reindex vault
ohsst # show status
ohsst --recent # show recent indexing activity
ohsst --errors # show chunks that failed to embed
Exemplo de saída
A busca híbrida retorna uma tabela com pontuações e trechos. As pontuações são codificadas por cores de acordo com a relevância:
| Pontuação | Cor | Significado |
|---|---|---|
| 0.8 – 1.0 | verde | Altamente relevante |
| 0.5 – 0.8 | amarelo | Moderadamente relevante |
| 0.2 – 0.5 | sem cor | Parcialmente relevante |
| 0.0 – 0.2 | esmaecido | Baixa relevância |
┌───────┬───────────────────────────────┬────────────────────────────────────────────┐
│ SCORE │ PATH │ SNIPPET │
├───────┼───────────────────────────────┼────────────────────────────────────────────┤
│ 0.98 │ notes/pkm/zettelkasten.md │ A note-taking method developed by Niklas │
│ │ │ Luhmann. Each note contains one atomic... │
├───────┼───────────────────────────────┼────────────────────────────────────────────┤
│ 0.72 │ notes/pkm/evergreen-notes.md │ Evergreen notes are written to evolve over │
│ │ │ time. Unlike fleeting notes, they are... │
└───────┴───────────────────────────────┴────────────────────────────────────────────┘
Com --extended, uma coluna TAGS/ALIASES é adicionada. As tags são prefixadas com #, os aliases são exibidos como estão:
┌───────┬───────────────────────────────┬──────────────────┬──────────────────────────────┐
│ SCORE │ PATH │ TAGS/ALIASES │ SNIPPET │
├───────┼───────────────────────────────┼──────────────────┼──────────────────────────────┤
│ 0.98 │ notes/pkm/zettelkasten.md │ #pkm │ A note-taking method... │
│ │ │ ЗК │ │
│ │ │ slip-box │ │
├───────┼───────────────────────────────┼──────────────────┼──────────────────────────────┤
│ 0.72 │ notes/pkm/evergreen-notes.md │ #pkm │ Evergreen notes are written │
│ │ │ #writing │ to evolve over time... │
└───────┴───────────────────────────────┴──────────────────┴──────────────────────────────┘
O modo de título omite a coluna de trechos automaticamente.
Servidor MCP
A maioria dos assistentes de IA opera sem acesso ao seu conhecimento pessoal e só consegue trabalhar com o que você cola na conversa. Adicionar este servidor dá a qualquer assistente compatível com MCP um índice persistente e pesquisável de todo o seu cofre. Isso se torna uma chamada de ferramenta, não uma sessão de copiar e colar: o assistente consulta suas notas da mesma forma que chama qualquer outra ferramenta, obtém resultados classificados com trechos e links e pode navegar pelo seu grafo de conhecimento sob demanda.
Adicione à sua configuração MCP (.mcp.json, claude_desktop_config.json ou equivalente para o seu cliente).
Configuração mínima (embeddings locais, sem chave de API)
Usa o modelo integrado Xenova/multilingual-e5-small. Funciona totalmente offline e suporta 100+ idiomas. Baixa ~117 MB na primeira execução.
{
"mcpServers": {
"obsidian-hybrid-search": {
"command": "npx",
"args": ["-y", "-p", "obsidian-hybrid-search@latest", "obsidian-hybrid-search-mcp"],
"env": {
"OBSIDIAN_VAULT_PATH": "/path/to/your/vault"
}
}
}
}
Configuração completa (OpenRouter)
{
"mcpServers": {
"obsidian-hybrid-search": {
"command": "npx",
"args": ["-y", "-p", "obsidian-hybrid-search@latest", "obsidian-hybrid-search-mcp"],
"env": {
"OBSIDIAN_VAULT_PATH": "/path/to/your/vault",
"OBSIDIAN_PREFIX": "myvault_",
"OBSIDIAN_RESPECT_GITIGNORE": "true",
"OBSIDIAN_IGNORE_PATTERNS": ".obsidian/**,templates/**,*.canvas",
"OBSIDIAN_INCLUDE_PATTERNS": "private/notes/**",
"OPENAI_API_KEY": "sk-or-v1-...",
"OPENAI_BASE_URL": "https://openrouter.ai/api/v1",
"OPENAI_EMBEDDING_MODEL": "openai/text-embedding-3-small"
}
}
}
}
Nota: Na primeira execução,
npxinstalará o pacote automaticamente. Os padrões de ignorar são persistidos no banco de dados e restaurados em toda inicialização subsequente, mesmo que a variável de ambiente esteja ausente.
Servidor HTTP compartilhado
Use isto quando vários clientes MCP precisarem compartilhar um único processo de busca/indexação de longa duração.
Inicie ou reutilize o servidor em segundo plano:
OBSIDIAN_VAULT_PATH="/path/to/your/vault" ohs serve
serve inicia o servidor MCP via HTTP por padrão; serve --http é o equivalente explícito. O comando imprime a URL do servidor, o PID, o caminho do log e um trecho de configuração do cliente. O endereço de bind padrão é 127.0.0.1:3939.
Em seguida, adicione isto a uma configuração de cliente MCP baseada em URL (.mcp.json, claude_desktop_config.json ou equivalente):
{
"mcpServers": {
"obsidian-hybrid-search": {
"url": "http://127.0.0.1:3939/mcp"
}
}
}
Gerencie o servidor:
ohs serve status
ohs serve stop
ohs serve --foreground
ohs serve --http --foreground
O modo HTTP usa MCP Streamable HTTP sem estado. Ele não emite nem valida Mcp-Session-Id, então um cliente MCP pode continuar fazendo chamadas de ferramenta após o daemon reiniciar, mesmo que ainda envie um cabeçalho de sessão obsoleto. Este modo é destinado às ferramentas de requisição/resposta do servidor e não fornece streams SSE persistentes, notificações iniciadas pelo servidor ou retomada de SSE.
Se a porta 3939 já estiver em uso, o comando sai com um erro em vez de escolher outra porta automaticamente. Use --port para cofres separados.
Ao vincular além do localhost, permita todos os hostnames ou endereços que os clientes MCP usarão.
ohs serve \
--host 0.0.0.0 \
--allowed-host 192.168.1.20:3939 \
--allowed-host notes.example.com:3939
Repita --allowed-host para múltiplos valores. Você também pode definir uma lista separada por vírgulas com OBSIDIAN_MCP_ALLOWED_HOSTS. A opção --allow-any-host desativa a proteção do cabeçalho Host para redes confiáveis.
Ferramentas MCP disponíveis
| Ferramenta | Descrição |
|---|---|
search | Pesquise no vault. Use query para busca de texto (mode: hybrid/semantic/fulltext/title) ou path para similaridade semântica. Combine path com related: true para travessia de grafo. Passe queries[] para fan-out de múltiplas consultas (busca paralela, fusão RRF). Suporta scope, tag, limit, threshold, depth, direction, snippet_length, rerank |
read | Busca uma ou mais notas por caminho relativo ao vault. Retorna conteúdo completo, título, aliases, tags, links e backlinks. Em caso de caminho não encontrado: retorna found: false com as 3 principais sugestões difusas. Aceita um único caminho ou um array. Use snippet_length para limitar o tamanho do conteúdo |
reindex | Reindexa o vault ou um arquivo específico |
status | Mostra o total de notas, a contagem indexada e o horário da última indexação |
Defina OBSIDIAN_PREFIX para adicionar um prefixo a cada nome de ferramenta. Por exemplo, myvault_ produz myvault_search e myvault_read. O prefixo fica vazio por padrão.
Configuração
| Variável de ambiente | Padrão | Descrição |
|---|---|---|
OBSIDIAN_VAULT_PATH | Obrigatório para MCP; a CLI detecta automaticamente | Caminho absoluto para o seu vault |
OBSIDIAN_PREFIX | "" | Prefixo opcional de ferramenta MCP, ex.: myvault_ → myvault_search, myvault_read |
OBSIDIAN_IGNORE_PATTERNS | .obsidian/**,templates/**,*.canvas | Padrões de ignorar separados por vírgula |
OBSIDIAN_RESPECT_GITIGNORE | true | Lê arquivos .gitignore raiz e aninhados; defina como false para desativar |
OBSIDIAN_INCLUDE_PATTERNS | "" | Padrões separados por vírgula para re-incluir notas ignoradas apenas por .gitignore |
OPENAI_API_KEY | Nenhum | Chave de API; omita para usar embeddings de modelo local ou servidores sem chave (Ollama, LM Studio) |
OPENAI_BASE_URL | https://api.openai.com/v1 | URL base da API |
OPENAI_EMBEDDING_MODEL | text-embedding-3-small | Nome do modelo de embedding |
Padrões de ignorar
- Use
folder/**para ignorar um diretório e todo o seu conteúdo. - Use
*.canvaspara ignorar arquivos por extensão. - Use
exact/path.mdpara ignorar um arquivo específico.
Arquivos .gitignore raiz e aninhados são respeitados por padrão. Defina OBSIDIAN_RESPECT_GITIGNORE=false para desativar esse comportamento. Use OBSIDIAN_INCLUDE_PATTERNS para re-incluir notas Markdown que são ignoradas apenas por .gitignore. Os padrões de inclusão não substituem OBSIDIAN_IGNORE_PATTERNS nem exclusões internas.
O banco de dados armazena a configuração de ignorar e a restaura quando o servidor reinicia, mesmo que a variável de ambiente esteja ausente.
Como funciona
- Indexação divide as notas por títulos com um fallback de janela deslizante, cria embeddings e armazena os resultados em SQLite com FTS5 e
sqlite-vec. - Busca executa BM25, busca difusa de títulos e aliases por trigramas e busca vetorial KNN em paralelo. O BM25 usa pesos de 10× para títulos, 5× para aliases e 1× para conteúdo. Em seguida, o RRF dá aos resultados semânticos e BM25 um peso de 1,5× cada, correspondências exatas de alias 2× e correspondências difusas parciais 0,25×. As pontuações finais variam de 0 a 1, onde pontuações mais altas significam maior relevância.
- Links são resolvidos a partir de wikilinks como
[[note]], mapeados para caminhos de notas e armazenados. Cada resultado de busca inclui arrayslinksebacklinks. - Observador usa
chokidarpara detectar alterações em arquivos e atualizar o índice em segundo plano.
Contribuindo
Issues e pull requests são bem-vindos. Consulte CONTRIBUTING.md para instruções de configuração e verificações do projeto.
Licença
MIT