Obsidian MCP + recuperação híbrida: referência de 2026
# Conecte o Obsidian ao Claude e a outros agentes via MCP: configuração do servidor, recuperação híbrida com BM25 + vetores e indexação de um vault com 16.894 arquivos — com configurações funcionais.
Obsidian não é um aplicativo de anotações. É um corpus markdown em texto simples, com prioridade local e estruturado em grafo, que vira um reservatório de contexto para IA quando você adiciona infraestrutura de recuperação. 16.894 arquivos. 49.746 chunks. Consultas em 23 ms. Zero chamadas API. Um arquivo SQLite de 83 MB. Este guia cobre o sistema completo: da arquitetura do cofre à recuperação híbrida, da integração com MCP aos fluxos de trabalho operacionais.
Principais pontos
Engenharia de contexto, não anotações. O valor de um vault do Obsidian para AI não está nas notas em si, mas na camada de retrieval que permite consultá-las. Um vault com 16.000 arquivos sem retrieval é um banco de dados somente para escrita. Um vault com 200 arquivos, busca hybrid e integração com MCP é uma base de conhecimento de AI. A infraestrutura de retrieval é o produto. As notas são a matéria-prima.
Hybrid retrieval supera busca puramente por palavra-chave ou puramente semântica. BM25 captura identificadores exatos e nomes de funções. A busca vetorial captura sinônimos e correspondências conceituais entre terminologias diferentes. Reciprocal Rank Fusion (RRF) combina as duas sem exigir calibração de pontuação. Nenhum dos métodos sozinho cobre os dois modos de falha. Pesquisas sobre ranking de passagens no MS MARCO confirmam o padrão: hybrid retrieval supera consistentemente qualquer método isolado.3 O mergulho técnico sobre hybrid retriever cobre a matemática do RRF, exemplos trabalhados com números reais, análise de modos de falha e uma calculadora interativa de fusion.
MCP dá às ferramentas de AI acesso direto ao vault. Servidores Model Context Protocol (MCP) expõem o retriever como uma ferramenta que Claude Code, Codex CLI, Cursor e outras ferramentas de AI podem chamar diretamente. O agente consulta o vault, recebe resultados ranqueados com atribuição de fonte e usa o contexto sem carregar arquivos inteiros. O servidor MCP é uma camada fina em volta do motor de retrieval.
Local-first significa custo zero de API e privacidade total. A pilha inteira roda em uma única máquina: SQLite para armazenamento, Model2Vec para embeddings, FTS5 para busca por palavra-chave, sqlite-vec para KNN vetorial. Sem serviços em nuvem, sem chamadas de API, sem dependência de rede. Notas pessoais nunca saem da máquina. O re-embed completo de 49.746 chunks custaria cerca de US$ 0,30 com preços de API da OpenAI, mas os custos reais são latência, exposição de privacidade e a dependência de rede em um sistema que deveria funcionar offline.4
Indexação incremental mantém o sistema atualizado em menos de 10 segundos. A comparação do horário de modificação dos arquivos detecta mudanças. Apenas arquivos modificados são divididos em chunks e reprocessados para embeddings. Um reindex completo leva cerca de quatro minutos em hardware Apple M-series. Atualizações incrementais em edições de um dia típico rodam em menos de dez segundos. O sistema permanece atualizado sem intervenção manual.
A arquitetura escala de 200 para mais de 20.000 notas. O mesmo design em três camadas (entrada, retrieval, integração) funciona em qualquer tamanho de vault. Comece com busca apenas por BM25 em um vault pequeno. Adicione busca vetorial quando colisões de palavra-chave virarem problema. Adicione fusion com RRF quando você precisar de correspondências exatas e semânticas. Cada camada é útil de forma independente e removível de forma independente.
Como usar este guia
Este guia cobre o sistema completo. Seu ponto de partida depende de onde você está:
| Você está… | Comece aqui | Depois explore |
|---|---|---|
| Começando com Obsidian + AI | Por que Obsidian para infraestrutura de AI, Configuração de MCP no Obsidian | Arquitetura do vault, Arquitetura do servidor MCP |
| Tem um vault existente e quer acesso por AI | Arquitetura do servidor MCP, Integração com Claude Code | Modelos de embedding, Busca full-text |
| Está criando um sistema de retrieval | O pipeline completo de retrieval, Reciprocal Rank Fusion | Ajuste de performance, Solução de problemas |
| Contexto de equipe ou empresa | Framework de decisão, Padrões de knowledge graph | Receitas de workflow para desenvolvedores, Guia de migração |
Seções marcadas como Contrato incluem detalhes de implementação, blocos de configuração e modos de falha. Seções marcadas como Narrativa focam conceitos, decisões de arquitetura e o raciocínio por trás das escolhas de design. Seções marcadas como Receita fornecem workflows passo a passo.
Por que Obsidian para infraestrutura de AI
A tese deste guia: vaults do Obsidian são o melhor substrato para bases de conhecimento pessoais de AI porque são local-first, em texto puro, estruturados como grafo e o usuário controla todas as camadas da pilha.
O que o Obsidian oferece à AI que as alternativas não oferecem
Arquivos markdown em texto puro. Cada nota é um arquivo .md no seu sistema de arquivos. Sem formato proprietário, sem exportação de banco de dados, sem API obrigatório para ler o conteúdo. Qualquer ferramenta que lê arquivos pode ler seu vault. grep, ripgrep, pathlib do Python, SQLite FTS5 — todos funcionam diretamente nos arquivos de origem. Quando você cria um sistema de retrieval, está indexando arquivos, não respostas de API. O índice está sempre consistente com a origem porque a origem é o sistema de arquivos.
Arquitetura local-first. O vault fica na sua máquina. Sem servidor, sem dependência de sync na nuvem, sem limites de taxa de API, sem termos de serviço governando como você processa seu próprio conteúdo. Você pode criar embeddings, indexar, dividir em chunks e buscar suas notas sem nenhum serviço externo. Isso importa para infraestrutura de AI porque o pipeline de retrieval roda tão rápido quanto seu disco permite, não tão rápido quanto um endpoint de API responde. Também importa para privacidade: notas pessoais contendo credenciais, dados de saúde, informações financeiras e reflexões privadas nunca saem da sua máquina.
Estrutura de grafo por meio de wiki-links. A sintaxe [[wiki-link]] do Obsidian cria um grafo direcionado entre notas. Uma nota sobre implementação de OAuth aponta para notas sobre rotação de tokens, gerenciamento de sessão e segurança de API. A estrutura de grafo codifica relações entre conceitos curadas por humanos. Embeddings vetoriais capturam similaridade semântica, mas wiki-links capturam conexões intencionais que o autor fez enquanto pensava sobre o tema. O grafo é um sinal que embeddings não conseguem replicar.
Ecossistema de plugins. O Obsidian tem mais de 2.500 plugins da comunidade (em março de 2026, contra mais de 1.800 em meados de 2025). Dataview consulta seu vault como um banco de dados. Templater gera notas a partir de templates com lógica de JavaScript. A integração com Git sincroniza seu vault com um repositório. Linter impõe consistência de formatação. O plugin core Bases (introduzido na v1.9.10) adiciona visualizações semelhantes a banco de dados — tabelas, galerias, calendários e quadros kanban — sobre arquivos do vault usando propriedades de frontmatter como campos, salvas como arquivos .base.15 Esses plugins adicionam estrutura ao vault sem mudar o formato subjacente em texto puro. O sistema de retrieval indexa a saída desses plugins, não os plugins em si.
Mais de 5 milhões de usuários. O Obsidian tem uma comunidade grande e ativa produzindo templates, workflows, plugins e documentação. Quando você encontra um problema de organização do vault ou configuração de plugin, alguém provavelmente já documentou uma solução. A comunidade também produz ferramentas adjacentes ao Obsidian: servidores MCP, scripts de indexação, pipelines de publicação e wrappers de API.
O que um sistema de arquivos sozinho não oferece
Um diretório de arquivos markdown tem a vantagem do texto puro, mas não tem três coisas que o Obsidian adiciona:
-
Links bidirecionais. O Obsidian rastreia backlinks automaticamente. Quando você cria um link da Nota A para a Nota B, a Nota B mostra que a Nota A faz referência a ela. O painel de grafo visualiza clusters de conexões. Essa consciência bidirecional é um metadado que um sistema de arquivos bruto não fornece.
-
Pré-visualização ao vivo com renderização de plugins. Consultas Dataview, diagramas Mermaid e blocos de callout são renderizados em tempo real. A experiência de escrita é mais rica do que em um editor de texto, enquanto o formato de armazenamento permanece em texto puro. Você escreve e organiza em um ambiente rico; o sistema de retrieval indexa o markdown bruto.
-
Infraestrutura da comunidade. Descoberta de plugins, marketplace de temas, serviço de sync (opcional), serviço de publicação (opcional) e um ecossistema de documentação. Você pode replicar qualquer recurso individual com ferramentas avulsas, mas o Obsidian empacota tudo em um workflow coerente.
O que o Obsidian NÃO faz (e o que você constrói)
O Obsidian não inclui infraestrutura de retrieval. Ele tem busca básica (full-text, nome de arquivo, tag), mas não tem pipeline de embedding, busca vetorial, ranking por fusion, servidor MCP, filtragem de credenciais, estratégia de chunking nem hooks de integração para ferramentas externas de AI. Este guia cobre a infraestrutura que você constrói em cima do Obsidian. O vault é o substrato. O pipeline de retrieval, o servidor MCP e os hooks de integração são a infraestrutura.
A arquitetura descrita aqui é markdown-first, não exclusiva do Obsidian. Se você usa Logseq, Foam, Dendron ou um diretório simples de arquivos markdown, o pipeline de retrieval funciona da mesma forma. O chunker lê arquivos .md. O embedder processa strings de texto. O indexer grava no SQLite. Nenhum desses componentes depende de recursos específicos do Obsidian. A contribuição do Obsidian é o ambiente de escrita e organização que produz os arquivos markdown que o retriever indexa.
Configuração do Obsidian MCP
Model Context Protocol (MCP) é a interface padrão que dá a Claude Code, Codex CLI, Cursor e outras ferramentas de AI acesso direto a um cofre do Obsidian. Esta seção conecta um cofre a uma ferramenta de AI em cinco minutos. Você vai instalar o Obsidian, criar um cofre, instalar um servidor MCP e executar sua primeira consulta. O início rápido usa um servidor MCP da comunidade para resultados imediatos. Seções posteriores abordam a criação de um pipeline de recuperação personalizado para uso em produção.
Pré-requisitos
- macOS, Linux ou Windows
- Node.js 18+ (para o servidor MCP)
- Obsidian 1.12+ (para integração com CLI; 1.13.1 é a versão pública atual para desktop; versões anteriores funcionam para configurações apenas com MCP)
- Claude Code, Codex CLI ou Cursor instalado
Etapa 1: crie um cofre
Baixe o Obsidian em obsidian.md e crie um novo cofre. Escolha um local de que você vá se lembrar — o servidor MCP precisa do caminho absoluto.
# Example vault location
~/Documents/knowledge-base/
Adicione algumas notas para dar ao retriever algo com que trabalhar. Até 10-20 notas já são suficientes para ver resultados. Cada nota deve ser um arquivo .md com um título significativo e pelo menos um parágrafo de conteúdo.
Etapa 2: instale um servidor MCP
Vários servidores MCP da comunidade oferecem acesso imediato ao cofre. O ecossistema cresceu bastante ao longo de 2025-2026. Um exemplo relevante é o MCPVault (npm @bitbonsai/mcpvault, repo bitbonsai/mcpvault), agora na versão v0.12.1 — um projeto separado de MarkusPfundstein/mcp-obsidian abaixo, não uma renomeação dele. A v0.11.0 (março de 2026) adicionou list_all_tags para escanear frontmatter e hashtags com contagens, melhorou o tratamento de pastas com ponto e adicionou suporte a .base/.canvas. Dois alertas de severidade média (GHSA-9c83-rr99-vfwj e GHSA-j99q-93c9-h869) foram divulgados contra a deny-list de diretórios restritos do filtro de caminhos, então use uma versão atual.13
Mudança em abril de 2026 — Obsidian CLI como ponte preferida: o Obsidian 1.12.0 introduziu o CLI de primeira classe, e o instalador público 1.12.7 (23 de março de 2026) incluiu o binário standalone + TUI + melhorias no arquivo de socket que facilitaram instalar e executar workflows de terminal.16 A versão pública atual para desktop, 1.13.1 (canal público, 9 de junho de 2026), é uma atualização de versão em relação à 1.13.0 — refinamentos na UX de configurações e um upgrade do CodeMirror — sem novos recursos de AI/automação além da superfície CLI da linha 1.12.x.2526 As ferramentas da comunidade estão migrando ativamente do plugin Local REST API (que alimentava
mcp-obsidian) para a integração baseada em CLI, porque ela é mais rápida e estável. O repoMarkusPfundstein/mcp-obsidianainda é mantido — commits até maio de 2026 adicionaram ferramentas incluindosearch_by_tageget_frontmatter— embora não publique releases com tag (instale a partir de um commit fixado). Ele continua baseado em Local-REST-API; para novas configurações, a ponte CLI geralmente é mais rápida e estável, então prefira ela ou as alternativas mais novas da comunidade listadas abaixo.20 Veja a seção “Obsidian CLI para workflows de AI” mais adiante neste guia para a configuração recomendada.
| Servidor | Autor | Transporte | Requer plugin | Recurso principal |
|---|---|---|---|---|
| obsidian-mcp-server | StevenStavrakis | STDIO | Não | Leve, baseado em arquivos |
| mcp-obsidian | MarkusPfundstein | STDIO | Local REST API | CRUD completo do cofre via REST, além de search_by_tag/get_frontmatter — mantido ativamente (commits até maio de 2026); sem releases com tag, fixe um commit20 |
| obsidian-mcp-tools | jacksteamdev | STDIO | Sim (plugin) | Busca semântica + Templater |
| obsidian-claude-code-mcp | iansinnott | WebSocket | Sim (plugin) | Descoberta automática para Claude Code |
| obsidian-mcp-server | cyanheads | STDIO | Local REST API | Tags, gerenciamento de frontmatter |
| Hybrid Search MCP | comunidade | STDIO | Não | Servidor MCP com BM25 + busca semântica + CLI. Novo e mantido ativamente em abril de 2026. |
Para o início rápido, a opção mais simples é um servidor baseado em arquivos que lê arquivos .md diretamente:
npm install -g obsidian-mcp-server
Etapa 3: configure sua ferramenta de AI
Claude Code — adicione a ~/.claude/settings.json:
{
"mcpServers": {
"obsidian": {
"command": "obsidian-mcp-server",
"args": ["--vault", "/absolute/path/to/your/vault"]
}
}
}
Codex CLI — adicione a .codex/config.toml:
[mcp_servers.obsidian]
command = "obsidian-mcp-server"
args = ["--vault", "/absolute/path/to/your/vault"]
Cursor — adicione a .cursor/mcp.json:
{
"mcpServers": {
"obsidian": {
"command": "obsidian-mcp-server",
"args": ["--vault", "/absolute/path/to/your/vault"]
}
}
}
Etapa 4: execute sua primeira consulta
Abra sua ferramenta de AI e faça uma pergunta que as notas do seu cofre consigam responder:
Search my Obsidian vault for notes about [topic you wrote about]
A ferramenta de AI chama o servidor MCP, que pesquisa seu cofre e retorna conteúdo correspondente. Você deve ver resultados com caminhos de arquivos e trechos relevantes.
O que Claude pode fazer depois de conectado
Os nomes exatos das ferramentas variam conforme o servidor, mas a superfície principal de capacidades é consistente entre as implementações:
| Capacidade | Ferramenta típica | O que o agente faz com ela |
|---|---|---|
| Pesquisar o cofre | obsidian_search / search |
Encontra notas que correspondem a uma consulta e retorna trechos ranqueados com caminhos de arquivos e atribuição de fonte |
| Ler uma nota completa | obsidian_read_note / read_note |
Busca o conteúdo completo da nota quando um trecho de busca não é suficiente |
| Listar e navegar | obsidian_list_notes / list_notes |
Explora notas por pasta, tag ou intervalo de datas quando não há uma consulta específica |
| Obter contexto formatado | obsidian_get_context |
Retorna um bloco de contexto estruturado por tópico, dimensionado para um token budget, pronto para injeção na conversa |
Na prática: Claude responde a perguntas a partir das suas notas com atribuição de fonte, traz decisões anteriores e material de referência para sessões de programação e explora a estrutura do cofre sem carregar arquivos inteiros no contexto. Alguns servidores da comunidade também expõem operações de escrita (criar, anexar, gerenciamento de tags e frontmatter); o servidor personalizado criado mais adiante neste guia é deliberadamente somente leitura, com a criação de notas tratada por hooks.
Aprofundamentos: Arquitetura do servidor MCP para design de ferramentas e permissões, Integração com Claude Code para hooks e o padrão de ponte, Integração com Codex CLI e Cursor e outras ferramentas para outros agentes.
O que você acabou de criar
Você conectou uma base de conhecimento local a uma ferramenta de AI por meio de um protocolo padrão. O servidor MCP lê os arquivos do seu cofre, executa busca básica e retorna resultados. Esta é a versão mínima viável.
O que este início rápido NÃO oferece: - Recuperação híbrida (BM25 + busca vetorial + fusão RRF) - Busca semântica baseada em embeddings - Filtragem de credenciais - Indexação incremental - Injeção automática de contexto baseada em hooks
O restante deste guia aborda como criar cada uma dessas capacidades. O início rápido prova o conceito. O pipeline completo entrega recuperação com qualidade de produção.
Obsidian CLI para AI Workflows
O Obsidian 1.12 (fevereiro de 2026) introduziu uma interface de linha de comando integrada que abre uma nova superfície de integração para AI workflows; ela continua atual até a versão pública desktop 1.13.1 (canal público, 9 de junho de 2026), uma atualização de UX das configurações + versão do CodeMirror, sem novos recursos de CLI.162526 O CLI funciona como um controle remoto para a GUI do Obsidian — o Obsidian precisa estar em execução (ou será iniciado automaticamente no primeiro comando). Ative em Settings > General > Command line interface.
Por que o CLI importa para a infraestrutura de IA
O CLI oferece acesso programático a operações nativas do Obsidian que antes exigiam a GUI ou APIs de plugins. Para AI workflows, os principais recursos são:
- Busca a partir de scripts e hooks.
obsidian search "query"eobsidian search:context "query"executam buscas no cofre a partir de qualquer shell script, hook ou pipeline de automação. A variantesearch:contextretorna linhas correspondentes com o contexto ao redor, útil para alimentar resultados em prompts de IA. - Automação de notas diárias.
obsidian dailyabre ou cria a nota diária de hoje. Combinado com shell scripting, isso permite workflows automatizados de briefing diário — um hook pode anexar resumos gerados por IA à nota diária. - Criação de notas baseada em templates.
obsidian template listeobsidian template creategeram notas a partir do Templater ou de templates nativos, permitindo que AI agents criem entradas estruturadas no cofre sem escrever arquivos markdown diretamente. - Gerenciamento de propriedades.
obsidian property seteobsidian property getleem e escrevem propriedades de frontmatter, permitindo atualizações de metadados a partir de scripts sem fazer parsing de YAML. - Controle de plugins.
obsidian plugin enable/disable/listgerencia plugins programaticamente, útil para alternar plugins de indexação durante operações em lote. - Gerenciamento de tarefas.
obsidian task list/add/completeoferece acesso estruturado a tarefas, útil para AI agents que gerenciam itens de trabalho no cofre.
CLI vs MCP para acesso de IA
O CLI e os servidores MCP cumprem papéis diferentes e são complementares, não concorrentes:
| Aspecto | Obsidian CLI | Servidor MCP |
|---|---|---|
| Chamador | Shell scripts, hooks, cron jobs | AI agents (Claude Code, Codex, Cursor) |
| Protocolo | Processo POSIX (stdin/stdout/stderr) | MCP (JSON-RPC sobre STDIO ou HTTP) |
| Ponto forte | Operações nativas do Obsidian (templates, plugins, propriedades) | Recuperação personalizada (embeddings, BM25, fusão RRF) |
| Limitação | Sem busca vetorial, sem pipeline de embeddings | Sem acesso a operações internas do Obsidian |
| Melhor para | Scripts de automação, pipelines de intake, ações de hooks | Consultas em tempo real de AI agents durante sessões |
Recomendação: Use o CLI para automação de intake (criar notas, gerenciar propriedades, executar busca nativa do Obsidian) e MCP para recuperação (busca hybrid com embeddings). Um hook PreToolUse pode chamar obsidian search:context como uma pré-verificação rápida antes de recorrer ao retriever MCP completo para resultados ranqueados.
Exemplo: hook de intake com CLI
#!/bin/bash
# Hook: append today's signals to daily note via CLI
DATE=$(date +%Y-%m-%d)
SUMMARY="$1"
obsidian daily # ensure daily note exists
obsidian file append "Daily Notes/${DATE}.md" "## AI Summary\n${SUMMARY}"
Plugins de agentes do Obsidian
Uma categoria crescente de plugins do Obsidian incorpora AI coding agents diretamente na UI do cofre, oferecendo uma alternativa à configuração externa de servidor MCP. Esses plugins executam o AI agent dentro da barra lateral do Obsidian, em vez de se conectarem a partir de uma ferramenta externa.
Claudian
Claudian incorpora Claude Code como um colaborador de IA no cofre. O diretório do cofre se torna o diretório de trabalho do Claude, dando a ele capacidades agentic completas: leitura/escrita de arquivos, busca, comandos bash e workflows de várias etapas.17
Principais recursos para infraestrutura de IA:
- Prompts com consciência de contexto. Anexa automaticamente a nota em foco, oferece suporte a menções de arquivo @notename, exclusão baseada em tags e seleção do editor como contexto.
- Suporte a visão. Analise imagens por arrastar e soltar, colar ou caminho de arquivo — útil para processar screenshots e diagramas capturados no cofre.
- Slash commands. Crie templates de prompt reutilizáveis acionados por /command, permitindo operações padronizadas no cofre.
- Modos de permissão. Modos YOLO (aprovação automática), Safe (aprovar cada ação) e Plan (somente plano), com uma blocklist de segurança e confinamento ao cofre.
Agent Client
Agent Client traz Claude Code, Codex CLI e Gemini CLI para uma barra lateral unificada do Obsidian via Agent Client Protocol (ACP).18
Principais recursos:
- Troca entre múltiplos agentes. Converse com Claude Code, Codex ou Gemini CLI a partir do mesmo painel, alternando entre agentes conforme necessário.
- Menções a notas. Use @notename para incluir o conteúdo de notas nos prompts, semelhante ao Claudian, mas independente de agente.
- Execução de shell. Execute comandos de terminal inline no chat — build scripts, comandos git ou qualquer operação de terminal sem sair da conversa.
- Aprovação de ações. Controle granular sobre leituras de arquivos, edições e execuções de comandos.
Quando usar plugins de agentes vs MCP externo
| Cenário | Plugin de agente | MCP externo |
|---|---|---|
| Escrever e editar notas do cofre com assistência de IA | Melhor — o agente vê o contexto do editor | Funciona, mas sem consciência do editor |
| Desenvolvimento de código em vários repos | Limitado — restrito ao cofre | Melhor — escopo de projeto com filesystem completo |
| Recuperação a partir de um corpus grande indexado | Apenas busca básica | Pipeline completo de recuperação hybrid |
| Perguntas e respostas rápidas no cofre durante sessões de anotações | Ideal — sem troca de contexto | Exige alternar para o terminal |
Recomendação: Use plugins de agentes para workflows centrados no cofre (escrever, organizar, resumir notas). Use servidores MCP externos para workflows de desenvolvimento em que o AI agent precisa do pipeline completo de recuperação e acesso a codebases fora do cofre. As duas abordagens podem coexistir — execute o Claudian dentro do Obsidian para trabalho com notas e Claude Code com MCP externamente para desenvolvimento.
Estrutura de decisão: Obsidian vs alternativas
Nem todo caso de uso precisa do Obsidian. Esta seção mapeia quando o Obsidian é o substrato certo, quando é exagero e quando outra opção se encaixa melhor.
Árvore de decisão
START: What is your primary content type?
│
├─ Structured data (tables, records, schemas)
│ → Use a database. SQLite, PostgreSQL, or a spreadsheet.
│ → Obsidian is for prose, not tabular data.
│
├─ Ephemeral context (current project, temporary notes)
│ → Use CLAUDE.md / AGENTS.md in the project repo.
│ → These travel with the code and reset per project.
│
├─ Team wiki (shared documentation, onboarding)
│ → Evaluate Notion, Confluence, or a shared git repo.
│ → Obsidian vaults are personal-first. Team sync is possible
│ but not native.
│
└─ Growing personal knowledge corpus
│
├─ < 50 notes
│ → A folder of markdown files + grep is sufficient.
│ → Obsidian adds value mainly through the link graph,
│ which needs density to be useful.
│
├─ 50 - 500 notes
│ → Obsidian adds value. Wiki-links create a navigable graph.
│ → BM25-only search (FTS5) is sufficient at this scale.
│ → Skip vector search and RRF until keyword collisions appear.
│
├─ 500 - 5,000 notes
│ → Full hybrid retrieval becomes valuable. Keyword collisions
│ increase. Semantic search catches queries that BM25 misses.
│ → Add vector search + RRF fusion at this scale.
│
└─ 5,000+ notes
→ Full pipeline is essential. BM25-only returns too much noise.
→ Credential filtering becomes critical (more notes = more
accidentally pasted secrets).
→ Incremental indexing matters (full reindex takes minutes).
→ MCP integration pays dividends on every AI interaction.
Matriz de comparação
| Critério | Obsidian | Notion | Apple Notes | Sistema de arquivos simples | CLAUDE.md |
|---|---|---|---|---|---|
| Local-first | Sim | Não (cloud) | Parcial (iCloud) | Sim | Sim |
| Texto puro | Sim (markdown) | Não (blocos) | Não (proprietário) | Sim | Sim |
| Estrutura de grafo | Sim (wiki-links) | Parcial (menções) | Não | Não | Não |
| Indexável por AI | Acesso direto a arquivos | API obrigatório | Exportação obrigatória | Acesso direto a arquivos | Já no contexto |
| Ecossistema de plugins | Mais de 2.500 plugins | Integrações | Nenhum | N/A | N/A |
| Funciona offline | Completo | Cache somente leitura | Parcial | Completo | Completo |
| Escala para mais de 10 mil notas | Sim | Sim (com API) | Degrada | Sim | Não (arquivo único) |
| Custo | Grátis (core) | US$ 10/mês ou mais | Grátis | Grátis | Grátis |
Quando Obsidian é exagero
- Contexto de um único projeto. Se a AI só precisa de contexto sobre o codebase atual, coloque isso em
CLAUDE.md,AGENTS.mdou na documentação em nível de projeto. Esses arquivos acompanham o repositório e são carregados automaticamente. - Dados estruturados. Se o conteúdo é composto por tabelas, registros ou schemas, use um banco de dados. As notas do Obsidian são orientadas a prosa. Dataview consegue consultar campos de frontmatter, mas um banco de dados real lida melhor com consultas estruturadas.
- Pesquisa temporária. Se as notas serão descartadas depois que o projeto acabar, uma pasta de rascunho com arquivos markdown é mais simples. Não crie infraestrutura de retrieval para conteúdo efêmero.
Quando Obsidian é a escolha certa
- Conhecimento acumulado ao longo de meses ou anos. O valor se acumula conforme o corpus cresce. Um vault com 200 notas consultado diariamente por seis meses entrega mais valor do que um vault com 5.000 notas consultado uma única vez.
- Vários domínios em um único corpus. Um vault com notas sobre programação, arquitetura, segurança, design e projetos pessoais se beneficia de retrieval entre domínios que um
CLAUDE.mdespecífico de projeto não consegue oferecer. - Conteúdo sensível à privacidade. Local-first significa que o pipeline de retrieval nunca envia conteúdo para serviços externos. O vault contém tudo o que você coloca nele, inclusive conteúdo que você não enviaria para um serviço de cloud.
Modelo mental: três camadas
O sistema tem três camadas que operam de forma independente, mas se potencializam quando combinadas. Cada camada tem uma preocupação diferente e um modo de falha diferente.
┌─────────────────────────────────────────────────────┐
│ INTEGRATION LAYER │
│ MCP servers, hooks, skills, context injection │
│ Concern: delivering context to AI tools │
│ Failure: wrong context, too much context, stale │
└──────────────────────┬──────────────────────────────┘
│ query + ranked results
┌──────────────────────┴──────────────────────────────┐
│ RETRIEVAL LAYER │
│ BM25, vector KNN, RRF fusion, token budget │
│ Concern: finding the right content for any query │
│ Failure: wrong ranking, missed results, slow queries │
└──────────────────────┬──────────────────────────────┘
│ chunked, embedded, indexed
┌──────────────────────┴──────────────────────────────┐
│ INTAKE LAYER │
│ Note creation, signal triage, vault organization │
│ Concern: what enters the vault and how it's stored │
│ Failure: noise, duplicates, missing structure │
└─────────────────────────────────────────────────────┘
Intake determina o que entra no vault. Sem curadoria, o vault acumula ruído: screenshots de tweets, artigos copiados e colados sem anotação, ideias pela metade sem contexto. A camada de intake é responsável pelo controle de qualidade no ponto de entrada. Um pipeline de pontuação, uma convenção de tags ou um processo de revisão manual — qualquer mecanismo que garanta que o vault contenha conteúdo que vale recuperar.
Retrieval torna o vault consultável. Este é o motor: dividir notas em unidades de busca com chunking, transformar chunks em embeddings no espaço vetorial, indexar para busca por palavras-chave e busca semântica, combinar resultados com RRF. A camada de retrieval transforma uma pasta de arquivos em uma knowledge base consultável. Sem essa camada, o vault pode ser navegado por exploração manual e busca básica, mas não fica programaticamente acessível para ferramentas de AI.
Integração conecta a camada de retrieval às ferramentas de AI. Um servidor MCP expõe retrieval como uma ferramenta chamável. Hooks injetam contexto automaticamente. Skills capturam novo conhecimento de volta no vault. A camada de integração é a interface entre a knowledge base e os agentes de AI que a consomem.
As camadas são desacopladas por design. O pipeline de pontuação de intake não sabe nada sobre embeddings. O retriever não sabe nada sobre regras de roteamento de sinais. O servidor MCP não sabe nada sobre como as notas foram criadas. Esse desacoplamento permite que você melhore qualquer camada de forma independente. Substitua o modelo de embeddings sem alterar o pipeline de intake. Adicione uma nova capacidade MCP sem modificar o retriever. Altere as heurísticas de pontuação de sinais sem tocar no índice.
Arquitetura do vault para consumo por AI
Um vault otimizado para recuperação por AI segue convenções diferentes de um vault otimizado para navegação pessoal. Esta seção aborda a estrutura de pastas, o schema das notas, as convenções de frontmatter e os padrões específicos que melhoram a qualidade da recuperação.
Estrutura de pastas
Use prefixos numéricos para pastas de nível superior para criar uma hierarquia organizacional previsível. Os números não indicam prioridade — eles agrupam domínios relacionados e tornam a estrutura fácil de escanear.
vault/
├── 00-inbox/ # Unsorted captures, pending triage
├── 01-projects/ # Active project notes
├── 02-areas/ # Ongoing areas of responsibility
├── 03-resources/ # Reference material by topic
│ ├── programming/
│ ├── security/
│ ├── ai-engineering/
│ ├── design/
│ └── devops/
├── 04-archive/ # Completed projects, old references
├── 05-signals/ # Scored signal intake
│ ├── ai-tooling/
│ ├── security/
│ ├── systems/
│ └── ...12 domain folders
├── 06-daily/ # Daily notes (if used)
├── 07-templates/ # Note templates (excluded from index)
├── 08-attachments/ # Images, PDFs (excluded from index)
├── .obsidian/ # Obsidian config (excluded from index)
└── .indexignore # Paths to exclude from retrieval index
Pastas que devem ser indexadas: Tudo que contém prosa em markdown — projetos, áreas, recursos, sinais, notas diárias.
Pastas que devem ser excluídas da indexação: Templates (eles contêm variáveis de placeholder, não conteúdo), anexos (arquivos binários), configuração do Obsidian e qualquer pasta com conteúdo sensível que você não quer no índice de recuperação.
O arquivo .indexignore
Crie um arquivo .indexignore na raiz do vault para excluir caminhos explicitamente do índice de recuperação. A sintaxe corresponde à do .gitignore:
# Obsidian internal
.obsidian/
# Templates contain placeholders, not content
07-templates/
# Binary attachments
08-attachments/
# Personal health/medical notes
02-areas/health/
# Financial records
02-areas/finance/personal/
# Career documents (resumes, salary data)
02-areas/career/private/
O indexador lê esse arquivo antes de escanear e ignora completamente os caminhos correspondentes. Arquivos em caminhos excluídos nunca passam por chunking, nunca recebem embeddings e nunca aparecem nos resultados de busca.
Schema das notas
Toda nota deve ter frontmatter YAML. O recuperador usa campos de frontmatter para filtragem e enriquecimento de contexto:
---
title: "OAuth Token Rotation Patterns"
type: note # note | signal | project | moc | daily
domain: security # primary domain for routing
tags:
- authentication
- oauth
- token-management
created: 2026-01-15
updated: 2026-02-28
source: "" # URL if captured from external source
status: active # active | archived | draft
---
Campos obrigatórios para recuperação:
title— Usado na exibição dos resultados de busca e no contexto de heading para BM25type— Permite consultas filtradas por tipo (“mostre apenas MOCs” ou “apenas sinais”)tags— Indexado no contexto de heading do FTS5 com peso 0,3, fornecendo correspondências de palavra-chave mesmo quando o corpo usa terminologia diferente
Campos opcionais, mas valiosos:
domain— Permite consultas com escopo por domínio (“busque apenas notas de segurança”)source— Atribuição para conteúdo capturado; o recuperador pode incluir URLs de origem nos resultadosstatus— Permite excluir notas arquivadas ou em rascunho da busca ativa
Convenções de chunking
O recuperador divide o conteúdo em chunks nos limites de headings H2 (##). Isso significa que a estrutura das suas notas afeta diretamente a granularidade da recuperação:
Bom para recuperação:
## Token Rotation Strategy
The rotation interval depends on the threat model...
## Implementation with refresh_token
The OAuth 2.0 refresh token flow requires...
## Error Handling: Expired Tokens
When a token expires mid-request...
Três seções H2 produzem três chunks pesquisáveis de forma independente. Cada chunk tem contexto suficiente para que o embedding capture seu significado. Uma consulta sobre “expired token handling” corresponde especificamente ao terceiro chunk.
Ruim para recuperação:
# OAuth Notes
Token rotation depends on threat model. The OAuth 2.0 refresh
token flow requires storing the refresh token securely. When a
token expires mid-request, the client should retry after refresh.
The rotation interval is typically 15-30 minutes for access tokens
and 7-30 days for refresh tokens...
Uma seção longa sem headings H2 produz um único chunk grande. O embedding faz uma média entre todos os tópicos da seção. Uma consulta sobre qualquer subtópico corresponde igualmente à nota inteira.
Regra prática: Se uma seção cobre mais de um conceito, divida-a em subseções H2. O chunker cuida do resto.
O que não colocar nas notas
Conteúdo que degrada a qualidade da recuperação:
- Copiar e colar artigos inteiros sem anotação. O recuperador indexa as palavras-chave do artigo original, diluindo seu vault com conteúdo que você não escreveu. Em vez disso, adicione um resumo, extraia os pontos principais ou crie um link para a URL de origem.
- Screenshots sem descrição em texto. O recuperador indexa texto em markdown. Uma imagem sem alt text ou descrição ao redor fica invisível tanto para BM25 quanto para busca vetorial.
- Strings de credenciais. Chaves API, tokens, senhas, strings de conexão. Mesmo com filtragem de credenciais, a abordagem mais segura é nunca colar secrets nas notas. Em vez disso, referencie-os pelo nome (“o token Cloudflare API em
~/.env”). - Conteúdo gerado automaticamente sem curadoria. Se uma ferramenta gera uma nota (transcrição de reunião, destaques do Readwise, importação de RSS), revise e anote antes que ela entre no vault permanente. Importações automáticas sem curadoria adicionam volume sem acrescentar valor recuperável.
Ecossistema de plugins para workflows de AI
Plugins do Obsidian que melhoram a qualidade do vault para recuperação por AI se dividem em três categorias: estruturais (impõem consistência), consulta (expõem metadados) e sync (mantêm o vault atualizado).
Plugins essenciais
Dataview. Consulta seu vault como um banco de dados usando campos de frontmatter. Crie índices dinâmicos: “todas as notas marcadas com security atualizadas nos últimos 30 dias” ou “todas as notas de projeto com status active.” O Dataview não ajuda diretamente na recuperação, mas ajuda você a identificar lacunas na cobertura do seu vault e encontrar notas que precisam ser atualizadas.
TABLE type, domain, updated
FROM "03-resources"
WHERE status = "active"
SORT updated DESC
LIMIT 20
Templater. Cria notas a partir de templates com campos dinâmicos. Garanta que toda nova nota comece com o frontmatter correto usando um template que preenche previamente os campos created, type e domain. Um frontmatter consistente melhora a filtragem de recuperação.
<%* /* New Resource Note Template */ %>
---
title: "<% tp.file.cursor() %>"
type: note
domain: <% tp.system.suggester(["programming", "security", "ai-engineering", "design", "devops"], ["programming", "security", "ai-engineering", "design", "devops"]) %>
tags: []
created: <% tp.date.now("YYYY-MM-DD") %>
updated: <% tp.date.now("YYYY-MM-DD") %>
source: ""
status: active
---
## Key Points
## Details
## References
Linter. Impõe regras de formatação em todo o vault. Uma hierarquia de títulos consistente (H1 para título, H2 para seções, H3 para subseções) garante que o chunker produza resultados previsíveis. Regras do Linter que importam para recuperação:
- Incremento de títulos: impor níveis de título sequenciais (sem pular de H1 para H3)
- Título YAML: corresponder ao nome do arquivo
- Espaços finais: remover (evita artefatos de tokenização do FTS5)
- Linhas em branco consecutivas: limitar a 1 (chunks mais limpos)
Git integration. Controle de versão para o seu vault. Acompanhe alterações ao longo do tempo, sincronize entre máquinas e recupere exclusões acidentais. O Git também fornece dados de mtime que o indexador usa para detecção incremental de alterações.
Plugins que ajudam a indexação
Smart Connections. Um plugin do Obsidian que oferece busca semântica com AI dentro do próprio Obsidian. O Smart Connections v4 cria embeddings locais por padrão — depois que seu vault é indexado, conexões semânticas e consultas funcionam totalmente offline, sem chamadas API.11 v4.5.0 (5 de maio de 2026) torna as conexões de rodapé parte do Smart Connections Core, então toda instalação pode mostrar conexões de notas relacionadas no rodapé sem abrir um painel lateral. Versões recentes da v4 também adicionaram visualizações em grafo para listas de conexões, locais de dock configuráveis, melhor recuperação de block-embedding após execuções de indexação interrompidas e “Substrate”, um ambiente entre plugins que permite que Smart Connections, Smart Chat e Smart Composer compartilhem estado.21 Embora o sistema de recuperação deste guia seja externo ao Obsidian (executado como um pipeline Python), o Smart Connections é útil para explorar relações semânticas enquanto você escreve. Os dois sistemas indexam o mesmo conteúdo, mas atendem a casos de uso diferentes: Smart Connections para descoberta dentro do editor, o recuperador externo para integração com ferramentas de AI via MCP.
Plugins AI-native lançados em abril de 2026. Uma onda de novos plugins da comunidade mira diretamente o workflow Claude Code / Codex / Gemini-CLI:
| Plugin | Lançado | O que faz |
|---|---|---|
| Cortex | 4 de abril | Agente de vault impulsionado por Claude Code — trata o vault como um workspace de agente, não apenas como um repositório de notas |
| VaultSearch | 7 de abril | Busca hybrid local-first: BM25 + semântica + fuzzy (sobreposição direta com a stack de recuperação deste guia) |
| LLM Wiki | 9 de abril | Transforme seu vault em uma base de conhecimento consultável de forma privada |
| Drift | 11 de abril | Visualizador de diffs no estilo VS Code para edição do Obsidian com AI; posicionado para workflows Claude Code |
| EngramQuest | 11 de abril | Gera desafios de memória a partir de notas; inclui “AI Skills” para Claude Code / Gemini CLI / Cursor |
| Hybrid Search MCP | Março (ainda novo) | Servidor MCP + CLI com BM25 + busca semântica — criado especificamente para assistentes de AI |
Trate isso como uma área emergente — vários desses plugins provavelmente serão consolidados ou absorvidos pelo Smart Connections / núcleo do Obsidian nos próximos trimestres. Se você está escolhendo um hoje, VaultSearch e Hybrid Search MCP são os mais próximos, em filosofia, do recuperador externo deste guia.
Nota sobre Dataview: O Dataview (o plugin de consulta antigo do Obsidian) lançou a versão 0.5.70 pela última vez em abril de 2025 e está efetivamente parado desde então. Para novos trabalhos, o recurso integrado Bases do Obsidian (1.9+) é o sucessor implícito e o caminho recomendado.
Metadata Menu. Oferece edição estruturada de frontmatter com autocomplete para valores de campos. Reduz erros de digitação nos campos type, domain e tags. Metadados consistentes melhoram a precisão da filtragem de recuperação.
Plugins que prejudicam a indexação
Excalidraw. Armazena desenhos como JSON incorporado em arquivos markdown. O JSON é markdown sintaticamente válido, mas produz lixo quando dividido em chunks e incorporado. Exclua arquivos do Excalidraw do índice via .indexignore ou filtre por extensão de arquivo.
Kanban. Armazena o estado do quadro como markdown com formatação especial. O formato foi projetado para renderização de Kanban, não para recuperação de prosa. O chunker produz fragmentos de títulos de cartões e metadados que não geram bons embeddings. Exclua quadros Kanban do índice.
Calendar. Cria notas diárias com conteúdo mínimo (geralmente apenas um cabeçalho de data). Notas vazias ou quase vazias produzem chunks de baixa qualidade. Se você usa notas diárias, escreva conteúdo substancial nelas ou exclua a pasta de notas diárias do índice.
Configuração de plugins que importa
File recovery → Enabled. Protege contra exclusão acidental de notas. Não está diretamente relacionado à recuperação, mas é essencial para uma base de conhecimento da qual você depende.
Strict line breaks → Disabled. Quebras de linha padrão do Markdown (linha em branco dupla para parágrafo) produzem chunks mais limpos do que o modo strict do Obsidian (linha nova única para <br>).
Default new file location → Designated folder. Direcione novos arquivos para 00-inbox/ para que notas sem categoria não poluam pastas de domínio. A inbox é uma área de preparação; os arquivos passam para pastas de domínio após triagem.
Wiki-link format → Shortest path when possible. Alvos de link mais curtos são mais fáceis para o recuperador resolver ao indexar a estrutura de links.
Modelos de embeddings: escolha e configuração
O modelo de embeddings converte chunks de texto em vetores numéricos para busca semântica. A escolha do modelo determina a qualidade da recuperação, o tamanho do índice, a velocidade de geração dos embeddings e as dependências em runtime. Esta seção explica por que o potion-base-8M da Model2Vec é a escolha padrão e quando escolher alternativas.
Por que Model2Vec potion-base-8M
Modelo: minishlab/potion-base-8M
Parâmetros: 7,6 milhões
Dimensões: 256
Tamanho: ~30 MB
Dependências: model2vec (somente numpy, sem PyTorch)
Inferência: somente CPU, embeddings estáticos de palavras (sem camadas de atenção)
Model2Vec destila o conhecimento de um sentence transformer em embeddings estáticos de tokens. Em vez de executar camadas de atenção sobre a entrada (como BERT, MiniLM e outros modelos transformer fazem), Model2Vec produz vetores por meio de uma média ponderada de embeddings de tokens pré-computados.5 A consequência prática: a velocidade de geração dos embeddings é 50-500x maior que a de modelos baseados em transformers, porque não há computação sequencial.
Na página atual de resultados da Model2Vec, potion-base-8M atinge cerca de 92% da pontuação all-task do all-MiniLM-L6-v2 (51,32 vs 55,80), mantendo-se ordens de grandeza mais rápido.6 A diferença restante de qualidade é o trade-off pelas vantagens de velocidade e simplicidade. Para chunks curtos de markdown (em média 200-400 palavras em um vault típico), a diferença de qualidade é menos perceptível do que em documentos mais longos, porque os dois modelos convergem para representações semelhantes em textos curtos e focados.
Configuração
# embedder.py
DEFAULT_MODEL = "minishlab/potion-base-8M"
EMBEDDING_DIM = 256
class Model2VecEmbedder:
def __init__(self, model_name=DEFAULT_MODEL):
self._model_name = model_name
self._model = None
def _ensure_model(self):
if self._model is not None:
return
_activate_venv() # Add isolated venv to sys.path
from model2vec import StaticModel
self._model = StaticModel.from_pretrained(self._model_name)
def embed_batch(self, texts):
self._ensure_model()
vecs = self._model.encode(texts)
return [v.tolist() for v in vecs]
Carregamento lazy. O modelo é carregado no primeiro uso, não no momento da importação. Importar o módulo do embedder não tem custo quando o retriever opera no modo de fallback somente BM25 (por exemplo, quando a venv de embeddings não está instalada).
Ambiente virtual isolado. O modelo roda em uma venv dedicada (por exemplo, ~/.claude/venvs/memory/) para evitar conflitos de dependências com o restante da toolchain. A função _activate_venv() adiciona o site-packages da venv ao sys.path em runtime.
# Create isolated venv
python3 -m venv ~/.claude/venvs/memory
~/.claude/venvs/memory/bin/pip install model2vec
Processamento em lotes. O embedder processa textos em lotes de 64 para amortizar o overhead da Model2Vec. O indexador envia chunks para embed_batch() em vez de gerar o embedding de um chunk por vez.
Quando escolher alternativas
| Modelo | Dim | Tamanho | Velocidade | Qualidade (MTEB) | Melhor para |
|---|---|---|---|---|---|
| potion-base-8M | 256 | 30 MB | 500x | 51,32 | Padrão: local, rápido, sem GPU |
| potion-base-32M | 256 | 120 MB | 400x | 52,83 | Mais qualidade, ainda estático |
| potion-retrieval-32M | 256 | 120 MB | 400x | 35,06 (retrieval) | Estático otimizado para recuperação |
| potion-multilingual-128M | 256 | ~500 MB | 300x | — | Vaults multilíngues (101 idiomas) |
| all-MiniLM-L6-v2 | 384 | 80 MB | 1x | 55,80 | Mais qualidade, ainda local |
| nomic-embed-text-v1.5 | 768 | 270 MB | 0,5x | 62,28 | Melhor qualidade local |
| text-embedding-3-small | 1536 | API | N/A | 62,30 | Baseado em API, maior qualidade |
Escolha potion-base-32M quando você quiser melhor qualidade do que potion-base-8M sem sair da família de embeddings estáticos. Ele usa um vocabulário maior destilado de baai/bge-base-en-v1.5, alcançando uma pontuação all-task de 52,83 (cerca de 3% acima do potion-base-8M), mantendo a mesma saída de 256 dimensões e dependência somente de numpy.8 O arquivo do modelo 4x maior aumenta o uso de memória, mas a velocidade de geração de embeddings continua ordens de grandeza mais rápida que a de modelos transformer.
Escolha potion-retrieval-32M quando seu caso de uso principal for recuperação (que é o caso da busca no vault). Esta variante é ajustada a partir do potion-base-32M especificamente para tarefas de retrieval, com pontuação de 35,06 na tabela de benchmark de retrieval da Model2Vec contra 32,67 do potion-base-32M.8 O trade-off é que ele é otimizado para recuperação, não para qualidade de embeddings de uso geral.
Escolha potion-multilingual-128M quando seu vault contiver notas em vários idiomas. Lançado em maio de 2025, este modelo de 101 idiomas é o modelo de embeddings estáticos com melhor desempenho para tarefas multilíngues, gerando embeddings para qualquer texto em qualquer idioma e mantendo a mesma dependência somente de numpy dos outros modelos potion.12 O arquivo maior do modelo (~500 MB) é o trade-off pela capacidade multilíngue. Use isso quando você tiver notas em japonês, chinês, alemão ou outros idiomas além do inglês junto com conteúdo em inglês.
Escolha all-MiniLM-L6-v2 quando a qualidade da recuperação for mais importante que a velocidade e você tiver PyTorch instalado. Os vetores de 384 dimensões aumentam o tamanho do banco de dados SQLite em ~50% em comparação com vetores de 256 dimensões. A velocidade de geração dos embeddings cai de <1 minuto para ~10 minutos em uma reindexação completa de 15.000 arquivos em hardware M-series.
Escolha nomic-embed-text-v1.5 quando você precisar da melhor qualidade possível de recuperação local e aceitar uma indexação mais lenta. Os vetores de 768 dimensões aproximadamente triplicam o tamanho do banco de dados. Requer PyTorch e uma CPU moderna ou GPU.
Escolha text-embedding-3-small quando latência de rede e privacidade forem trade-offs aceitáveis. O API produz os embeddings de maior qualidade, mas introduz uma dependência de cloud, custo por token (US$ 0,02/milhão de tokens) e envia seu conteúdo para os servidores da OpenAI.
Fique com potion-base-8M em todos os outros casos. A vantagem de velocidade é crítica para indexação iterativa (reindexar durante o desenvolvimento), a dependência somente de numpy evita a complexidade de instalação do PyTorch, e os vetores de 256 dimensões mantêm o banco de dados compacto.
Quantização e redução de dimensionalidade
Model2Vec v0.5.0+ oferece suporte ao carregamento de modelos com precisão e dimensões reduzidas.8 Isso é útil para deploy em hardware limitado ou para reduzir o tamanho do banco de dados sem trocar de modelo:
from model2vec import StaticModel
# Load with int8 quantization (25% of original size)
model = StaticModel.from_pretrained("minishlab/potion-base-8M", quantize=True)
# Load with reduced dimensions (e.g., 128 instead of 256)
model = StaticModel.from_pretrained("minishlab/potion-base-8M", dimensionality=128)
Modelos quantizados mantêm qualidade de recuperação quase idêntica com uma fração do uso de memória. A redução de dimensionalidade segue uma truncagem no estilo Matryoshka — as primeiras N dimensões carregam a maior parte das informações. Reduzir de 256 para 128 dimensões corta pela metade o armazenamento dos vetores, com perda mínima de qualidade para recuperação de textos curtos.
Model2Vec v0.8.x atualiza os internos de tokenizer/persistência, descontinua o suporte a Python 3.9 e atualiza os resultados publicados para as tabelas MTEB mais recentes. Fixe a versão ou teste model2vec antes de atualizar um indexador de produção, porque upgrades da biblioteca podem alterar caminhos de carregamento de modelos mesmo quando o nome do modelo de embeddings permanece igual.10
Fine-tuning para embeddings específicos do vault
Model2Vec v0.4.0+ oferece suporte ao treinamento de modelos de classificação personalizados sobre embeddings estáticos, v0.7.0 adiciona quantização de vocabulário e pooling configurável para destilação, e v0.8.x refatora o comportamento de tokenizer e persistência.10 Isso é relevante para vaults com vocabulário especializado (notas médicas, referências jurídicas, jargão específico de domínio), em que os modelos potion padrão podem não capturar nuances semânticas:
from model2vec import StaticModel
from model2vec.train import train_model
# Fine-tune on vault-specific data
model = StaticModel.from_pretrained("minishlab/potion-base-8M")
trained_model = train_model(model, train_texts, train_labels)
trained_model.save_pretrained("./vault-embeddings")
Para a maioria dos vaults, o potion-base-8M padrão produz qualidade de recuperação suficiente. Fine-tuning só vale a pena quando a recuperação deixa de encontrar de forma consistente conexões específicas do domínio que um modelo de uso geral não consegue capturar.
Rastreamento de hash do modelo
O indexador armazena um hash derivado do nome do modelo e do tamanho do vocabulário. Se você alterar o modelo de embeddings, o indexador detecta a incompatibilidade na próxima execução incremental e dispara automaticamente uma reindexação completa.
def _compute_model_hash(self):
"""Hash model name + vocab size for compatibility tracking."""
key = f"{self._model_name}:{self._model.vocab_size}"
return hashlib.sha256(key.encode()).hexdigest()[:16]
Isso evita misturar vetores de modelos diferentes no mesmo banco de dados, o que produziria pontuações sem sentido de cosine similarity.
Modos de falha
Falha no download do modelo. A primeira execução baixa o modelo do Hugging Face. Se o download falhar (problema de rede, firewall corporativo), o retriever usa fallback para o modo somente BM25. O modelo fica em cache local depois do primeiro download.
Incompatibilidade de dimensões. Se você trocar de modelo sem limpar o banco de dados, os vetores armazenados terão uma dimensão diferente dos novos embeddings. O indexador detecta isso por meio do hash do modelo e dispara uma reindexação completa. Se a verificação de hash falhar (modelo personalizado sem hash adequado), sqlite-vec gerará erro em consultas KNN com dimensões incompatíveis.
Pressão de memória em vaults grandes. Gerar embeddings para mais de 50.000 chunks em um único lote pode consumir muita memória. O indexador processa em lotes de 64 para limitar o pico de uso de memória. Se a memória ainda for um problema, reduza o tamanho do lote.
Pesquisa de texto completo com FTS5
A extensão FTS5 do SQLite oferece pesquisa de texto completo com ranqueamento BM25. FTS5 é o componente de pesquisa por palavra-chave do pipeline de recuperação hybrid. Esta seção aborda a configuração do FTS5, quando o BM25 se destaca e seus modos de falha específicos.
Tabela virtual FTS5
CREATE VIRTUAL TABLE chunks_fts USING fts5(
chunk_text,
section,
heading_context,
content=chunks,
content_rowid=id
);
Modo de sincronização de conteúdo. O parâmetro content=chunks informa ao FTS5 para referenciar a tabela chunks diretamente, em vez de armazenar uma cópia duplicada do texto. Isso reduz pela metade o requisito de armazenamento, mas significa que o FTS5 precisa ser sincronizado manualmente quando chunks são inseridos, atualizados ou excluídos.
Colunas. Três colunas são indexadas:
- chunk_text — O conteúdo principal de cada chunk (peso BM25: 1,0)
- section — O texto do cabeçalho H2 (peso BM25: 0,5)
- heading_context — Título da nota, tags e metadados (peso BM25: 0,3)
Ranqueamento BM25
O BM25 ranqueia documentos por frequência de termos, frequência inversa de documentos e normalização do tamanho do documento. A função auxiliar bm25() no FTS5 aceita pesos por coluna:
SELECT
c.id, c.file_path, c.section, c.chunk_text,
bm25(chunks_fts, 1.0, 0.5, 0.3) AS score
FROM chunks_fts
JOIN chunks c ON chunks_fts.rowid = c.id
WHERE chunks_fts MATCH ?
ORDER BY score
LIMIT 30;
Os pesos das colunas (1,0, 0,5, 0,3) significam:
- Uma correspondência de palavra-chave em chunk_text contribui mais para a pontuação
- Uma correspondência em section (cabeçalho) contribui metade disso
- Uma correspondência em heading_context (título, tags) contribui 30% disso
Esses pesos são ajustáveis. Se o seu vault tiver cabeçalhos descritivos que preveem fortemente a qualidade do conteúdo, aumente o peso de section. Se suas tags forem abrangentes e precisas, aumente o peso de heading_context.
Quando o BM25 vence
O BM25 se destaca em consultas que contêm identificadores exatos:
- Nomes de funções:
_rrf_fuse,embed_batch,get_stale_files - flags de CLI:
--incremental,--vault,--model - Chaves de configuração:
bm25_weight,max_tokens,batch_size - Mensagens de erro:
SQLITE_LOCKED,ConnectionRefusedError - Termos técnicos específicos:
PostToolUse,PreToolUse,AGENTS.md
Para essas consultas, o BM25 encontra a correspondência exata imediatamente. A pesquisa vetorial retornaria conteúdo semanticamente relacionado, mas poderia ranquear a correspondência exata abaixo de uma discussão conceitual.
Quando o BM25 falha
O BM25 falha em consultas que usam terminologia diferente do conteúdo armazenado:
- Consulta: “como lidar com falhas de autenticação” → O vault contém notas sobre “recuperação de erro de login” e “tratamento de expiração de sessão”. O BM25 não encontra correspondência porque as palavras-chave são diferentes.
- Consulta: “qual é a melhor forma de gerenciar estado” → O vault contém notas sobre “padrões de Redux store” e “context providers”. O BM25 não encontra porque “gerenciamento de estado” é expresso por nomes de tecnologias específicas.
O BM25 também falha com colisão de palavras-chave em escala. Em um vault com 15.000 arquivos, uma pesquisa por “configuração” corresponde a centenas de notas porque quase toda nota de projeto menciona configuração. Os resultados estão tecnicamente corretos, mas são praticamente inúteis — o ranqueamento não consegue determinar qual nota de “configuração” é relevante para a consulta atual.
Tokenizer do FTS5
O FTS5 usa o tokenizer unicode61 por padrão, que lida com texto ASCII e Unicode. Para vaults com conteúdo CJK (chinês, japonês, coreano) significativo, considere o tokenizer trigram:
-- For CJK-heavy vaults
CREATE VIRTUAL TABLE chunks_fts USING fts5(
chunk_text, section, heading_context,
content=chunks, content_rowid=id,
tokenize='trigram'
);
O tokenizer padrão unicode61 divide o texto nos limites das palavras, o que funciona mal para idiomas sem espaços entre palavras. O tokenizer trigram divide a cada três caracteres, permitindo correspondência por substring ao custo do tamanho do índice (aproximadamente 3x maior).
Manutenção
O FTS5 exige sincronização explícita quando a tabela chunks subjacente muda:
# After inserting chunks
cursor.execute("""
INSERT INTO chunks_fts(chunks_fts)
VALUES('rebuild')
""")
O comando rebuild reconstrói o índice FTS5 a partir da tabela de conteúdo. Execute-o após inserções em massa (reindexação completa), mas não após atualizações incrementais individuais — para essas, use INSERT INTO chunks_fts(rowid, chunk_text, section, heading_context) para sincronizar linhas individuais.
Pesquisa vetorial com sqlite-vec
A extensão sqlite-vec traz a busca vetorial KNN (K-Nearest Neighbors) para o SQLite. Esta seção cobre a configuração do sqlite-vec, o pipeline de embedding da nota até o vetor pesquisável e os padrões específicos de consulta.
Tabela virtual sqlite-vec
CREATE VIRTUAL TABLE chunk_vecs USING vec0(
id INTEGER PRIMARY KEY,
embedding float[256]
);
O módulo vec0 armazena vetores float de 256 dimensões como dados binários compactados. A coluna id mapeia 1:1 para a tabela chunks, permitindo joins entre resultados vetoriais e metadados de chunks.
Pipeline de embedding
O pipeline vai da nota até o vetor pesquisável:
Note (.md file)
→ Chunker: split at H2 boundaries
→ Chunks (30-2000 chars each)
→ Credential filter: scrub secrets
→ Embedder: Model2Vec encode
→ Vectors (256-dim float arrays)
→ sqlite-vec: store as packed binary
→ Ready for KNN queries
Serialização vetorial
O módulo struct do Python serializa vetores float para armazenamento no sqlite-vec:
import struct
def _serialize_vector(vec):
"""Pack float list into binary for sqlite-vec."""
return struct.pack(f"{len(vec)}f", *vec)
def _deserialize_vector(blob, dim=256):
"""Unpack binary blob to float list."""
return list(struct.unpack(f"{dim}f", blob))
Consulta KNN
Uma consulta de busca vetorial gera um embedding da consulta de entrada e depois encontra os K chunks mais próximos por distância de cosseno:
def _vector_search(self, query_text, limit=30):
query_vec = self.embedder.embed_batch([query_text])[0]
packed = _serialize_vector(query_vec)
results = self.db.execute("""
SELECT
cv.id,
cv.distance,
c.file_path,
c.section,
c.chunk_text
FROM chunk_vecs cv
JOIN chunks c ON cv.id = c.id
WHERE embedding MATCH ?
AND k = ?
ORDER BY distance
""", [packed, limit]).fetchall()
return results
O operador MATCH no sqlite-vec executa busca aproximada de vizinhos mais próximos. O parâmetro k controla quantos resultados retornar. A coluna distance contém a distância de cosseno (0 = idêntico, 2 = oposto).
Paginação KNN com restrições de distância
A partir do sqlite-vec v0.1.7, consultas KNN têm suporte a restrições WHERE distance < ?, permitindo paginação baseada em cursor em grandes conjuntos de resultados sem reescanear páginas anteriores.14 As versões estáveis posteriores v0.1.8 e v0.1.9 são releases de empacotamento e correções de bugs de DELETE, não releases com novo modelo de consulta, então a v0.1.7 continua sendo o limite de recurso para esse padrão de paginação.23
No horizonte, a linha v0.1.10-alpha (31 de março a 18 de maio de 2026) é a primeira a levar o sqlite-vec além do KNN de força bruta: ela introduz tipos de índice de vizinho mais próximo aproximado — rescore, um índice experimental ivf (inverted-file) que não vem habilitado por padrão, e um índice DiskANN baseado em disco para cofres grandes demais para manter vetores residentes em memória.23 Isso mudaria a história de escalabilidade para cofres muito grandes, mas a linha 0.1.10 ainda está em pré-release (alpha) — trate a indexação ANN como experimental e continue construindo sobre o caminho KNN de força bruta estável da v0.1.9 para cofres de produção até que uma versão estável 0.1.10 seja lançada.
def _paginated_vector_search(self, query_vec, page_size=20, max_distance=None):
"""Paginate through KNN results using distance constraints."""
packed = _serialize_vector(query_vec)
constraint = f"AND distance < {max_distance}" if max_distance else ""
results = self.db.execute(f"""
SELECT cv.id, cv.distance, c.file_path, c.chunk_text
FROM chunk_vecs cv
JOIN chunks c ON cv.id = c.id
WHERE embedding MATCH ?
AND k = ?
{constraint}
ORDER BY distance
""", [packed, page_size]).fetchall()
# Use last result's distance as cursor for next page
next_cursor = results[-1][1] if results else None
return results, next_cursor
Isso substitui o padrão anterior de buscar um k grande e fatiar no Python, reduzindo o uso de memória em consultas exploratórias sobre cofres grandes.
Suporte a DELETE em tabelas vec0
O sqlite-vec v0.1.7 adicionou suporte nativo a DELETE para tabelas virtuais vec0, e a v0.1.9 corrigiu um caminho de erro de DELETE envolvendo colunas de texto de metadados com mais de 12 caracteres.1423 Antes, remover vetores exigia descartar e recriar a tabela. Agora, o caminho de remoção de arquivos do indexador pode excluir vetores diretamente:
# Before v0.1.7: required workaround (drop + recreate, or mark as inactive)
# After v0.1.7: direct DELETE works
db.execute("DELETE FROM chunk_vecs WHERE id = ?", [chunk_id])
Isso simplifica a reindexação incremental quando notas são excluídas ou movidas. O indexador não precisa mais manter uma tabela paralela de “IDs ativos” nem rebuilds em lote.
Quando a busca vetorial vence
A busca vetorial se destaca em consultas nas quais o conceito importa mais do que as palavras específicas:
- Consulta: “como lidar com falhas de autenticação” → Encontra notas sobre “recuperação de erro de login” (mesmo espaço semântico, palavras-chave diferentes)
- Consulta: “quais padrões existem para caching” → Encontra notas sobre “memoization”, “estratégias de Redis TTL” e “HTTP cache headers” (conceitos relacionados, terminologia diversa)
- Consulta: “abordagens para testar código assíncrono” → Encontra notas sobre “fixtures pytest-asyncio”, “mock event loops” e “async test patterns” (mesmo conceito expresso por detalhes de implementação)
Quando a busca vetorial falha
A busca vetorial tem dificuldade com identificadores exatos:
- Consulta:
_rrf_fuse→ Retorna notas sobre “fusion algorithms” e “rank merging”, mas pode ranquear a definição real da função abaixo de discussões conceituais - Consulta:
PostToolUse→ Retorna notas sobre “tool lifecycle hooks” e “post-execution handlers” em vez do nome específico do hook
A busca vetorial também tem dificuldade com dados estruturados. Arquivos de configuração JSON, blocos YAML e snippets de código produzem embeddings que capturam padrões estruturais em vez de significado semântico. Um arquivo JSON com "review": true gera um embedding diferente de uma discussão em prosa sobre code review.
Degradação suave
Se o sqlite-vec não carregar (extensão ausente, plataforma incompatível, biblioteca corrompida), o retriever faz fallback para busca apenas com BM25:
class VectorIndex:
def __init__(self, db_path):
self.db = sqlite3.connect(db_path)
self._vec_available = False
try:
self.db.enable_load_extension(True)
self.db.load_extension("vec0")
self._vec_available = True
except Exception:
pass # BM25-only mode
@property
def vec_available(self):
return self._vec_available
O retriever verifica vec_available antes de tentar consultas vetoriais. Quando desabilitado, todas as buscas usam apenas BM25, e a etapa de fusão RRF é ignorada.
Reciprocal Rank Fusion (RRF)
RRF combina duas listas ranqueadas sem exigir calibração de pontuação. Esta seção aborda o algoritmo, um rastreamento de consulta trabalhado, o ajuste do parâmetro k e por que RRF foi escolhido em vez de alternativas. Para uma calculadora interativa com ranks editáveis, presets de cenário e um explorador visual de arquitetura, veja o mergulho aprofundado no hybrid retriever.
O algoritmo
RRF atribui a cada documento uma pontuação baseada apenas na sua posição de rank em cada lista:
score(d) = Σ (weight_i / (k + rank_i))
Onde:
- k é uma constante de suavização (60, seguindo Cormack et al.3)
- rank_i é o rank do documento, baseado em 1, na lista de resultados i
- weight_i é um multiplicador opcional por lista (padrão 1.0)
Documentos que ficam bem ranqueados em várias listas recebem pontuações fusionadas mais altas. Documentos que aparecem em apenas uma lista recebem uma pontuação dessa única fonte.
Por que RRF em vez de alternativas
Combinação linear ponderada exige calibrar pontuações BM25 contra distâncias de cosine similarity. As pontuações BM25 não têm limite superior e escalam com o tamanho do corpus. As distâncias de cosine similarity são limitadas a [0, 2]. Combiná-las exige normalização, e os parâmetros de normalização dependem do dataset. RRF usa apenas posições de rank, que são sempre números inteiros começando em 1, independentemente do método de pontuação.
Modelos de fusão aprendidos exigem dados de treinamento rotulados — pares de relevância entre consulta e documento. Para uma base de conhecimento pessoal, esses dados de treinamento não existem. Você precisaria julgar manualmente centenas de pares consulta-documento para treinar um modelo útil. RRF funciona sem nenhum dado de treinamento.
Métodos de votação Condorcet (Borda count, Schulze method) são teoricamente elegantes, mas mais complexos de implementar e ajustar. O artigo original de RRF demonstrou que RRF supera métodos Condorcet em dados de avaliação TREC.3
Fusão na prática
Consulta: “how does the review aggregator handle disagreements”
BM25 ranqueia review-aggregator.py na posição 3 (correspondências exatas de palavras-chave em “review,” “aggregator,” “disagreements”), mas coloca dois arquivos de configuração acima (eles correspondem a “review” com mais destaque). A busca vetorial ranqueia o mesmo chunk na posição 1 (correspondência semântica em resolução de conflitos). Após a fusão por RRF:
| Chunk | BM25 | Vec | Pontuação fusionada |
|---|---|---|---|
| review-aggregator.py “Disagreement Resolution” | #3 | #1 | 0.0323 |
| code-review-patterns.md “Multi-Reviewer” | #4 | #2 | 0.0317 |
| deliberation-config.json “Review Weights” | #1 | — | 0.0164 |
Chunks que ficam bem ranqueados em ambas as listas sobem para o topo. Chunks que aparecem em apenas uma lista recebem uma pontuação de fonte única e ficam abaixo dos resultados ranqueados em duas listas. A lógica real de resolução de desacordos vence porque os dois métodos a encontraram — BM25 por palavras-chave, busca vetorial por semântica.
Para o rastreamento completo passo a passo com a matemática de RRF por rank, experimente diferentes valores de k na calculadora interativa de RRF.
Implementação
RRF_K = 60
def _rrf_fuse(self, bm25_results, vec_results,
bm25_weight=1.0, vec_weight=1.0):
"""Fuse BM25 and vector results using Reciprocal Rank Fusion."""
scores = {}
for rank, r in enumerate(bm25_results, start=1):
cid = r["id"]
if cid not in scores:
scores[cid] = {
"rrf_score": 0.0,
"file_path": r["file_path"],
"section": r["section"],
"chunk_text": r["chunk_text"],
"bm25_rank": None,
"vec_rank": None,
}
scores[cid]["rrf_score"] += bm25_weight / (self._rrf_k + rank)
scores[cid]["bm25_rank"] = rank
for rank, r in enumerate(vec_results, start=1):
cid = r["id"]
if cid not in scores:
scores[cid] = {
"rrf_score": 0.0,
"file_path": r["file_path"],
"section": r["section"],
"chunk_text": r["chunk_text"],
"bm25_rank": None,
"vec_rank": None,
}
scores[cid]["rrf_score"] += vec_weight / (self._rrf_k + rank)
scores[cid]["vec_rank"] = rank
fused = sorted(
scores.values(),
key=lambda x: x["rrf_score"],
reverse=True,
)
return fused
Ajustando k
A constante k controla quanto peso é dado aos resultados mais bem ranqueados em relação aos resultados de rank mais baixo:
- k mais baixo (por exemplo, 10): Os resultados no topo dominam. Rank 1 pontua 1/11 = 0,091, rank 10 pontua 1/20 = 0,050 (diferença de 1,8x). Bom quando você confia que os rankers individuais acertam o resultado principal.
- k padrão (60): Equilibrado. Rank 1 pontua 1/61 = 0,0164, rank 10 pontua 1/70 = 0,0143 (diferença de 1,15x). As diferenças de rank são comprimidas, dando mais peso a aparecer em várias listas.
- k mais alto (por exemplo, 200): Aparecer nas duas listas importa muito mais do que a posição de rank. Rank 1 pontua 1/201, rank 10 pontua 1/210 — quase idêntico. Use quando os rankers individuais produzem rankings ruidosos, mas a concordância entre listas é confiável.
Comece com k=60. O artigo original de RRF encontrou esse valor robusto em diversos datasets TREC. Ajuste apenas depois de medir casos de falha na sua própria distribuição de consultas.
Desempate
Quando dois chunks têm pontuações RRF idênticas (raro, mas possível com o mesmo rank em uma lista e sem aparecer na outra), desfaça empates assim:
- Prefira chunks que aparecem nas duas listas em vez de chunks que aparecem em apenas uma
- Entre chunks nas duas listas, prefira aquele com o menor rank combinado
- Entre chunks em apenas uma lista, prefira aquele com o menor rank nessa lista
O pipeline completo de retrieval
Esta seção acompanha uma consulta da entrada à saída por todo o pipeline: busca BM25, busca vetorial, fusão RRF, truncamento por orçamento de tokens e montagem do contexto.
Fluxo de ponta a ponta
User query: "PostToolUse hook for context compression"
│
├─ BM25 Search (FTS5)
│ → MATCH "PostToolUse hook context compression"
│ → Top 30 results ranked by BM25 score
│ → 12ms
│
├─ Vector Search (sqlite-vec)
│ → Embed query with Model2Vec
│ → KNN k=30 on chunk_vecs
│ → Top 30 results ranked by cosine distance
│ → 8ms
│
└─ RRF Fusion
→ Merge 60 candidates (may overlap)
→ Score by rank position
→ Top 10 results
→ 3ms
│
└─ Token Budget
→ Truncate to max_tokens (default 4000)
→ Estimate at 4 chars per token
→ Return results with metadata
→ <1ms
Latência total: ~23ms para um banco de dados com 49.746 chunks em hardware Apple M3 Pro.
A API de search
class HybridRetriever:
def search(self, query, limit=10, max_tokens=4000,
bm25_weight=1.0, vec_weight=1.0):
"""
Search the vault using hybrid BM25 + vector retrieval.
Args:
query: Search query text
limit: Maximum results to return
max_tokens: Token budget for total result text
bm25_weight: Weight for BM25 results in RRF
vec_weight: Weight for vector results in RRF
Returns:
List of SearchResult with file_path, section,
chunk_text, rrf_score, bm25_rank, vec_rank
"""
# BM25 search
bm25_results = self._bm25_search(query, limit=30)
# Vector search (if available)
if self.index.vec_available:
vec_results = self._vector_search(query, limit=30)
fused = self._rrf_fuse(
bm25_results, vec_results,
bm25_weight, vec_weight,
)
else:
fused = bm25_results # BM25-only fallback
# Token budget truncation
results = []
token_count = 0
for r in fused[:limit]:
chunk_tokens = len(r["chunk_text"]) // 4
if token_count + chunk_tokens > max_tokens:
break
results.append(r)
token_count += chunk_tokens
return results
Truncamento por orçamento de tokens
O parâmetro max_tokens impede que o retriever retorne mais contexto do que a ferramenta de AI consegue usar. A estimativa usa 4 caracteres por token (uma aproximação razoável para prosa em inglês). Os resultados são truncados de forma gulosa: adiciona resultados na ordem do ranking até o orçamento acabar.
Essa é uma estratégia conservadora. Uma abordagem mais sofisticada consideraria as pontuações de qualidade de cada resultado e preferiria resultados mais curtos e de maior qualidade em vez de resultados mais longos e de menor qualidade. A abordagem gulosa é mais simples e funciona bem na prática porque o ranking RRF já ordena os resultados por relevância.
Esquema do banco de dados (completo)
-- Chunk content and metadata
CREATE TABLE chunks (
id INTEGER PRIMARY KEY,
file_path TEXT NOT NULL,
section TEXT NOT NULL,
chunk_text TEXT NOT NULL,
heading_context TEXT DEFAULT '',
mtime_ns INTEGER NOT NULL,
embedded_at REAL NOT NULL
);
CREATE INDEX idx_chunks_file ON chunks(file_path);
CREATE INDEX idx_chunks_mtime ON chunks(mtime_ns);
-- FTS5 for BM25 search (content-synced to chunks table)
CREATE VIRTUAL TABLE chunks_fts USING fts5(
chunk_text, section, heading_context,
content=chunks, content_rowid=id
);
-- sqlite-vec for vector KNN search
CREATE VIRTUAL TABLE chunk_vecs USING vec0(
id INTEGER PRIMARY KEY,
embedding float[256]
);
-- Model metadata for compatibility tracking
CREATE TABLE model_meta (
key TEXT PRIMARY KEY,
value TEXT
);
Caminho de degradação gradual
Full pipeline: BM25 + Vector + RRF → Best results
No sqlite-vec: BM25 only → Good results (no semantic)
No model download: BM25 only → Good results (no semantic)
No FTS5: Vector only → Decent results (no keyword)
No database: Error → Prompt user to run indexer
O retriever verifica os recursos disponíveis na inicialização e adapta sua estratégia de consulta. Um componente ausente reduz a qualidade, mas não causa erros. A única falha crítica é a ausência do arquivo do banco de dados.
Estatísticas de produção
Medido em um vault com 16.894 arquivos, 49.746 chunks, banco de dados SQLite de 83 MB, Apple M3 Pro:
| Métrica | Valor |
|---|---|
| Total de arquivos | 16.894 |
| Total de chunks | 49.746 |
| Tamanho do banco de dados | 83 MB |
| Latência de consulta BM25 (p50) | 12ms |
| Latência de consulta vetorial (p50) | 8ms |
| Latência da fusão RRF | 3ms |
| Latência de search de ponta a ponta (p50) | 23ms |
| Tempo de reindexação completa | ~4 minutos |
| Tempo de reindexação incremental | <10 segundos |
| Modelo de embedding | potion-base-8M (256-dim) |
| Pool de candidatos BM25 | 30 |
| Pool de candidatos vetoriais | 30 |
| Limite padrão de resultados | 10 |
| Orçamento padrão de tokens | 4.000 tokens |
Hashing de conteúdo e detecção de alterações
O indexador precisa saber quais arquivos mudaram desde a última execução do índice. Esta seção cobre o mecanismo de detecção de alterações e a estratégia de hashing.
Comparação de horário de modificação do arquivo
O indexador armazena mtime_ns (horário de modificação do arquivo em nanossegundos) para cada chunk na tabela chunks. Em uma execução incremental, o indexador:
- Examina o vault em busca de todos os arquivos
.mdnas pastas permitidas - Lê o
mtime_nsde cada arquivo a partir do sistema de arquivos - Compara com o
mtime_nsarmazenado no banco de dados - Identifica três categorias:
- Arquivos novos: o path existe no sistema de arquivos, mas não no banco de dados
- Arquivos alterados: o path existe nos dois, mas o
mtime_nsé diferente - Arquivos excluídos: o path existe no banco de dados, mas não no sistema de arquivos
def get_stale_files(self, vault_mtimes):
"""Find files whose mtime changed or are new."""
stored = dict(self.db.execute(
"SELECT DISTINCT file_path, mtime_ns FROM chunks"
).fetchall())
stale = []
for path, mtime in vault_mtimes.items():
if path not in stored or stored[path] != mtime:
stale.append(path)
return stale
def get_deleted_files(self, vault_paths):
"""Find files in database that no longer exist in vault."""
stored_paths = set(r[0] for r in self.db.execute(
"SELECT DISTINCT file_path FROM chunks"
).fetchall())
return stored_paths - set(vault_paths)
Por que mtime, não hash de conteúdo
O hashing de conteúdo (SHA-256 do conteúdo do arquivo) seria mais confiável do que a comparação por mtime — ele detectaria casos em que um arquivo foi tocado sem alteração (por exemplo, um git checkout restaurando o mtime original). Porém, o hashing exige ler todos os arquivos em cada execução incremental. Para 16.894 arquivos, ler o conteúdo dos arquivos leva de 2 a 3 segundos. Ler mtimes do sistema de arquivos leva <100ms.
O trade-off: a comparação por mtime ocasionalmente dispara a reindexação desnecessária de arquivos inalterados (falsos positivos), mas nunca deixa de detectar alterações reais. Falsos positivos custam algumas chamadas extras de embedding por execução. A diferença de velocidade (100ms vs 3 segundos) torna o mtime a escolha pragmática para um sistema que roda em cada interação com AI.
Como lidar com exclusões
Quando um arquivo é excluído do vault, o indexador remove todos os seus chunks do banco de dados:
def remove_file(self, file_path):
"""Remove all chunks and vectors for a file."""
chunk_ids = [r[0] for r in self.db.execute(
"SELECT id FROM chunks WHERE file_path = ?",
[file_path],
).fetchall()]
for cid in chunk_ids:
self.db.execute(
"DELETE FROM chunk_vecs WHERE id = ?", [cid]
)
self.db.execute(
"DELETE FROM chunks WHERE file_path = ?",
[file_path],
)
A instrução DELETE FROM chunk_vecs funciona nativamente a partir do sqlite-vec v0.1.7, com uma correção de bug na v0.1.9 para operações DELETE em tabelas vec0 com colunas de texto de metadados mais longas.1423 Versões anteriores exigiam workarounds (remover e recriar a tabela virtual, ou manter um conjunto externo de “IDs ativos”). Se você estiver usando uma versão anterior à 0.1.9, atualize antes de depender de exclusões diretas em esquemas com muitos metadados.
Tabelas FTS5 com sincronização de conteúdo exigem exclusão explícita via INSERT INTO chunks_fts(chunks_fts, rowid, ...) VALUES('delete', ?, ...) para cada linha removida. O indexador lida com isso como parte do processo de remoção de arquivos.
Reindex incremental vs completo
O indexador oferece suporte a dois modos: incremental (rápido, para uso diário) e completo (lento, ocasional). Esta seção explica quando usar cada um, as garantias de idempotência e a recuperação de corrupção.
Reindex incremental
Quando usar: Indexação diária depois de editar notas. É o modo padrão.
O que ele faz: 1. Varre o vault em busca de alterações de arquivos (comparação de mtime) 2. Exclui chunks de arquivos removidos 3. Refaz o chunking e os embeddings dos arquivos alterados 4. Insere novos chunks para arquivos novos 5. Sincroniza o índice FTS5
Duração típica: <10 segundos para as edições de um dia em um vault com 16.000 arquivos.
python index_vault.py --incremental
Reindex completo
Quando usar: - Depois de alterar o modelo de embedding (incompatibilidade de hash do modelo detectada) - Depois de uma migração de schema (novas colunas, índices alterados) - Depois de corrupção do banco de dados (falha na verificação de integridade) - Quando a indexação incremental produz resultados inesperados
O que ele faz: 1. Remove todos os dados existentes (chunks, vetores, entradas FTS5) 2. Varre o vault inteiro 3. Faz o chunking de todos os arquivos 4. Gera embeddings de todos os chunks 5. Cria o índice FTS5 do zero
Duração típica: ~4 minutos para 16.894 arquivos no Apple M3 Pro.
python index_vault.py --full
Idempotência
Ambos os modos são idempotentes: executar o mesmo comando duas vezes produz o mesmo resultado. O indexador exclui os chunks existentes de um arquivo antes de inserir novos, então repetir a indexação incremental em um banco de dados já atualizado produz zero alterações. Repetir a indexação completa produz um banco de dados idêntico.
Recuperação de corrupção
Se o banco de dados SQLite for corrompido (queda de energia durante a escrita, erro de disco, processo encerrado no meio de uma transação):
# Check integrity
sqlite3 vectors.db "PRAGMA integrity_check;"
# If corruption detected, full reindex rebuilds from source files
python index_vault.py --full
A fonte da verdade sempre são os arquivos do vault, não o banco de dados. O banco de dados é um artefato derivado que pode ser reconstruído a qualquer momento. Esta é uma propriedade crítica do design: você nunca precisa fazer backup do banco de dados.
A flag --incremental
Quando o indexador roda com --incremental:
- Verificação do hash do modelo. Compara o hash do modelo armazenado com o modelo atual. Se for diferente, muda automaticamente para o modo de reindex completo e avisa o usuário.
- Varredura de arquivos. Percorre as pastas permitidas, coleta caminhos de arquivos e mtimes.
- Detecção de alterações. Compara com os dados armazenados.
- Processamento em lote. Refaz o chunking e os embeddings dos arquivos alterados em lotes de 64.
- Relatório de progresso. Imprime a contagem de arquivos processados e o tempo decorrido.
- Encerramento controlado. Trata SIGINT concluindo o arquivo atual antes de parar.
Filtragem de credenciais e limites de dados
Notas pessoais contêm segredos: chaves API, bearer tokens, strings de conexão de banco de dados, chaves privadas coladas durante sessões de debugging. O filtro de credenciais impede que isso entre no índice de retrieval.
O problema
Uma nota sobre debugging de uma integração OAuth pode conter:
The token was: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
I used this curl command:
curl -H "Authorization: Bearer sk-ant-api03-abc123..."
Sem filtragem, tanto o JWT quanto a chave API seriam divididos em chunks, transformados em embeddings e armazenados no banco de dados. Uma busca por “authentication” retornaria o chunk contendo segredos reais. Pior, se o retriever enviar resultados para uma ferramenta de AI por meio de MCP, os segredos aparecem na janela de contexto da AI e, potencialmente, nos logs da ferramenta.
Filtragem baseada em padrões
O filtro de credenciais roda em cada chunk antes do armazenamento, fazendo correspondência com 25 padrões específicos de fornecedores, além de padrões genéricos:
Padrões específicos de fornecedores:
| Padrão | Exemplo | Regex |
|---|---|---|
| Chave API da OpenAI | sk-... |
sk-[a-zA-Z0-9_-]{20,} |
| Chave API da Anthropic | sk-ant-api03-... |
sk-ant-api\d{2}-[a-zA-Z0-9_-]{20,} |
| PAT do GitHub | ghp_... |
gh[ps]_[a-zA-Z0-9]{36,} |
| AWS Access Key | AKIA... |
AKIA[0-9A-Z]{16} |
| Chave Stripe | sk_live_... |
[sr]k_(live\|test)_[a-zA-Z0-9]{24,} |
| Token Cloudflare | ... |
Vários padrões |
Padrões genéricos:
| Padrão | Detecção |
|---|---|
| JWT tokens | eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+ |
| Bearer tokens | Bearer\s+[a-zA-Z0-9_\-\.]+ |
| Chaves privadas | -----BEGIN (RSA\|EC\|OPENSSH) PRIVATE KEY----- |
| base64 de alta entropia | Strings com entropia >4,5 bits/caractere, 40+ caracteres |
| Atribuições de senha | password\s*[:=]\s*["'][^"']+["'] |
Implementação do filtro
def clean_content(text):
"""Scrub credentials from text before indexing."""
result = ScanResult(is_clean=True, match_count=0, patterns=[])
for pattern in CREDENTIAL_PATTERNS:
matches = pattern.regex.findall(text)
if matches:
text = pattern.regex.sub(
f"[REDACTED:{pattern.name}]", text
)
result.is_clean = False
result.match_count += len(matches)
result.patterns.append(pattern.name)
return text, result
Principais escolhas de design:
-
Filtrar antes do embedding. O texto limpo é o que recebe o embedding. A representação vetorial nunca codifica padrões de credenciais. Uma consulta por “chave API” retorna notas que discutem gerenciamento de chaves API, não notas que contêm chaves reais.
-
Substituir, não remover. O token
[REDACTED:pattern-name]preserva o contexto semântico do texto ao redor. O embedding captura que “algo parecido com uma credencial estava aqui” sem codificar a credencial em si. -
Registrar padrões, não valores. O filtro registra quais padrões corresponderam (por exemplo, “Scrubbed 2 credential(s) from oauth-debug.md [jwt, bearer-token]”), mas nunca registra o valor da credencial.
Exclusão baseada em caminho
O arquivo .indexignore oferece exclusão granular ampla por caminho. O filtro de credenciais oferece limpeza granular fina dentro dos arquivos indexados. Ambos são necessários:
.indexignorepara pastas inteiras que você sabe que contêm conteúdo sensível (notas de saúde, registros financeiros, documentos de carreira)- Filtro de credenciais para segredos acidentalmente incorporados em conteúdo que, de outra forma, poderia ser indexado
Classificação de dados
Para vaults com conteúdo diverso, considere classificar as notas por sensibilidade:
| Nível | Exemplos | Indexar? | Filtrar? |
|---|---|---|---|
| Público | Rascunhos de blog, notas técnicas | Sim | Sim |
| Interno | Planos de projeto, decisões de arquitetura | Sim | Sim |
| Sensível | Dados salariais, registros de saúde | Não (.indexignore) | N/A |
| Restrito | Credenciais, chaves privadas | Não (.indexignore) | N/A |
Arquitetura do servidor MCP
Servidores Model Context Protocol (MCP) expõem o retriever como uma ferramenta que agentes de IA podem chamar. Esta seção cobre o design do servidor, a superfície de capacidades e os limites de permissão.
Escolha de protocolo: STDIO vs HTTP
MCP oferece suporte a 2 modos de transporte:
STDIO — A ferramenta de IA inicia o servidor MCP como um processo filho e se comunica por stdin/stdout. Este é o modo padrão para ferramentas locais. Claude Code, Codex CLI e Cursor oferecem suporte a servidores MCP via STDIO.
{
"mcpServers": {
"obsidian": {
"command": "python",
"args": ["/path/to/obsidian_mcp.py"],
"env": {
"VAULT_PATH": "/path/to/vault",
"DB_PATH": "/path/to/vectors.db"
}
}
}
}
HTTP — O servidor MCP roda como um serviço HTTP independente. Útil para acesso remoto, configurações com vários clientes ou configurações de equipe em que o vault está em um servidor compartilhado.
{
"mcpServers": {
"obsidian": {
"url": "http://localhost:3333/mcp"
}
}
}
Recomendação: Use STDIO para vaults pessoais. É mais simples, mais seguro (sem exposição à rede), e o ciclo de vida do servidor é gerenciado pela ferramenta de IA. Use HTTP somente quando várias ferramentas ou várias máquinas precisarem de acesso simultâneo ao mesmo vault.
Evolução da especificação MCP. A especificação MCP de junho de 2025 adicionou autorização OAuth 2.1, saídas estruturadas de ferramentas (esquemas de retorno tipados) e elicitação (prompts de usuário iniciados pelo servidor). A versão de novembro de 2025 lançou Streamable HTTP como modo de transporte de primeira classe, descoberta de URL
.well-knownpara navegação automática das capacidades do servidor, anotações estruturadas de ferramentas que declaram se uma ferramenta é somente leitura ou mutável, e um sistema de padronização por níveis SDK.79 A próxima revisão agora é concreta: a especificação de 2026-07-28 entrou em Release Candidate em 21 de maio de 2026 — a maior revisão do MCP desde o lançamento. Suas principais mudanças são um núcleo de protocolo stateless (o handshakeinitializee o cabeçalhoMcp-Session-Idsão removidos, então os servidores deixam de rastrear estado de sessão por conexão), Apps MCP (servidores podem retornar HTML renderizado pelo servidor exibido em iframes de cliente em sandbox), Tasks saindo do core experimental para uma extensão oficial (tasks/get,tasks/update,tasks/cancelpara operações de longa duração), autorização OAuth 2.0 / OIDC reforçada e uma política de ciclo de vida de depreciação de recursos de 12 meses. A especificação final será lançada em 28 de julho de 2026.24 Para servidores de vault pessoal, STDIO continua sendo o caminho mais simples, e o núcleo stateless torna servidores STDIO de usuário único ainda mais enxutos. O transporte Streamable HTTP, a descoberta.well-knowne os Apps MCP beneficiam principalmente implantações HTTP empresariais com roteamento multi-tenant e balanceamento de carga. Monitore o roadmap do MCP para atualizações que afetem sua escolha de transporte.
Design de capacidades
O servidor MCP deve expor um conjunto mínimo de ferramentas:
search — A ferramenta principal. Executa recuperação hybrid e retorna resultados ranqueados.
{
"name": "obsidian_search",
"description": "Search the Obsidian vault using hybrid BM25 + vector retrieval",
"parameters": {
"query": { "type": "string", "description": "Search query" },
"limit": { "type": "integer", "default": 5 },
"max_tokens": { "type": "integer", "default": 2000 }
}
}
read_note — Lê o conteúdo completo de uma nota específica pelo caminho. Útil quando o agente quer ver o contexto completo de um resultado de busca.
{
"name": "obsidian_read_note",
"description": "Read the full content of a note by file path",
"parameters": {
"file_path": { "type": "string", "description": "Relative path within vault" }
}
}
list_notes — Lista notas que correspondem a um filtro (por pasta, tag, tipo ou intervalo de datas). Útil para exploração quando o agente não tem uma consulta específica.
{
"name": "obsidian_list_notes",
"description": "List notes matching filters",
"parameters": {
"folder": { "type": "string", "description": "Folder path within vault" },
"tag": { "type": "string", "description": "Tag to filter by" },
"limit": { "type": "integer", "default": 20 }
}
}
get_context — Uma ferramenta de conveniência que executa uma busca e formata os resultados como um bloco de contexto adequado para injeção em uma conversa.
{
"name": "obsidian_get_context",
"description": "Get formatted context from vault for a topic",
"parameters": {
"topic": { "type": "string", "description": "Topic to get context for" },
"max_tokens": { "type": "integer", "default": 2000 }
}
}
Limites de permissão
O servidor MCP deve impor limites rígidos:
-
Somente leitura. O servidor lê o vault e o banco de dados de índice. Ele não cria, modifica nem exclui notas. Operações de escrita (captura de novas notas) são tratadas por hooks ou skills separados, não pelo servidor MCP.
-
Limitado ao vault. O servidor lê apenas arquivos dentro do caminho de vault configurado. Tentativas de path traversal (
../../etc/passwd) devem ser rejeitadas. -
Saída com filtragem de credenciais. Mesmo que o banco de dados contenha conteúdo pré-filtrado, aplique filtragem de credenciais na saída como medida de defesa em profundidade.
-
Respostas limitadas por token. Aplique
max_tokensem todas as respostas das ferramentas para impedir que a ferramenta de IA receba blocos de contexto grandes demais.
Tratamento de erros
Ferramentas MCP devem retornar mensagens de erro estruturadas que ajudem a ferramenta de IA a se recuperar:
def search(self, query, limit=5, max_tokens=2000):
if not self.db_path.exists():
return {
"error": "Index database not found. Run the indexer first.",
"suggestion": "python index_vault.py --full"
}
results = self.retriever.search(query, limit, max_tokens)
if not results:
return {
"results": [],
"message": f"No results found for '{query}'. Try broader terms."
}
return {
"results": [
{
"file_path": r["file_path"],
"section": r["section"],
"text": r["chunk_text"],
"score": round(r["rrf_score"], 4),
}
for r in results
],
"count": len(results),
"query": query,
}
Integração com Claude Code
Claude Code é o principal consumidor do sistema de recuperação do Obsidian. Esta seção cobre a configuração do MCP, a integração com hooks e o padrão obsidian_bridge.py.
Configuração do MCP
Adicione o servidor MCP do Obsidian a ~/.claude/settings.json:
{
"mcpServers": {
"obsidian": {
"command": "python",
"args": ["/path/to/obsidian_mcp.py"],
"env": {
"VAULT_PATH": "/absolute/path/to/vault",
"DB_PATH": "/absolute/path/to/vectors.db"
}
}
}
}
Depois de adicionar a configuração, reinicie o Claude Code. O servidor MCP será iniciado como um processo filho. Verifique se ele está em execução:
> What tools do you have from the obsidian MCP server?
Claude Code deve listar as ferramentas disponíveis (obsidian_search, obsidian_read_note, etc.).
Integração com hooks
Hooks estendem o comportamento do Claude Code em pontos definidos do ciclo de vida. Dois hooks são relevantes para a integração com o Obsidian:
Hook PreToolUse — Consulta o vault antes que o agente processe uma chamada de ferramenta. Injeta automaticamente o contexto relevante.
#!/bin/bash
# ~/.claude/hooks/pre-tool-use/obsidian-context.sh
# Automatically inject vault context before tool execution
TOOL_NAME="$1"
PROMPT="$2"
# Only inject context for code-related tools
case "$TOOL_NAME" in
Edit|Write|Bash)
# Query the vault
CONTEXT=$(python /path/to/retriever.py search "$PROMPT" --limit 3 --max-tokens 1500)
if [ -n "$CONTEXT" ]; then
echo "---"
echo "Relevant vault context:"
echo "$CONTEXT"
echo "---"
fi
;;
esac
Hook PostToolUse — Captura saídas significativas de ferramentas de volta para o vault para recuperação futura.
#!/bin/bash
# ~/.claude/hooks/post-tool-use/capture-insight.sh
# Capture significant outputs to vault (selective)
TOOL_NAME="$1"
OUTPUT="$2"
# Only capture substantial outputs
if [ ${#OUTPUT} -gt 500 ]; then
python /path/to/capture.py --text "$OUTPUT" --source "claude-code-$TOOL_NAME"
fi
O padrão obsidian_bridge.py
Um módulo de ponte fornece um API Python que hooks e skills podem chamar:
# obsidian_bridge.py
from retriever import HybridRetriever
_retriever = None
def get_retriever():
global _retriever
if _retriever is None:
_retriever = HybridRetriever(
db_path="/path/to/vectors.db",
vault_path="/path/to/vault",
)
return _retriever
def search_vault(query, limit=5, max_tokens=2000):
"""Search vault and return formatted context."""
retriever = get_retriever()
results = retriever.search(query, limit, max_tokens)
if not results:
return ""
lines = ["## Vault Context\n"]
for r in results:
lines.append(f"**{r['file_path']}** — {r['section']}")
lines.append(f"> {r['chunk_text'][:500]}")
lines.append("")
return "\n".join(lines)
A skill /capture
Uma skill do Claude Code para capturar insights de volta para o vault:
/capture "OAuth token rotation requires both access and refresh token invalidation"
--domain security
--tags oauth,tokens
A skill cria uma nova nota em 00-inbox/ com frontmatter adequado e aciona uma reindexação incremental para que a nova nota fique imediatamente pesquisável.
Padrões de comandos personalizados
Skills do Claude Code podem encapsular operações do vault em comandos nomeados. Profissionais criaram bibliotecas de comandos específicos para Obsidian que tratam o vault tanto como fonte de leitura quanto como destino de escrita.
Varredura de sinais. Um comando /scan-intel consulta fontes externas, pontua descobertas em relação a interesses pessoais de pesquisa e grava sinais qualificados como notas do vault com frontmatter:
/scan-intel --topics "agent infrastructure, security" --lookback 7d
O comando busca dados em fontes configuradas (arXiv, HN, RSS), aplica um modelo de pontuação (relevância, acionabilidade, profundidade, autoridade) e grava os sinais aprovados em pastas do vault específicas por tópico. O vault se torna o consumidor downstream de um pipeline automatizado de inteligência.
Diário do capitão. Um comando /captains-log agrega a atividade diária do git em todos os repositórios, grava uma entrada de diário estruturada no vault e inclui decisões tomadas, percepções e tópicos em aberto:
/captains-log
O comando extrai o histórico de commits de GitHub, agrupa por repositório e formata como uma entrada narrativa de diário. Com o tempo, os logs diários criam um registro pesquisável do que foi entregue e por quê.
Captura no Obsidian. Um comando /obsidian-capture pega um insight da sessão atual do Claude Code e o grava diretamente no vault com os metadados adequados:
/obsidian-capture "SAST gates in agent loops increase security degradation"
--folder AI-Tools --tags security,agents
O padrão se estende a qualquer operação no vault: criar MOCs, atualizar notas de status de projetos, vincular sinais relacionados ou gerar resumos semanais a partir dos logs diários acumulados.
Exemplos da comunidade. Profissionais estão publicando suas bibliotecas de comandos. Um desenvolvedor compartilhou 22 comandos personalizados de Obsidian + Claude Code cobrindo revisões diárias, planejamento de projetos, captura de pesquisa e fluxos de trabalho de conteúdo.1 Outro criou uma skill “Visual Explainer” que gera notas de diagramas no vault a partir da análise de código.2 Os comandos variam, mas a arquitetura é consistente: skills do Claude Code como interface, notas do vault como camada de armazenamento e infraestrutura de recuperação como mecanismo de consulta.
Gerenciamento da janela de contexto
A integração deve considerar a janela de contexto do Claude Code:
- Limite o contexto injetado a 1.500-2.000 tokens por consulta. Mais do que isso compete com a memória de trabalho do agente.
- Inclua atribuição da fonte. Sempre inclua o caminho do arquivo e o título da seção para que o agente possa referenciar a fonte.
- Trunque o texto do chunk. Chunks longos devem ser truncados com
...em vez de omitidos por completo. Os primeiros 300-500 caracteres geralmente contêm a informação principal. - Não injete em toda chamada de ferramenta. O hook PreToolUse deve injetar contexto seletivamente com base na ferramenta chamada. Operações de leitura não precisam de contexto do vault. Operações Write e Edit se beneficiam dele.
Integração com Codex CLI
Codex CLI se conecta a servidores MCP por meio de config.toml. O padrão de integração difere do Claude Code na sintaxe de configuração e na entrega de instruções.
Configuração do MCP
Adicione a .codex/config.toml ou ~/.codex/config.toml:
[mcp_servers.obsidian]
command = "python"
args = ["/path/to/obsidian_mcp.py"]
[mcp_servers.obsidian.env]
VAULT_PATH = "/absolute/path/to/vault"
DB_PATH = "/absolute/path/to/vectors.db"
Padrões de AGENTS.md
Codex CLI lê AGENTS.md para instruções no nível do projeto. Inclua orientações de busca no vault:
## Available Tools
### Obsidian Vault (MCP: obsidian)
Use the `obsidian_search` tool to find relevant context from the knowledge base.
Search the vault when you need:
- Background on a concept or pattern
- Prior decisions or rationale
- Reference material for implementation
Example queries:
- "authentication patterns in FastAPI"
- "how does the review aggregator work"
- "sqlite-vec configuration"
Diferenças em relação ao Claude Code
| Recurso | Claude Code | Codex CLI |
|---|---|---|
| Configuração do MCP | settings.json |
config.toml |
| Hooks | ~/.claude/hooks/ |
Não compatível |
| Skills | ~/.claude/skills/ |
Não compatível |
| Arquivo de instruções | CLAUDE.md |
AGENTS.md |
| Modos de aprovação | --dangerously-skip-permissions |
suggest / auto-edit / full-auto |
Diferença principal: Codex CLI não oferece suporte a hooks. O padrão de injeção automática de contexto (hook PreToolUse) não está disponível. Em vez disso, inclua instruções explícitas em AGENTS.md dizendo ao agente para pesquisar no vault antes de começar o trabalho.
Cursor e outras ferramentas
Cursor e outras ferramentas de AI compatíveis com MCP podem se conectar ao mesmo servidor MCP do Obsidian. Esta seção cobre a configuração para ferramentas comuns.
Cursor
Adicione a .cursor/mcp.json na raiz do seu projeto:
{
"mcpServers": {
"obsidian": {
"command": "python",
"args": ["/path/to/obsidian_mcp.py"],
"env": {
"VAULT_PATH": "/absolute/path/to/vault",
"DB_PATH": "/absolute/path/to/vectors.db"
}
}
}
}
O arquivo .cursorrules do Cursor pode incluir instruções para usar o vault:
When working on implementation tasks, search the Obsidian vault
for relevant context before writing code. Use the obsidian_search
tool with descriptive queries about the concept you're implementing.
Matriz de compatibilidade
| Ferramenta | Suporte a MCP | Transporte | Local da configuração |
|---|---|---|---|
| Claude Code | Completo | STDIO | ~/.claude/settings.json |
| Codex CLI | Completo | STDIO | .codex/config.toml |
| Cursor | Completo | STDIO | .cursor/mcp.json |
| Windsurf | Completo | STDIO | .windsurf/mcp.json |
| Continue.dev | Parcial | HTTP | ~/.continue/config.json |
| Zed | Em andamento | STDIO | Settings UI |
| Claudian (plugin do Obsidian) | N/A (embutido) | Claude Code CLI | configurações do plugin do Obsidian |
| Agent Client (plugin do Obsidian) | N/A (embutido) | ACP | configurações do plugin do Obsidian |
Fallback para ferramentas sem MCP
Para ferramentas que não são compatíveis com MCP, o retriever pode ser encapsulado como uma CLI:
# Search from command line
python retriever_cli.py search "query text" --limit 5
# Output formatted for copy-paste into any tool
python retriever_cli.py context "query text" --format markdown
A CLI gera texto estruturado que pode ser colado manualmente na entrada de qualquer ferramenta de AI. Isso é menos elegante do que a integração com MCP, mas funciona universalmente.
Prompt caching a partir de notas estruturadas
Notas estruturadas no vault podem servir como blocos de contexto reutilizáveis que reduzem o uso de tokens entre interações com AI. Esta seção cobre o design de chaves de cache e o gerenciamento do orçamento de tokens.
O padrão
Em vez de buscar contexto a cada interação, pré-construa blocos de contexto a partir de notas bem estruturadas do vault e armazene-os em cache:
# cache_keys.py
CONTEXT_BLOCKS = {
"auth-patterns": {
"vault_query": "authentication patterns implementation",
"max_tokens": 1500,
"ttl_hours": 24, # Rebuild daily
},
"api-conventions": {
"vault_query": "API design conventions REST patterns",
"max_tokens": 1000,
"ttl_hours": 168, # Rebuild weekly
},
"project-architecture": {
"vault_query": "current project architecture decisions",
"max_tokens": 2000,
"ttl_hours": 12, # Rebuild twice daily
},
}
Invalidação de cache
A invalidação de cache se baseia em dois sinais:
- Expiração do TTL. Cada bloco de contexto tem um time-to-live. Quando o TTL expira, o bloco é reconstruído por meio de uma nova consulta ao vault.
- Detecção de mudanças no vault. Quando o indexer detecta alterações em arquivos que contribuíram para um bloco de contexto em cache, o bloco é invalidado imediatamente.
Gerenciamento do orçamento de tokens
Uma sessão começa com um orçamento total de contexto. Blocos em cache consomem parte desse orçamento:
Total context budget: 8,000 tokens
├─ System prompt: 1,500 tokens
├─ Cached blocks: 3,000 tokens (pre-loaded)
├─ Dynamic search: 2,000 tokens (on-demand)
└─ Conversation: 1,500 tokens (remaining)
Os blocos em cache são carregados no início da sessão. Resultados de busca dinâmicos preenchem o orçamento restante por consulta. Essa abordagem híbrida dá ao agent uma base de contexto frequentemente necessário, preservando orçamento para consultas específicas.
Uso de tokens antes/depois
Sem cache: Toda consulta relevante aciona uma busca no vault, retornando 1.500-2.000 tokens de contexto. Ao longo de 10 consultas em uma sessão, o agent consome 15.000-20.000 tokens de contexto do vault.
Com cache: Três blocos de contexto pré-construídos consomem 4.500 tokens no total. Buscas adicionais adicionam 1.500-2.000 tokens por consulta única. Ao longo de 10 consultas em que 6 são cobertas por blocos em cache, o agent consome 4.500 + (4 * 1.500) = 10.500 tokens — aproximadamente metade do uso sem cache.
Hooks PostToolUse para compressão de contexto
Saídas de ferramentas podem ser verbosas: stack traces, listagens de arquivos, resultados de testes. Um hook PostToolUse pode compactar essas saídas antes que elas consumam espaço na janela de contexto.
O problema
Uma chamada da ferramenta Bash que executa testes poderia retornar:
PASSED tests/test_auth.py::test_login_success
PASSED tests/test_auth.py::test_login_failure
PASSED tests/test_auth.py::test_token_refresh
PASSED tests/test_auth.py::test_session_expiry
... (200 more lines)
FAILED tests/test_api.py::test_rate_limit_exceeded
A saída completa tem 5.000 tokens, mas o sinal está em 2 linhas: 200 passaram, 1 falhou.
Implementação do hook
#!/bin/bash
# ~/.claude/hooks/post-tool-use/compress-output.sh
# Compress verbose tool outputs to preserve context window
TOOL_NAME="$1"
OUTPUT="$2"
OUTPUT_LEN=${#OUTPUT}
# Only compress large outputs
if [ "$OUTPUT_LEN" -lt 2000 ]; then
exit 0 # Pass through unchanged
fi
case "$TOOL_NAME" in
Bash)
# Compress test output
if echo "$OUTPUT" | grep -q "PASSED\|FAILED"; then
PASSED=$(echo "$OUTPUT" | grep -c "PASSED")
FAILED=$(echo "$OUTPUT" | grep -c "FAILED")
FAILURES=$(echo "$OUTPUT" | grep "FAILED")
echo "Tests: $PASSED passed, $FAILED failed"
if [ "$FAILED" -gt 0 ]; then
echo "Failures:"
echo "$FAILURES"
fi
fi
;;
esac
Prevenção de disparo recursivo
Um hook de compressão que emite saída poderia disparar a si mesmo se não tiver uma proteção:
# Guard against recursive invocation
if [ -n "$COMPRESS_HOOK_ACTIVE" ]; then
exit 0
fi
export COMPRESS_HOOK_ACTIVE=1
Heurísticas de compressão
| Tipo de saída | Detecção | Estratégia de compressão |
|---|---|---|
| Resultados de testes | palavras-chave PASSED / FAILED |
Contar pass/fail, mostrar apenas falhas |
| Listagens de arquivos | ls ou find no comando |
Truncar para as primeiras 20 entradas + contagem |
| Stack traces | palavra-chave Traceback |
Manter o primeiro e o último frame + mensagem de erro |
| Git status | modified: / new file: |
Resumir contagens por status |
| Saída de build | warning: / error: |
Remover linhas informativas, manter avisos/erros |
Pipeline de entrada e triagem de sinais
A camada de entrada determina o que entra no vault. Sem curadoria, o vault acumula ruído. Esta seção cobre o pipeline de pontuação que encaminha sinais para pastas de domínio.
Fontes
Os sinais vêm de vários canais:
- Feeds RSS: blogs técnicos, avisos de segurança, release notes
- Bookmarks via Web Clipper: a extensão oficial Obsidian Web Clipper (Chrome, Firefox, Safari) é o caminho de entrada com maior fidelidade para captura pelo navegador. O ciclo de lançamentos de abril de 2026 tornou a extensão bem mais útil para workflows de AI:22
- 1.4.0 (9 de abr.): UI interativa de transcrição do YouTube — fixe o vídeo, navegue pela transcrição, use rolagem automática e destaque a posição atual. Além de um padrão “Open in Reader” que envia uma captura com 1 clique direto para o modo Reader.
- 1.5.0–1.5.1 (15 de abr.): visualizador de destaques — navegue e pesquise destaques capturados em todo o vault. Transição em fade-in para o Reader. Reprodução/pausa mais suave no YouTube. A 1.5.1 corrigiu uma regressão de compilação do webpack.
- 1.6.0–1.6.2 (21–23 de abr.): reformulação da UX do marcador com suporte a mobile. Defuddle 0.18 adiciona extratores específicos por fonte para LinkedIn, Threads, Bluesky, Discourse e Medium. A 1.6.2 corrige uma regressão da área de transferência no modo incorporado do Safari. Configure templates por domínio de origem para que transcrições do YouTube, READMEs do GitHub e artigos longform sejam salvos em notas com nomes sensatos e o frontmatter certo para o pipeline de pontuação abaixo.
- Newsletters: trechos importantes de newsletters por email
- Captura manual: notas escritas durante leitura, conversas ou pesquisa
- Saída de ferramentas: saídas significativas de ferramentas de AI capturadas via hooks
- iOS Share Extension: o app iOS do Obsidian (atualizado no início de 2026) inclui uma Share Extension que salva conteúdo do Safari, redes sociais e outros apps diretamente no vault sem abrir o Obsidian.19 Isso cria um caminho de entrada mobile com pouco atrito — compartilhe um artigo do Safari e ele chega como uma nota do vault pronta para pontuação.
- Obsidian CLI: scripts de shell e hooks podem criar notas via
obsidian file createou anexar conteúdo a notas existentes viaobsidian file append, permitindo pipelines automatizados de entrada no desktop.
Dimensões de pontuação
Cada sinal recebe pontuação em quatro dimensões (0,0 a 1,0 cada):
| Dimensão | Pergunta | Pontuação baixa (0,0-0,3) | Pontuação alta (0,7-1,0) |
|---|---|---|---|
| Relevância | Isto se relaciona aos meus domínios ativos? | Tangencial, fora do escopo | Diretamente relevante para o trabalho ativo |
| Acionabilidade | Posso usar esta informação? | Teoria pura, sem aplicação | Técnica ou padrão específico que posso aplicar |
| Profundidade | Quão substancial é o conteúdo? | Manchetes, resumo superficial | Análise detalhada com exemplos |
| Autoridade | Quão confiável é a fonte? | Blog anônimo, não verificado | Fonte primária, revisada por pares, especialista reconhecido |
Pontuação composta e roteamento
composite = (relevance * 0.35) + (actionability * 0.25) +
(depth * 0.25) + (authority * 0.15)
| Faixa de pontuação | Ação |
|---|---|
| 0,55+ | Encaminhar automaticamente para a pasta de domínio |
| 0,40 - 0,55 | Colocar na fila para revisão manual |
| < 0,40 | Descartar (não armazenar) |
Roteamento por domínio
Sinais com pontuação acima de 0,55 são encaminhados para uma das 12 pastas de domínio com base em correspondência de palavras-chave e classificação de tópico:
05-signals/
├── ai-tooling/ # Claude, LLMs, AI development tools
├── security/ # Vulnerabilities, auth, cryptography
├── systems/ # Architecture, distributed systems
├── programming/ # Languages, patterns, algorithms
├── web/ # Frontend, backends, APIs
├── data/ # Databases, data engineering
├── devops/ # CI/CD, containers, infrastructure
├── design/ # UI/UX, product design
├── mobile/ # iOS, Android, cross-platform
├── career/ # Industry trends, hiring, growth
├── research/ # Academic papers, whitepapers
└── other/ # Signals that don't fit a domain
Estatísticas de produção
Ao longo de 14 meses de operação:
| Métrica | Valor |
|---|---|
| Total de sinais processados | 7.771 |
| Encaminhados automaticamente (>0,55) | 4.832 (62%) |
| Na fila para revisão (0,40-0,55) | 1.543 (20%) |
| Descartados (<0,40) | 1.396 (18%) |
| Pastas de domínio ativas | 12 |
| Média de sinais por dia | ~18 |
Padrões de Knowledge Graph
O grafo de wiki-links do Obsidian codifica relações entre notas. Esta seção cobre semântica de links, travessia do grafo para expansão de contexto e anti-padrões que degradam a qualidade do grafo.
Semântica de backlinks
Todo wiki-link cria uma aresta direcionada no grafo. O Obsidian rastreia tanto links diretos quanto backlinks:
- Link direto: a nota A contém
[[Note B]]→ A aponta para B - Backlink: a nota B mostra que a nota A faz referência a ela
O grafo codifica diferentes tipos de relação dependendo do contexto:
| Padrão de link | Semântica | Exemplo |
|---|---|---|
| Link inline | “Está relacionado a” | “Veja [[OAuth Token Rotation]] para detalhes” |
| Link em cabeçalho | “Tem subtópico” | ”## Related\n- [[Token Rotation]]\n- [[Session Management]]” |
| Link estilo tag | “É categorizado como” | ”[[type/reference]]” |
| Link MOC | “Faz parte de” | Uma nota Map of Content que lista notas relacionadas |
Maps of Content (MOCs)
MOCs são notas de índice que organizam notas relacionadas em uma estrutura navegável:
---
title: "Authentication & Security MOC"
type: moc
domain: security
---
## Core Concepts
- [[OAuth 2.0 Overview]]
- [[JWT Token Anatomy]]
- [[Session Management Patterns]]
## Implementation Patterns
- [[OAuth Token Rotation]]
- [[Refresh Token Security]]
- [[PKCE Flow Implementation]]
## Failure Modes
- [[Token Expiry Handling]]
- [[Session Fixation Prevention]]
- [[CSRF Defense Strategies]]
MOCs beneficiam a recuperação de duas formas:
- Correspondência direta. Uma busca por “visão geral de autenticação” corresponde ao próprio MOC, fornecendo ao agente uma lista curada de notas relacionadas.
- Expansão de contexto. Depois de encontrar uma nota específica, o retriever pode verificar se a nota aparece em algum MOC e incluir a estrutura do MOC nos resultados, dando ao agente um mapa do tópico mais amplo.
Travessia do grafo para expansão de contexto
Uma melhoria futura para o retriever: depois de encontrar os principais resultados, expandir o contexto seguindo links:
def expand_context(results, depth=1):
"""Follow wiki-links from top results to find related context."""
expanded = set()
for result in results:
# Parse wiki-links from chunk text
links = extract_wiki_links(result["chunk_text"])
for link_target in links:
# Resolve link to file path
target_path = resolve_wiki_link(link_target)
if target_path and target_path not in expanded:
expanded.add(target_path)
# Include target's most relevant chunk
target_chunks = get_chunks_for_file(target_path)
# ... rank and include best chunk
return results + list(expanded_results)
Isto não está implementado no retriever atual, mas representa uma extensão natural da estrutura do grafo.
Anti-padrões
Clusters órfãos. Grupos de notas que apontam umas para as outras, mas não têm conexões com o restante do vault. O painel de grafo no Obsidian torna isso visível como ilhas desconectadas. Clusters órfãos indicam MOCs ausentes ou links entre domínios ausentes.
Proliferação de tags. Usar tags de forma inconsistente ou criar tags granulares demais. Um vault com 500 tags únicas em 5.000 notas tem média de 1 nota para cada 10 tags — as tags não são úteis para filtragem. Consolide para 20-50 tags de alto nível que mapeiam para suas pastas de domínio.
Notas cheias de links e pobres em conteúdo. Notas que consistem inteiramente em wiki-links sem prosa. Essas notas são mal indexadas porque o chunker não tem texto para embedar. Adicione pelo menos um parágrafo de contexto explicando por que as notas vinculadas estão relacionadas.
Links bidirecionais para tudo. Nem toda referência precisa ser um wiki-link. Mencionar “OAuth” de passagem não exige [[OAuth 2.0 Overview]]. Reserve wiki-links para relações intencionais e navegáveis em que clicar no link forneceria contexto útil.
Receitas de fluxo de trabalho para desenvolvedores
Fluxos de trabalho práticos que combinam recuperação do vault com tarefas diárias de desenvolvimento.
Carregamento de contexto pela manhã
Comece o dia carregando o contexto relevante:
Search my vault for notes about [current project] updated in the last week
O retriever retorna notas recentes sobre seu projeto ativo, oferecendo uma rápida recapitulação de onde você parou. Mais eficaz do que reler as mensagens de commit de ontem.
Captura de pesquisa durante o código
Ao implementar um recurso, capture insights sem sair do editor:
/capture "FastAPI dependency injection with async generators requires yield,
not return. The generator is the dependency lifecycle."
--domain programming
--tags fastapi,dependency-injection
O insight capturado é indexado imediatamente e fica disponível para recuperação futura. Ao longo dos meses, essas microcapturas criam um corpus de conhecimento específico de implementação.
Início de projeto
Ao começar um novo projeto ou recurso:
- Pesquise no vault: “O que eu sei sobre [tecnologia/padrão]?”
- Revise os 5 principais resultados em busca de decisões anteriores e gotchas
- Verifique se existe um MOC para o domínio; se não existir, crie um
- Pesquise modos de falha: “problemas com [tecnologia]”
Debugging com pesquisa no vault
Ao encontrar um erro ou comportamento inesperado:
Search my vault for [error message or symptom]
Notas anteriores de debugging muitas vezes contêm a causa raiz e a correção. Isso é especialmente valioso para problemas recorrentes entre projetos — o vault lembra o que você esquece.
Preparação para code review
Antes de revisar um PR:
Search my vault for patterns and conventions about [module being changed]
O vault retorna decisões anteriores, restrições arquiteturais e padrões de código relevantes para o código em revisão. A revisão é informada por conhecimento institucional, não apenas pelo diff.
Ajuste de performance
Esta seção cobre estratégias de otimização para diferentes tamanhos de vault e padrões de uso.
Gerenciamento do tamanho do índice
| Tamanho do vault | Chunks | Tamanho do DB | Reindexação completa | Incremental |
|---|---|---|---|---|
| 500 notas | ~1.500 | 3 MB | 15 segundos | <1 segundo |
| 2.000 notas | ~6.000 | 12 MB | 45 segundos | 2 segundos |
| 5.000 notas | ~15.000 | 30 MB | 2 minutos | 4 segundos |
| 15.000 notas | ~50.000 | 83 MB | 4 minutos | <10 segundos |
| 50.000 notas | ~150.000 | 250 MB | 15 minutos | 30 segundos |
Com 50.000+ notas, considere: - Aumentar o tamanho do lote de 64 para 128 para gerar embeddings mais rápido - Usar o modo WAL (padrão) para acesso concorrente - Executar a reindexação completa fora dos horários de pico
Otimização de consulta
Modo WAL. O modo Write-Ahead Logging do SQLite permite leituras concorrentes enquanto o indexador escreve:
db.execute("PRAGMA journal_mode=WAL")
Isso é essencial quando o servidor MCP lida com consultas enquanto o indexador executa uma atualização incremental.
Pooling de conexões. O servidor MCP deve reutilizar conexões com o banco de dados em vez de abrir uma nova conexão por consulta. Uma única conexão de longa duração com modo WAL oferece suporte a leituras concorrentes.
# MCP server initialization
db = sqlite3.connect(DB_PATH, check_same_thread=False)
db.execute("PRAGMA journal_mode=WAL")
db.execute("PRAGMA mmap_size=268435456") # 256 MB mmap
I/O mapeado em memória. O pragma mmap_size informa ao SQLite para usar I/O mapeado em memória para o arquivo de banco de dados. Para um banco de dados de 83 MB, mapear o arquivo inteiro na memória elimina a maioria das leituras em disco.
Otimização de FTS5. Após uma reindexação completa, execute:
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');
Isso mescla os segmentos internos de b-tree do FTS5, reduzindo a latência de consulta para pesquisas posteriores.
Benchmarks de escala
Medido em Apple M3 Pro, 36 GB de RAM, SSD NVMe:
| Operação | 500 notas | 5K notas | 15K notas | 50K notas |
|---|---|---|---|---|
| Consulta BM25 | 2ms | 5ms | 12ms | 25ms |
| Consulta vetorial | 1ms | 3ms | 8ms | 20ms |
| Fusão RRF | <1ms | <1ms | 3ms | 5ms |
| Pesquisa completa | 3ms | 8ms | 23ms | 50ms |
Todos os benchmarks incluem acesso ao banco de dados, execução da consulta e formatação dos resultados. A latência de rede para comunicação MCP STDIO adiciona 1-2ms.
Solução de problemas
Desvio do índice
Sintoma: A pesquisa retorna resultados desatualizados ou não encontra notas adicionadas recentemente.
Causa: O indexador incremental não foi executado após adicionar notas, ou o mtime de um arquivo não foi atualizado (por exemplo, sincronizado de outra máquina com timestamps preservados).
Correção: Execute uma reindexação completa: python index_vault.py --full
Troca do modelo de embeddings
Sintoma: Depois de alterar o modelo de embeddings, a pesquisa vetorial retorna resultados sem sentido.
Causa: Vetores antigos (do modelo anterior) estão sendo comparados com novos vetores de consulta. As dimensões ou a semântica do espaço vetorial são incompatíveis.
Correção: O indexador deve detectar a incompatibilidade de hash do modelo e acionar automaticamente uma reindexação completa. Se isso não acontecer, limpe manualmente o banco de dados e reindexe:
rm vectors.db
python index_vault.py --full
Manutenção do FTS5
Sintoma: Consultas FTS5 retornam resultados incorretos ou incompletos após muitas atualizações incrementais.
Causa: Segmentos internos do FTS5 podem ficar fragmentados depois de muitas atualizações pequenas.
Correção: Reconstrua e otimize:
INSERT INTO chunks_fts(chunks_fts) VALUES('rebuild');
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');
Timeout do MCP
Sintoma: A ferramenta de AI informa que o servidor MCP atingiu timeout.
Causa: A primeira consulta aciona o carregamento do modelo (inicialização preguiçosa), que leva 2-5 segundos. O timeout padrão de MCP da ferramenta de AI pode ser menor.
Correção: Faça o pré-aquecimento do modelo na inicialização do servidor:
# In MCP server initialization
retriever = HybridRetriever(db_path, vault_path)
retriever.search("warmup", limit=1) # Trigger model load
Locks de arquivo do SQLite
Sintoma: Erros SQLITE_BUSY ou SQLITE_LOCKED.
Causa: Vários processos escrevendo no banco de dados ao mesmo tempo. O modo WAL permite leituras concorrentes, mas apenas um escritor.
Correção: Garanta que apenas um processo (o indexador) escreva no banco de dados. O servidor MCP e os hooks devem apenas ler. Se você precisar de escritas concorrentes, use o modo WAL e defina um timeout de ocupado:
db.execute("PRAGMA busy_timeout=5000") # Wait up to 5 seconds
sqlite-vec não carrega
Sintoma: A pesquisa vetorial está desativada; o retriever roda em modo somente BM25.
Causa: A extensão sqlite-vec não está instalada, não foi encontrada no caminho da biblioteca ou é incompatível com a versão do SQLite.
Correção:
# Install via pip
pip install sqlite-vec
# Or compile from source
git clone https://github.com/asg017/sqlite-vec
cd sqlite-vec && make
Verifique se a extensão carrega:
import sqlite3
db = sqlite3.connect(":memory:")
db.enable_load_extension(True)
db.load_extension("vec0")
print("sqlite-vec loaded successfully")
Problemas de memória em vault grande
Sintoma: Erros de falta de memória durante a reindexação completa de um vault grande (50.000+ notas).
Causa: O tamanho do lote de embeddings é grande demais, ou todo o conteúdo dos arquivos está sendo carregado na memória simultaneamente.
Correção: Reduza o tamanho do lote e processe os arquivos incrementalmente:
BATCH_SIZE = 32 # Reduce from 64
Também garanta que o indexador processe os arquivos um de cada vez (lendo, fazendo chunking e gerando embeddings de cada arquivo antes de passar para o próximo), em vez de carregar todos os arquivos na memória.
Guia de migração
Do Apple Notes
- Exporte o Apple Notes usando a opção “Export All” (macOS) ou use uma ferramenta de migração como
apple-notes-liberator - Converta as exportações HTML para markdown usando
markdownifyoupandoc - Mova os arquivos convertidos para a pasta
00-inbox/do seu vault - Revise e adicione frontmatter a cada nota
- Mova as notas para as pastas de domínio apropriadas
Do Notion
- Exporte do Notion: Settings → Export → Markdown & CSV
- Descompacte a exportação na pasta
00-inbox/do seu vault - Corrija artefatos de markdown específicos do Notion:
- O Notion usa
- [ ]para checklists — isso é markdown padrão - O Notion inclui tabelas de propriedades como HTML — converta para frontmatter YAML
- O Notion incorpora imagens como caminhos relativos — copie as imagens para sua pasta de anexos
- Adicione frontmatter padrão (
type,domain,tags) - Substitua links de páginas do Notion por wiki-links do Obsidian
Do Google Docs
- Use o Google Takeout para exportar todos os documentos
- Converta arquivos
.docxpara markdown:pandoc -f docx -t markdown input.docx -o output.md - Converta em lote:
for f in *.docx; do pandoc -f docx -t markdown "$f" -o "${f%.docx}.md"; done - Mova para o vault, adicione frontmatter e organize em pastas
De markdown puro (sem Obsidian)
Se você já tem um diretório de arquivos markdown:
- Abra o diretório como um vault do Obsidian (Obsidian → Open Vault → Open folder)
- Adicione
.obsidian/ao.gitignorese o diretório tiver controle de versão - Crie templates de frontmatter e aplique aos arquivos existentes
- Comece a conectar notas com
[[wiki-links]]conforme você lê e organiza - Execute o indexador imediatamente — o sistema de recuperação funciona desde o primeiro dia
De outro sistema de recuperação
Se você está migrando de um sistema diferente de embeddings/pesquisa:
- Não tente migrar vetores. Modelos diferentes produzem espaços vetoriais incompatíveis. Execute uma reindexação completa com o novo modelo.
- Migre o conteúdo, não o índice. Os arquivos do vault são a fonte da verdade. O índice é um artefato derivado.
- Verifique após a migração. Execute 10-20 consultas cujas respostas você já conhece e confira se os resultados correspondem às suas expectativas.
Changelog
| Data | Alteração |
|---|---|
| 2026-07-07 | Correções de precisão. MCPVault foi esclarecido como seu próprio projeto (npm @bitbonsai/mcpvault, repo bitbonsai/mcpvault), agora v0.12.1, com dois avisos de filtro de caminho de severidade média (GHSA-9c83-rr99-vfwj, GHSA-j99q-93c9-h869) — o link [^24] anterior apontava para o repo errado (MarkusPfundstein/mcp-obsidian). Status do MarkusPfundstein/mcp-obsidian corrigido: ele é mantido ativamente (commits até 15 de maio de 2026, adicionando search_by_tag/get_frontmatter), não está “dormente desde junho de 2025”; ele ainda não publica releases com tags. Verificado no histórico de commits do GitHub, nos Security Advisories do GitHub e no npm. |
| 2026-07-06 | Reestruturação editorial para facilitar a localização: “Quick Start: First AI-Connected Vault” foi renomeado para Configuração do Obsidian MCP (âncora #obsidian-mcp-setup) e foi adicionado um resumo de capacidades “O que o Claude pode fazer depois de conectado” (buscar, ler, listar, contexto formatado; limite read-only com escritas tratadas por hooks), consolidado da seção de arquitetura do MCP Server. Nenhum fato novo; links internos atualizados. |
| 2026-06-10 | Atualização de versão atual. Obsidian 1.13.1 desktop chegou ao canal público (9 de junho de 2026) — uma atualização de UX de configurações + CodeMirror em relação à 1.13.0, sem grande mudança de AI/automação. Referências à versão atual no corpo foram movidas de 1.13.0 para 1.13.1 (pública, 9 de junho de 2026). |
| 2026-06-09 | Atualização do ecossistema. A especificação MCP 2026-07-28 entrou em Release Candidate (anunciada em 21 de maio de 2026) — a maior revisão do MCP desde o lançamento: núcleo de protocolo stateless (remove o handshake initialize e Mcp-Session-Id), Apps do MCP (HTML renderizado pelo servidor em iframes com sandbox), Tasks saindo do core experimental para uma extensão oficial, reforço de OAuth 2.0/OIDC e uma política de ciclo de vida de depreciação de 12 meses (especificação final em 28 de julho de 2026); substituiu o enquadramento especulativo de roadmap “provisoriamente em meados de 2026” na nota de evolução da especificação MCP pelo RC concreto. sqlite-vec v0.1.10-alpha (31 de março – 18 de maio de 2026) adiciona tipos de índice de vizinho mais próximo aproximado (rescore, ivf experimental, DiskANN baseado em disco) além do KNN por força bruta — marcado como no horizonte/experimental, já que a linha 0.1.10 ainda é pré-release. Obsidian 1.13.0 desktop (early access, 28 de maio de 2026) atualizado como a versão atual nas referências do corpo; é uma release de UX/segurança/ferramentas de desenvolvimento sem novas capacidades de AI/automação. |
| 2026-06-08 | Verificação de manutenção. Model2Vec v0.8.2 (29 de maio de 2026) lançado: uma release de manutenção que adiciona uma opção de pesos congelados para treinamento, além de correções de tokens multiword, uma refatoração de treinamento e correções no tratamento de pesos não quantizados; nota de rodapé atualizada. Nada mais recente que a baseline existente: a versão mais recente do Obsidian continua sendo 1.13.0 (28 de maio, já documentada abaixo), a versão estável do sqlite-vec continua sendo v0.1.9 (v0.1.10 ainda alpha), e a especificação MCP continua sendo a revisão de 2025-11-25. Nenhuma alteração no corpo além da nota de versão do Model2Vec. |
| 2026-05-28 | Obsidian 1.13.0 desktop + 1.13.0 mobile (Catalyst early-access) lançados. Desktop: painel de Settings reformulado, que abre em sua própria janela com busca integrada e navegação por teclado; Obsidian URIs agora exibem uma caixa de confirmação antes de disparar ações; novo aviso antes de carregar recursos HTML de unidades de rede; Search adicionado à visualização Bookmarks; tratamento de imagens no editor aprimorado; melhorias em File Explorer / Properties / Sync; vários recursos para desenvolvedores API e correções de bugs. Mobile: nova iOS Share Sheet com locais de destino configuráveis; reordenação de abas pelo alternador de abas; gestos de pressionar e segurar em tablets para redimensionar divisões e barras laterais fixadas; Bases ganha um item de menu para redimensionar colunas em visualizações de tabela; correções de bugs no iOS e na busca. Implicações para workflows de AI: a caixa de confirmação em Obsidian URIs adiciona uma barreira deliberada a integrações MCP/agente acionadas por URI; o menu de redimensionamento de colunas do Bases torna o Bases mais útil como índice frontal do vault que agentes consultam; o destino configurável da iOS Share Sheet torna o caminho de captura no iPhone (já documentado como entrada principal) mais rápido de conectar a pipelines Claude/Codex. |
| 2026-05-06 | Atualização de atualidade verificada por fontes: Smart Connections v4.5.0 moveu conexões de rodapé para Core; releases estáveis sqlite-vec v0.1.8/v0.1.9 atualizaram empacotamento e comportamento de DELETE; Model2Vec v0.8.x atualizou componentes internos de tokenizer/persistência e tabelas de benchmark; corrigida a cronologia do Obsidian CLI de “1.12.7 introduziu CLI” para “1.12.0 introduziu CLI, 1.12.7 melhorou o empacotamento de instalação/runtime.” |
| 2026-04-27 | Ciclo de abril do Web Clipper: 1.4.0 (UI interativa de transcrição do YouTube + Open in Reader como padrão), 1.5.0 (visualizador Highlights), 1.6.0 (reformulação da UX do Highlighter + extratores de fonte Defuddle 0.18 para LinkedIn/Threads/Bluesky/Discourse/Medium), 1.6.1 + 1.6.2 (correções no Reader e Safari). Reenquadra o Web Clipper como o principal caminho de entrada no navegador para workflows de AI, em vez de uma menção passageira a bookmark. Nenhuma release de Obsidian desktop, Sync ou Bases no período. |
| 2026-04-16 | Smart Connections v4.3.0 (visualização de grafo, dock configurável, recuperação de block-embedding, env Substrate entre plugins). Documentada a onda de plugins AI-native de abril de 2026 (Cortex, VaultSearch, LLM Wiki, Drift, EngramQuest, Hybrid Search MCP). Marcado MarkusPfundstein/mcp-obsidian como modo de manutenção (último commit em junho de 2025). Dataview dormente; Bases é o sucessor para trabalhos novos. Obsidian CLI 1.12.7 continua sendo a ponte preferida para assistentes de AI. |
| 2026-04-01 | Adicionada seção Obsidian CLI (comandos v1.12 para workflows de AI). Adicionada seção de plugin de agente (Claudian, Agent Client). Documentado o plugin core Bases para organização de vault. Contagem de plugins atualizada para 2.500+. Adicionada iOS Share Extension como fonte de entrada. Matriz de compatibilidade atualizada com plugins de agente incorporados. |
| 2026-03-30 | MCPVault v0.11.0: ferramenta list_all_tags, suporte a .base/.canvas, renomeado para @bitbonsai/mcpvault. Obsidian Desktop v1.12.7 inclui o binário CLI para interações mais rápidas no terminal. |
| 2026-03-23 | Documentado sqlite-vec v0.1.7 estável: suporte a DELETE para tabelas vec0, restrições de distância KNN para paginação. Índice DiskANN de vizinho mais próximo aproximado anunciado para release futura. |
| 2026-03-07 | Adicionado potion-multilingual-128M (101 idiomas, maio de 2025) à comparação de modelos de embedding. sqlite-vec em v0.1.7-alpha.10 (correções de CI/CD, sem mudanças de recursos). Especificação MCP e técnicas de retrieval confirmadas como atuais. |
| 2026-03-03 | Atualizada a evolução da especificação MCP (novembro de 2025 lançado: Streamable HTTP, .well-known, anotações de ferramentas). Adicionados fine-tuning do Model2Vec e suporte a tokenizer BPE/Unigram. Adicionada tabela de comparação de servers MCP da comunidade. Smart Connections atualizado para v4. |
| 2026-03-02 | Adicionados potion-base-32M e potion-retrieval-32M à comparação de modelos. Adicionada seção de quantização/redução de dimensionalidade. Adicionada nota de evolução da especificação MCP. |
| 2026-03-01 | Lançamento inicial |
Referências
-
Internet Vin, “22 commands I use with Obsidian and Claude Code,” março de 2026, x.com/internetvin/status/2026461256677245131. ↩
-
Nicopreme, skill de agente “Visual Explainer” com comandos slash, x.com/nicopreme/status/2023495040258261460. ↩
-
Cormack, G.V., Clarke, C.L.A. e Buettcher, S. Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods. SIGIR, 2009. Apresenta RRF com k=60 como um método sem parâmetros para combinar listas ranqueadas. ↩↩↩
-
OpenAI Embeddings Pricing. text-embedding-3-small: US$ 0,02 por milhão de tokens. Custo estimado do vault por reindexação completa: ~US$ 0,30. ↩
-
van Dongen, T. et al. Model2Vec: Turn any Sentence Transformer into a Small Fast Model. arXiv, 2025. Descreve a abordagem de destilação que produz embeddings estáticos a partir de sentence transformers. ↩
-
potion-base-8M Model Card e Model2Vec results. As tabelas publicadas atuais reportam potion-base-8M com 51,32 Avg (All) / 51,08 Avg (MTEB), em comparação com all-MiniLM-L6-v2 com 55,80 Avg (All) / 55,93 Avg (MTEB), ou cerca de 92% de retenção na pontuação de todas as tarefas. ↩
-
Model Context Protocol Specification. O padrão MCP para conectar ferramentas de AI a fontes de dados. ↩
-
Model2Vec Potion Models, potion-base-32M e potion-retrieval-32M. Os model cards atuais reportam potion-base-32M com 52,83 Avg (All) e potion-retrieval-32M com 35,06 na tabela de retrieval. ↩↩↩
-
Update on the Next MCP Protocol Release. A versão de novembro de 2025 trouxe transporte Streamable HTTP, descoberta de URLs .well-known, anotações estruturadas de ferramentas e padronização de tiers SDK. Próxima versão prevista provisoriamente para meados de 2026, com operações assíncronas, extensões específicas de domínio e comunicação agente-para-agente. ↩
-
Model2Vec Releases. v0.4.0 (fev. 2025): suporte a treinamento/fine-tuning. v0.5.0 (abr. 2025): reescrita do backend, quantização, redução de dimensionalidade. v0.7.0 (out. 2025): quantização de vocabulário, suporte ao tokenizer BPE/Unigram. v0.8.0/v0.8.1 (mar. 2026): refatorações de tokenizer e persistência, descontinuação do Python 3.9, atualizações de resultados MTEB V2 e compatibilidade com caminhos do Windows. v0.8.2 (29 de maio de 2026): uma versão de manutenção que adiciona uma opção de pesos congelados para treinamento, além de correções em tokens de múltiplas palavras, uma refatoração de treinamento e correções no tratamento de pesos não quantizados. ↩↩
-
Smart Connections for Obsidian. Smart Connections v4: embeddings de AI local-first, busca semântica funciona offline após a indexação inicial. ↩
-
potion-multilingual-128M. Minish Lab, maio de 2025. Modelo de embedding estático em 101 idiomas, os embeddings estáticos multilíngues com melhor desempenho. Mesma dependência apenas de numpy dos outros modelos potion. ↩
-
MCPVault —
bitbonsai/mcpvault. npm@bitbonsai/mcpvault, versão mais recente v0.12.1 (publicada em 2026-06-23); um projeto distinto deMarkusPfundstein/mcp-obsidian, não uma renomeação dele. A v0.11.0 (março de 2026) adicionou a ferramentalist_all_tagspara escanear frontmatter e hashtags com contagens, melhorou o tratamento de pastas com pontos e adicionou suporte a arquivos.base/.canvas. Dois GitHub Security Advisories de severidade média afetam seu filtro de caminhos: GHSA-9c83-rr99-vfwj (diretórios restritos negados apenas na raiz do vault, não quando aninhados) e GHSA-j99q-93c9-h869 (bypass de deny-list por equivalência de maiúsculas/minúsculas e ponto/espaço final) — use v0.12.1 ou posterior. ↩ -
sqlite-vec v0.1.7 Release. 17 de março de 2026. Versão estável: suporte a DELETE para tabelas virtuais vec0, restrições de distância KNN para paginação, melhorias em testes fuzz. Indexação DiskANN de vizinho mais próximo aproximado anunciada para uma versão futura. ↩↩↩
-
Introduction to Bases. Plugin core do Obsidian introduzido na v1.9.10. Visualizações no estilo banco de dados (tabelas, galerias, calendários, quadros kanban) sobre arquivos do vault usando propriedades de frontmatter como campos. Arquivos salvos no formato
.base. ↩ -
Obsidian Desktop v1.12.0 Changelog e Obsidian Desktop v1.12.7 Changelog. A v1.12.0 introduziu o CLI para automação de vault via terminal; a v1.12.7 melhorou o empacotamento de instalação/runtime com um binário independente, TUI e comportamento de arquivo de socket. Veja também a documentação do CLI. ↩↩
-
Claudian. Plugin do Obsidian que incorpora Claude Code como colaborador de AI no vault. Oferece chat na barra lateral, prompts sensíveis ao contexto, suporte a visão, comandos slash e modos de permissão. ↩
-
Agent Client. Plugin do Obsidian que fornece uma interface unificada para Claude Code, Codex CLI e Gemini CLI via Agent Client Protocol (ACP). Suporta menções a notas, execução de shell e aprovação de ações. ↩
-
Obsidian iOS Changelog. Atualizações do início de 2026 incluem Share Extension para salvar conteúdo de outros apps diretamente no vault, correções nos widgets Daily Note e Bookmark, e melhorias na atualização do widget View Note. ↩
-
MarkusPfundstein/mcp-obsidian. Mantido ativamente — commits até 15 de maio de 2026, com trabalho recente adicionando ferramentas incluindo
search_by_tageget_frontmatter, além de cobertura de testes ampliada (verificado no histórico de commits do repositório e emtools.py). Ainda não distribui releases com tags, então instale a partir de um commit fixado. Baseado em Local-REST-API; discussões no fórum (abril de 2026) relatam migração da comunidade para a ponte Obsidian CLI de primeira classe (1.12.x) em novas configurações, mas mcp-obsidian continua sendo uma opção funcional e atualizada para implantações REST-API existentes. ↩↩ -
Smart Connections v4.5.0 Release. 5 de maio de 2026. Conexões no rodapé se tornaram um recurso Core; versões v4 recentes também incluem visualizações em grafo para listas de conexões, locais configuráveis para o painel de conexões, recuperação melhorada de block-embedding, estado cross-plugin Substrate, correções de fallback de transformer e redução de cálculos duplicados de conexões. ↩
-
obsidianmd/obsidian-clipper releases — fonte primária para o mapeamento versão-recurso do Web Clipper. Ciclo de abril de 2026: 1.4.0 (9 de abr., UI de transcrição do YouTube + Open in Reader como padrão), 1.5.0 (15 de abr., visualizador de Highlights + fade-in do Reader), 1.5.1 (15 de abr., correção de compilação webpack), 1.6.0 (21 de abr., UX do Highlighter + Defuddle 0.18 com extratores LinkedIn/Threads/Bluesky/Discourse/Medium), 1.6.1 (22 de abr., correções no outline do Reader + busca em highlights), 1.6.2 (23 de abr., correção de clipboard no modo incorporado do Safari). Também listado na Mozilla Add-ons store e na Chrome Web Store. ↩
-
sqlite-vec v0.1.8, sqlite-vec v0.1.9, sqlite-vec v0.1.10-alpha.3 e sqlite-vec v0.1.10-alpha.4. A v0.1.8 corrigiu o empacotamento npm; a v0.1.9 corrigiu um bug de DELETE em colunas de texto de metadados com mais de 12 caracteres; a v0.1.10-alpha.3 adiciona suporte correto a
INSERT OR REPLACE INTO; a v0.1.10-alpha.4 (18 de maio de 2026) corrige falha deALTER TABLE RENAMEem tabelasvec0usando os novos recursos ivf/diskann e um bug de limpeza de instrução em cache no DiskANN. A linha 0.1.10 ainda está em prerelease. ↩↩↩↩ -
MCP 2026-07-28 Specification Release Candidate. Anunciado em 21 de maio de 2026; a especificação final sai em 28 de julho de 2026. Maior revisão do MCP desde o lançamento: núcleo de protocolo stateless (remove o handshake
initializee o cabeçalhoMcp-Session-Id), Apps MCP (HTML renderizado pelo servidor em iframes de cliente em sandbox), Tasks saindo do core experimental para uma extensão oficial (tasks/get,tasks/update,tasks/cancel), fortalecimento de autorização OAuth 2.0 / OIDC e uma política de ciclo de vida de 12 meses para descontinuação de recursos. ↩ -
Obsidian Desktop v1.13.0 Changelog. Early access, 28 de maio de 2026. Versão de UX/segurança/ferramentas para desenvolvedores: painel Settings reformulado que abre em sua própria janela com busca e navegação por teclado, diálogos de confirmação antes de URIs do Obsidian serem acionadas, um novo API de Settings para desenvolvedores de plugins e uma correção de CLI para instalações flatpak. Nenhuma nova capacidade importante de AI/automação além da superfície CLI da linha 1.12.x. ↩↩
-
Obsidian Changelog. Obsidian 1.13.1 desktop chegou ao canal público em 9 de junho de 2026 — um refinamento de UX de configurações e upgrade do CodeMirror em relação à 1.13.0, sem nova capacidade de AI/automação. ↩↩