Obsidian MCP + recuperação híbrida: referência de 2026
# Use a documentação oficial do Obsidian para noções básicas do app; use a referência do Blake para MCP, busca híbrida e indexação de um cofre de IA com 16.894 arquivos.
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 aprendizados
Engenharia de contexto, não criação de notas. O valor de um cofre do Obsidian para IA não está nas notas em si, mas na camada de recuperação que permite consultá-las. Um cofre com 16.000 arquivos sem recuperação é um banco de dados somente de escrita. Um cofre com 200 arquivos, busca hybrid e integração com MCP é uma base de conhecimento de IA. A infraestrutura de recuperação é o produto. As notas são a matéria-prima.
A recuperação hybrid supera a busca puramente por palavras-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 ranqueamento de passagens no MS MARCO confirmam o padrão: a recuperação híbrida supera consistentemente qualquer um dos métodos isoladamente.3 O aprofundamento sobre o recuperador híbrido cobre a matemática do RRF, exemplos resolvidos com números reais, análise de modos de falha e uma calculadora interativa de fusão.
MCP dá às ferramentas de IA acesso direto ao cofre. Servidores Model Context Protocol (MCP) expõem o recuperador como uma ferramenta que Claude Code, Codex CLI, Cursor e outras ferramentas de IA podem chamar diretamente. O agente consulta o cofre, recebe resultados ranqueados com atribuição de fonte e usa o contexto sem carregar arquivos inteiros. O servidor MCP é uma camada fina em torno do mecanismo de recuperação.
Local-first significa custo zero de API e privacidade total. A stack inteira roda em uma única máquina: SQLite para armazenamento, Model2Vec para embeddings, FTS5 para busca por palavras-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 nos 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 alterações. Só arquivos modificados passam novamente por chunking e re-embedding. Uma reindexação completa 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 de três camadas (entrada, recuperação, integração) funciona em qualquer tamanho de cofre. Comece com busca apenas por BM25 em um cofre pequeno. Adicione busca vetorial quando colisões de palavras-chave virarem um problema. Adicione fusão RRF quando você precisar de correspondências exatas e semânticas. Cada camada é útil por conta própria e pode ser removida independentemente.
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 |
|---|---|---|
| Novo em Obsidian + IA | Por que Obsidian para infraestrutura de IA, Início rápido | Arquitetura do cofre, Arquitetura do servidor MCP |
| Já tem um cofre e quer acesso por IA | Arquitetura do servidor MCP, Integração com Claude Code | Modelos de embedding, Busca de texto completo |
| Construindo um sistema de recuperação | O pipeline completo de recuperação, Reciprocal Rank Fusion | Ajuste de performance, Solução de problemas |
| Em contexto de equipe ou empresa | Framework de decisão, Padrões de grafo de conhecimento | 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 em conceitos, decisões de arquitetura e no 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 IA
A tese deste guia: cofres do Obsidian são o melhor substrato para bases de conhecimento pessoais de IA porque são local-first, em plaintext, estruturados como grafo, e o usuário controla todas as camadas da stack.
O que Obsidian oferece à IA que as alternativas não oferecem
Arquivos markdown em plaintext. Toda nota é um arquivo .md no seu sistema de arquivos. Sem formato proprietário, sem exportação de banco de dados, sem API necessária para ler o conteúdo. Qualquer ferramenta que lê arquivos pode ler seu cofre. grep, ripgrep, pathlib do Python, SQLite FTS5 — todas funcionam diretamente nos arquivos de origem. Quando você constrói um sistema de recuperação, você indexa arquivos, não respostas de API. O índice está sempre consistente com a fonte porque a fonte é o sistema de arquivos.
Arquitetura local-first. O cofre fica na sua máquina. Sem servidor, sem dependência de sync em nuvem, sem limites de taxa de API, sem termos de serviço governando como você processa seu próprio conteúdo. Você pode gerar embeddings, indexar, fazer chunking e buscar suas notas sem nenhum serviço externo. Isso importa para infraestrutura de IA porque o pipeline de recuperação roda tão rápido quanto o 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 wiki-links. A sintaxe [[wiki-link]] do Obsidian cria um grafo direcionado entre notas. Uma nota sobre implementação de OAuth se conecta a 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. Obsidian tem mais de 2.500 plugins da comunidade (em março de 2026, acima dos mais de 1.800 em meados de 2025). Dataview consulta seu cofre como um banco de dados. Templater gera notas a partir de templates com lógica de JavaScript. A integração com Git sincroniza seu cofre com um repositório. Linter aplica 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 cofre usando propriedades de frontmatter como campos, salvos como arquivos .base.15 Esses plugins adicionam estrutura ao cofre sem alterar o formato plaintext subjacente. O sistema de recuperação indexa a saída desses plugins, não os plugins em si.
Mais de 5 milhões de usuários. Obsidian tem uma grande comunidade ativa produzindo templates, workflows, plugins e documentação. Quando você encontra um problema de organização do cofre ou configuração de plugin, é provável que alguém já tenha documentado 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 apenas um sistema de arquivos não oferece
Um diretório de arquivos markdown tem a vantagem do plaintext, mas não tem três coisas que o Obsidian adiciona:
-
Links bidirecionais. 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ão. Essa consciência bidirecional é metadata que um sistema de arquivos bruto não fornece.
-
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 que a de um editor de texto, enquanto o formato de armazenamento continua sendo plaintext. Você escreve e organiza em um ambiente rico; o sistema de recuperação 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 standalone, mas o Obsidian os empacota em um workflow coerente.
O que Obsidian NÃO faz (e o que você constrói)
Obsidian não inclui infraestrutura de recuperação. Ele tem busca básica (texto completo, nome de arquivo, tag), mas não tem pipeline de embedding, busca vetorial, ranqueamento por fusão, servidor MCP, filtragem de credenciais, estratégia de chunking nem hooks de integração para ferramentas externas de IA. Este guia cobre a infraestrutura que você constrói em cima do Obsidian. O cofre é o substrato. O pipeline de recuperação, 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 recuperação funciona da mesma forma. O chunker lê arquivos .md. O embedder processa strings de texto. O indexador 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 recuperador indexa.
Início rápido: primeiro cofre conectado à IA
Esta seção conecta um cofre a uma ferramenta de IA 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 gerar resultados imediatos. As seções posteriores cobrem como criar 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; versões anteriores funcionam para configurações que usam apenas 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 que você vá lembrar — o servidor MCP precisa do caminho absoluto.
# Example vault location
~/Documents/knowledge-base/
Adicione algumas notas para dar ao recuperador 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. Atualizações recentes de destaque incluem o MCPVault v0.11.0 (março de 2026), que adicionou list_all_tags para verificar frontmatter e hashtags com contagens, melhorou o tratamento de pastas com pontos no nome e adicionou suporte a arquivos .base e .canvas.13 O pacote também foi renomeado para @bitbonsai/mcpvault no npm.
Mudança de abril de 2026 — Obsidian CLI como ponte preferencial: o Obsidian 1.12.0 introduziu o CLI nativo, e o instalador público da versão 1.12.7 (23 de março de 2026) incluiu o binário independente + TUI + melhorias no arquivo de socket que facilitaram a instalação e execução de fluxos de trabalho no terminal.16 As ferramentas da comunidade estão migrando ativamente do plugin Local REST API (que alimentava o
mcp-obsidian) para a integração baseada em CLI, porque ela é mais rápida e mais estável. O repositórioMarkusPfundstein/mcp-obsidianestá sem commits desde junho de 2025 e nunca teve releases com tag — trate-o como em modo de manutenção e prefira servidores baseados em CLI ou as alternativas mais novas da comunidade listadas abaixo.20 Consulte a seção “Obsidian CLI para fluxos de trabalho de IA” mais adiante neste guia para ver a configuração recomendada.
| Servidor | Autor | Transporte | Requer plugin | Principal recurso |
|---|---|---|---|---|
| obsidian-mcp-server | StevenStavrakis | STDIO | Não | Leve, baseado em arquivos |
| mcp-obsidian | MarkusPfundstein | STDIO | Local REST API | CRUD completo do cofre via REST — modo de manutenção, sem commits desde junho de 202520 |
| 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 | Gerenciamento de tags e 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 IA
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 IA 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 IA chama o servidor MCP, que pesquisa seu cofre e retorna o conteúdo correspondente. Você deve ver resultados com caminhos de arquivo e trechos relevantes.
O que você acabou de criar
Você conectou uma base de conhecimento local a uma ferramenta de IA por meio de um protocolo padrão. O servidor MCP lê os arquivos do seu cofre, executa uma 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 hybrid (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 cobre 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 fluxos de trabalho de IA
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 fluxos de trabalho de IA.16 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-o em Settings > General > Command line interface.
Por que o CLI importa para 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 fluxos de trabalho de IA, as principais capacidades são:
- Busca a partir de scripts e hooks.
obsidian search "query"eobsidian search:context "query"executam buscas no cofre a partir de qualquer script shell, hook ou pipeline de automação. A variantesearch:contextretorna as linhas correspondentes com o contexto ao redor, útil para alimentar prompts de IA com resultados. - Automação de notas diárias.
obsidian dailyabre ou cria a nota diária de hoje. Combinado com shell scripting, isso permite fluxos de trabalho automatizados de briefing diário — um hook pode acrescentar 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 agentes de IA criem entradas estruturadas no cofre sem escrever arquivos markdown diretamente. - Gerenciamento de propriedades.
obsidian property seteobsidian property getleem e gravam 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 ativar ou desativar plugins de indexação durante operações em lote. - Gerenciamento de tarefas.
obsidian task list/add/completeoferece acesso estruturado a tarefas, útil para agentes de IA que gerenciam itens de trabalho no cofre.
CLI vs MCP para acesso por IA
O CLI e os servidores MCP cumprem papéis diferentes e são complementares, não concorrentes:
| Aspecto | Obsidian CLI | Servidor MCP |
|---|---|---|
| Chamador | Scripts shell, hooks, cron jobs | Agentes de IA (Claude Code, Codex, Cursor) |
| Protocolo | Processo POSIX (stdin/stdout/stderr) | MCP (JSON-RPC sobre STDIO ou HTTP) |
| Força | 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 entrada, ações de hooks | Consultas em tempo real de agentes de IA durante sessões |
Recomendação: use o CLI para automação de entrada (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 recuperador MCP completo para resultados ranqueados.
Exemplo: hook de entrada alimentado por 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 agente do Obsidian
Uma categoria crescente de plugins do Obsidian incorpora agentes de codificação de IA diretamente na UI do vault, oferecendo uma alternativa à configuração externa de servidor MCP. Esses plugins executam o agente de IA na barra lateral do Obsidian, em vez de conectar a partir de uma ferramenta externa.
Claudian
Claudian incorpora Claude Code como colaborador de IA no vault. O diretório do vault se torna o diretório de trabalho do Claude, dando a ele capacidades agentivas completas: leitura/gravação de arquivos, busca, comandos bash e workflows de várias etapas.17
Principais recursos para infraestrutura de IA:
- Prompts cientes do contexto. Anexa automaticamente a nota em foco, oferece suporte a menções de arquivo com @notename, exclusão baseada em tags e seleção do editor como contexto.
- Suporte a visão. Analisa imagens por arrastar e soltar, colar ou caminho de arquivo — útil para processar screenshots e diagramas capturados no vault.
- Comandos slash. Crie templates de prompt reutilizáveis acionados por /command, permitindo operações padronizadas no vault.
- 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 vault.
Agent Client
Agent Client traz Claude Code, Codex CLI e Gemini CLI para uma barra lateral unificada do Obsidian por meio do Agent Client Protocol (ACP).18
Principais recursos:
- Alternância entre vários agentes. Converse com Claude Code, Codex ou Gemini CLI no mesmo painel, alternando entre agentes conforme necessário.
- Menções a notas. Use @notename para incluir o conteúdo de notas nos prompts, de forma semelhante ao Claudian, mas sem depender de um agente específico.
- Execução no shell. Execute comandos de terminal inline no chat — scripts de build, 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 agente vs MCP externo
| Cenário | Plugin de agente | MCP externo |
|---|---|---|
| Escrever e editar notas do vault 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 vault | Melhor — restrito ao projeto, com filesystem completo |
| Recuperação de um corpus grande indexado | Apenas busca básica | Pipeline completo de recuperação hybrid |
| Perguntas rápidas sobre o vault durante sessões de anotação | Ideal — sem troca de contexto | Exige alternar para o terminal |
Recomendação: use plugins de agente para workflows centrados no vault (escrever, organizar e resumir notas). Use servidores MCP externos para workflows de desenvolvimento em que o agente de IA precisa do pipeline completo de recuperação e acesso a bases de código fora do vault. As duas abordagens podem coexistir — execute o Claudian dentro do Obsidian para trabalho com notas e Claude Code com MCP externamente para desenvolvimento.
Framework de decisão: Obsidian vs alternativas
Nem todo caso de uso precisa do Obsidian. Esta seção mapeia quando o Obsidian é a base certa, quando é excesso 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 | Filesystem simples | CLAUDE.md |
|---|---|---|---|---|---|
| Local-first | Sim | Não (cloud) | Parcial (iCloud) | Sim | Sim |
| Plaintext | Sim (markdown) | Não (blocos) | Não (proprietário) | Sim | Sim |
| Estrutura em grafo | Sim (wiki-links) | Parcial (menções) | Não | Não | Não |
| Indexável por IA | Acesso direto aos arquivos | API necessário | Exportação necessária | Acesso direto aos arquivos | Já está no contexto |
| Ecossistema de plugins | Mais de 2.500 plugins | Integrações | Nenhum | N/A | N/A |
| Funciona offline | Total | Cache somente leitura | Parcial | Total | Total |
| Escala para mais de 10 mil notas | Sim | Sim (com API) | Degrada | Sim | Não (arquivo único) |
| Custo | Gratuito (core) | US$ 10/mês+ | Gratuito | Gratuito | Gratuito |
Quando Obsidian é excesso
- Contexto de um único projeto. Se a IA só precisa de contexto sobre a base de código atual, coloque isso em
CLAUDE.md,AGENTS.mdou documentação no nível do projeto. Esses arquivos acompanham o repo e são carregados automaticamente. - Dados estruturados. Se o conteúdo está em tabelas, registros ou schemas, use um banco de dados. As notas do Obsidian priorizam prosa. O 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 terminar, uma pasta de rascunho com arquivos markdown é mais simples. Não construa infraestrutura de recuperação 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 vez.
- Vários domínios em um único corpus. Um vault contendo notas sobre programação, arquitetura, segurança, design e projetos pessoais se beneficia de recuperação entre domínios, algo que um
CLAUDE.mdespecífico de projeto não consegue oferecer. - Conteúdo sensível à privacidade. Local-first significa que o pipeline de recuperação 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 em 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 │
└─────────────────────────────────────────────────────┘
Entrada determina o que entra no vault. Sem curadoria, o vault acumula ruído: screenshots de tweets, artigos copiados e colados sem anotação, pensamentos pela metade sem contexto. A camada de entrada é 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 valha a pena recuperar.
Recuperação torna o vault consultável. Este é o motor: chunking de notas em unidades de busca, embedding de chunks em espaço vetorial, indexação para busca por palavra-chave e busca semântica, fusão de resultados com RRF. A camada de recuperação transforma uma pasta de arquivos em uma base de conhecimento consultável. Sem essa camada, o vault pode ser navegado por browsing manual e busca básica, mas não fica programaticamente acessível para ferramentas de IA.
Integração conecta a camada de recuperação às ferramentas de IA. Um servidor MCP expõe a recuperação 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 base de conhecimento e os agentes de IA que a consomem.
As camadas são desacopladas por design. O pipeline de pontuação da entrada não sabe nada sobre embeddings. O mecanismo de recuperação 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 significa que você pode melhorar qualquer camada de forma independente. Troque o modelo de embedding sem alterar o pipeline de entrada. Adicione uma nova capacidade MCP sem modificar o mecanismo de recuperação. Mude as heurísticas de pontuação de sinais sem tocar no índice.
Arquitetura do cofre para consumo por IA
Um cofre otimizado para recuperação por IA segue convenções diferentes de um cofre otimizado para navegação pessoal. Esta seção aborda a estrutura de pastas, o esquema 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 a fim de 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 examinar.
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 contenha 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 que contenha conteúdo sensível que você não quer no índice de recuperação.
O arquivo .indexignore
Crie um arquivo .indexignore na raiz do cofre para excluir explicitamente caminhos do índice de recuperação. A sintaxe segue a 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 da varredura e ignora totalmente os caminhos correspondentes. Arquivos em caminhos excluídos nunca são divididos em chunks, nunca recebem embeddings e nunca aparecem nos resultados de busca.
Esquema 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 cabeçalhos para BM25type— Permite consultas filtradas por tipo (“mostrar apenas MOCs” ou “apenas sinais”)tags— Indexado no contexto de cabeçalhos do FTS5 com peso 0,3, fornecendo correspondências por palavra-chave mesmo quando o corpo usa terminologia diferente
Campos opcionais, mas valiosos:
domain— Permite consultas limitadas por domínio (“buscar 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 cabeçalhos H2 (##). Isso significa que a estrutura da sua nota 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 o embedding capturar seu significado. Uma consulta sobre “tratamento de token expirado” 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 cabeçalhos H2 produz um único chunk grande. O embedding faz uma média de 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:
- Colagens brutas de artigos inteiros sem anotação. O recuperador indexa as palavras-chave do artigo original, diluindo seu cofre 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.
- Capturas de tela sem descrição em texto. O recuperador indexa texto em markdown. Uma imagem sem texto alternativo 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 segredos nas notas. Em vez disso, referencie-os pelo nome (“o token API Cloudflare 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 cofre permanente. Importações automáticas sem curadoria adicionam volume sem adicionar valor recuperável.
Ecossistema de plugins para workflows de IA
Os plugins do Obsidian que melhoram a qualidade do vault para recuperação por IA se dividem em três categorias: estruturais (impõem consistência), consulta (expõem metadados) e sincronização (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 na 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 consistente de títulos (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 a recuperação:
- Incremento de títulos: impor níveis sequenciais de título (sem pular de H1 para H3)
- Título YAML: corresponder ao nome do arquivo
- Espaços no fim da linha: remover (evita artefatos de tokenização do FTS5)
- Linhas em branco consecutivas: limitar a 1 (chunks mais limpos)
Integração com Git. Controle de versão para o seu vault. Acompanhe mudanças ao longo do tempo, sincronize entre máquinas e recupere notas excluídas por acidente. O Git também fornece dados de mtime que o indexador usa para detecção incremental de mudanças.
Plugins que ajudam na indexação
Smart Connections. Um plugin do Obsidian que oferece busca semântica com IA 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 consulta funcionam totalmente offline, sem chamadas API.11 v4.5.0 (5 de maio de 2026) torna as conexões no rodapé parte do Smart Connections Core, para que toda instalação possa mostrar conexões com notas relacionadas no rodapé sem abrir um painel lateral. Versões v4 recentes também adicionaram visualizações em grafo para listas de conexões, locais configuráveis para dock, melhor recuperação de embeddings de bloco após execuções de indexação interrompidas e “Substrate”, um ambiente cross-plugin 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 IA 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 movido 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 | Transforma seu vault em uma knowledge base consultável de forma privada |
| Drift | 11 de abril | Visualizador de diff no estilo VS Code para edição do Obsidian com IA; posicionado para workflows Claude Code |
| EngramQuest | 11 de abril | Gera desafios de memória a partir das notas; vem com “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 IA |
Trate isso como uma área emergente — vários desses plugins provavelmente vão se consolidar ou ser 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 da filosofia do recuperador externo deste guia.
Nota sobre Dataview: Dataview (o antigo plugin de consultas do Obsidian) lançou a versão 0.5.70 em abril de 2025 e está, na prática, parado desde então. Para trabalho novo, 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 na recuperação.
Plugins que prejudicam a indexação
Excalidraw. Armazena desenhos como JSON incorporado em arquivos markdown. O JSON é markdown sintaticamente válido, mas gera lixo quando é dividido em chunks e transformado em embeddings. Exclua arquivos do Excalidraw do índice via .indexignore ou filtre por extensão de arquivo.
Kanban. Armazena o estado do quadro como markdown formatado de modo especial. O formato foi criado para renderização de Kanban, não para recuperação de texto corrido. O chunker produz fragmentos de títulos de cards e metadados que não geram bons embeddings. Exclua quadros Kanban do índice.
Calendar. Cria notas diárias com conteúdo mínimo (muitas vezes apenas um cabeçalho com a 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
Recuperação de arquivos → Ativada. Protege contra exclusão acidental de notas. Não está diretamente relacionada à recuperação, mas é crítica para uma knowledge base da qual você depende.
Quebras de linha estritas → Desativadas. Quebras de linha padrão do Markdown (dupla quebra de linha para parágrafo) produzem chunks mais limpos do que o modo estrito do Obsidian (quebra de linha simples para <br>).
Local padrão de novos arquivos → Pasta designada. Direcione novos arquivos para 00-inbox/ para que notas não categorizadas não poluam pastas de domínio. A caixa de entrada é uma área de preparação; os arquivos vão para pastas de domínio depois da triagem.
Formato de wiki-link → Caminho mais curto quando possível. 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 embedding 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 embedding e as dependências em tempo de execução. Esta seção explica por que o potion-base-8M do Model2Vec é a escolha padrão e quando escolher alternativas.
Por que usar Model2Vec potion-base-8M
Modelo: minishlab/potion-base-8M
Parâmetros: 7,6 milhões
Dimensões: 256
Tamanho: ~30 MB
Dependências: model2vec (apenas numpy, sem PyTorch)
Inferência: somente CPU, embeddings estáticos de palavras (sem camadas de atenção)
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 fazem BERT, MiniLM e outros modelos transformer), o 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 embedding é 50-500x maior que a de modelos baseados em transformer, porque não há computação sequencial.
Na página atual de resultados do Model2Vec, o potion-base-8M alcança cerca de 92% da pontuação geral em todas as tarefas do all-MiniLM-L6-v2 (51,32 vs 55,80), permanecendo ordens de magnitude mais rápido.6 A diferença de qualidade restante é o trade-off pelas vantagens de velocidade e simplicidade. Para chunks curtos de markdown (média de 200-400 palavras em um vault típico), a diferença de qualidade é menos pronunciada do que em documentos mais longos, porque ambos os 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 custa nada quando o retriever opera em modo de fallback somente BM25 (por exemplo, quando a venv de embedding 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 tempo de execução.
# Create isolated venv
python3 -m venv ~/.claude/venvs/memory
~/.claude/venvs/memory/bin/pip install model2vec
Processamento em batch. O embedder processa textos em batches de 64 para amortizar o overhead do Model2Vec. O indexer envia chunks para embed_batch() em vez de gerar embedding de um chunk por vez.
Quando escolher alternativas
| Modelo | Dim | Tamanho | Velocidade | Qualidade (MTEB) | Ideal 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 | Maior qualidade, ainda estático |
| potion-retrieval-32M | 256 | 120 MB | 400x | 35,06 (recuperação) | 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 | Maior 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 qualidade melhor que a do 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, atingindo uma pontuação geral de 52,83 em todas as tarefas (cerca de 3% maior que a do potion-base-8M), mantendo a mesma saída de 256 dimensões e a dependência apenas em numpy.8 O arquivo do modelo 4x maior aumenta o uso de memória, mas a velocidade de embedding continua ordens de magnitude maior que a de modelos transformer.
Escolha potion-retrieval-32M quando seu principal caso de uso for recuperação (que é o caso da busca no vault). Essa variante é ajustada a partir do potion-base-32M especificamente para tarefas de recuperação, com pontuação de 35,06 na tabela de benchmark de recuperação do Model2Vec, contra 32,67 do potion-base-32M.8 O trade-off é que ele é otimizado para recuperação, não para qualidade de embedding de uso geral.
Escolha potion-multilingual-128M quando seu vault contiver notas em vários idiomas. Lançado em maio de 2025, esse modelo de 101 idiomas é o modelo de embedding estático com melhor desempenho para tarefas multilíngues, gerando embeddings para qualquer texto em qualquer idioma e mantendo a mesma dependência apenas em numpy dos outros modelos potion.12 O arquivo maior do modelo (~500 MB) é o trade-off pela capacidade multilíngue. Use 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 SQLite em ~50% em comparação com vetores de 256 dimensões. A velocidade de embedding 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 local possível de recuperação e aceitar uma indexação mais lenta. Os vetores de 768 dimensões praticamente triplicam o tamanho do banco de dados. Exige 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 embeddings da mais alta qualidade, mas introduz uma dependência de nuvem, custo por token ($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 apenas em 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
O Model2Vec v0.5.0+ permite carregar modelos com precisão e dimensões reduzidas.8 Isso é útil para implantação 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 consumo de memória. A redução de dimensionalidade segue uma truncagem no estilo Matryoshka — as primeiras N dimensões carregam a maior parte da informação. 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.
O Model2Vec v0.8.x atualiza os componentes internos de tokenizer/persistência, descontinua o suporte ao Python 3.9 e atualiza os resultados publicados para as tabelas MTEB mais recentes. Faça pin ou teste model2vec antes de atualizar um indexer de produção, porque upgrades de biblioteca podem alterar caminhos de carregamento do modelo mesmo quando o nome do modelo de embedding permanece o mesmo.10
Fine-tuning para embeddings específicos do vault
O Model2Vec v0.4.0+ permite treinar modelos de classificação personalizados sobre embeddings estáticos, a v0.7.0 adiciona quantização de vocabulário e pooling configurável para destilação, e a 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 de domínio específico) 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 passar 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 indexer armazena um hash derivado do nome do modelo e do tamanho do vocabulário. Se você alterar o modelo de embedding, o indexer 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 volta para o modo somente BM25. O modelo fica em cache local após o 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 indexer detecta isso via hash do modelo e dispara uma reindexação completa. Se a verificação de hash falhar (modelo personalizado sem hash adequado), o sqlite-vec gerará erro em consultas KNN com dimensões incompatíveis.
Pressão de memória em vaults grandes. Gerar embeddings de 50.000+ chunks em um único batch pode consumir bastante memória. O indexer processa em batches de 64 para limitar o pico de uso de memória. Se a memória ainda for um problema, reduza o tamanho do batch.
Pesquisa de texto completo com FTS5
A extensão FTS5 do SQLite oferece pesquisa de texto completo com ranqueamento BM25. FTS5 é o componente de busca por palavras-chave do pipeline de recuperação híbrida (hybrid retrieval). 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 forem 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 do termo, frequência inversa do documento 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 bem 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 busca 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 busca 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 inúteis na prática — o ranqueamento não consegue determinar qual nota de “configuração” é relevante para a consulta atual.
Tokenizador FTS5
O FTS5 usa o tokenizador unicode61 por padrão, que lida com texto ASCII e Unicode. Para vaults com conteúdo CJK significativo (chinês, japonês, coreano), considere o tokenizador 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 tokenizador padrão unicode61 divide por limites de palavras, o que funciona mal para idiomas sem espaços entre as palavras. O tokenizador trigram divide a cada três caracteres, permitindo correspondência por substring ao custo do tamanho do índice (aproximadamente 3 vezes 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 — nesses casos, use INSERT INTO chunks_fts(rowid, chunk_text, section, heading_context) para sincronizar linhas individuais.
Busca vetorial com sqlite-vec
A extensão sqlite-vec leva a busca vetorial KNN (K-Nearest Neighbors) para o SQLite. Esta seção aborda a configuração do sqlite-vec, o pipeline de embeddings 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 faz o mapeamento 1:1 para a tabela chunks, permitindo joins entre resultados vetoriais e metadados de chunks.
Pipeline de embeddings
O pipeline flui da nota para 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 de vetores
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 embeddings da consulta de entrada e, em seguida, 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 aceitam restrições WHERE distance < ?, permitindo paginação baseada em cursor em grandes conjuntos de resultados sem varrer novamente as páginas anteriores.14 As versões estáveis posteriores v0.1.8 e v0.1.9 são lançamentos de empacotamento e correção de bug de DELETE, não lançamentos 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
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 em Python, reduzindo o uso de memória em consultas exploratórias sobre vaults 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: “how to handle authentication failures” → Encontra notas sobre “login error recovery” (mesmo espaço semântico, palavras-chave diferentes)
- Consulta: “what patterns exist for caching” → Encontra notas sobre “memoization,” “Redis TTL strategies,” e “HTTP cache headers” (conceitos relacionados, terminologia diversa)
- Consulta: “approaches to testing asynchronous code” → Encontra notas sobre “pytest-asyncio fixtures,” “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 classificar 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 embeddings diferentes dos de uma discussão em prosa sobre code review.
Degradação gradual
Se o sqlite-vec não conseguir carregar (extensão ausente, plataforma incompatível, biblioteca corrompida), o retriever volta para busca somente 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 desativado, 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 com exemplo, 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ários e um explorador visual de arquitetura, veja a análise aprofundada do hybrid retriever.
O algoritmo
RRF atribui a cada documento uma pontuação baseada apenas na posição dele no 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, começando em 1, na lista de resultados i
- weight_i é um multiplicador opcional por lista (padrão 1.0)
Documentos 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 usar RRF em vez de alternativas
Combinação linear ponderada exige calibrar pontuações BM25 em relação a distâncias de cosseno. As pontuações BM25 não têm limite superior e escalam com o tamanho do corpus. As distâncias de cosseno 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 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 consulta-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 (contagem de Borda, método de Schulze) são teoricamente elegantes, mas mais complexos de implementar e ajustar. O artigo original sobre 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 sobre resolução de conflitos). Depois da fusão 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 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 com rank duplo. A lógica real de resolução de divergências 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, teste diferentes valores de k na calculadora RRF interativa.
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 comparação com os resultados em posições mais baixas:
- k menor (por exemplo, 10): Os resultados no topo dominam. O rank 1 pontua 1/11 = 0,091, o 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. O rank 1 pontua 1/61 = 0,0164, o 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 maior (por exemplo, 200): Aparecer em ambas as listas importa muito mais do que a posição no rank. O rank 1 pontua 1/201, o rank 10 pontua 1/210 — quase idênticos. 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 considerou esse valor robusto em diversos datasets TREC. Ajuste somente 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 o empate assim:
- Prefira chunks que aparecem em ambas as listas em vez de chunks que aparecem em apenas uma
- Entre chunks presentes nas duas listas, prefira aquele com o menor rank combinado
- Entre chunks presentes 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 até a 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.
O API de busca
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 por 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.
Schema 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 é um arquivo de banco de dados ausente.
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 de fusão RRF | 3ms |
| Latência de busca de ponta a ponta (p50) | 23ms |
| Tempo de reindexação completa | ~4 minutos |
| Tempo de reindexação incremental | <10 segundos |
| Modelo de embeddings | potion-base-8M (256-dim) |
| Pool de candidatos BM25 | 30 |
| Pool de candidatos vetorial | 30 |
| Limite padrão de resultados | 10 |
| Orçamento padrão de tokens | 4.000 tokens |
Hash de conteúdo e detecção de mudanças
O indexador precisa saber quais arquivos mudaram desde a última execução do índice. Esta seção cobre o mecanismo de detecção de mudanças e a estratégia de hash.
Comparação do 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:
- Escaneia o vault em busca de todos os arquivos
.mdnas pastas permitidas - Lê o
mtime_nsde cada arquivo no filesystem - Compara com o
mtime_nsarmazenado no banco de dados - Identifica três categorias:
- Arquivos novos: o caminho existe no filesystem, mas não no banco de dados
- Arquivos alterados: o caminho existe em ambos, mas o
mtime_nsé diferente - Arquivos excluídos: o caminho existe no banco de dados, mas não no filesystem
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
Hash 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 mudar (por exemplo, um git checkout restaurando o mtime original). Porém, fazer hash exige ler todos os arquivos a cada execução incremental. Para 16.894 arquivos, ler o conteúdo dos arquivos leva 2-3 segundos. Ler mtimes no filesystem leva <100ms.
O trade-off: a comparação por mtime ocasionalmente dispara uma reindexação desnecessária de arquivos inalterados (falsos positivos), mas nunca deixa de detectar mudanças reais. Falsos positivos custam algumas chamadas extras de embeddings por execução. A diferença de velocidade (100ms contra 3 segundos) torna mtime a escolha pragmática para um sistema que roda em toda 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 (descartar e recriar a tabela virtual ou manter um conjunto externo de “IDs ativos”). Se estiver usando uma versão anterior à 0.1.9, faça upgrade antes de depender de deletes diretos em schemas 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 cuida disso como parte do processo de remoção do arquivo.
Reindexação incremental vs completa
O indexador oferece 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.
Reindexação incremental
Quando usar: Indexação diária após editar notas. É o modo padrão.
O que faz: 1. Escaneia o cofre em busca de alterações nos arquivos (comparação de mtime) 2. Exclui chunks de arquivos excluídos 3. Recria os chunks e 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 cofre com 16.000 arquivos.
python index_vault.py --incremental
Reindexação completa
Quando usar: - Depois de trocar o modelo de embeddings (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 faz: 1. Remove todos os dados existentes (chunks, vetores, entradas FTS5) 2. Escaneia o cofre inteiro 3. Cria chunks para todos os arquivos 4. Gera embeddings para 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
Os dois 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 ficar corrompido (queda de energia durante uma gravação, 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 os arquivos do cofre, não o banco de dados. O banco de dados é um artefato derivado que pode ser recriado a qualquer momento. Esta é uma propriedade essencial 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 forem diferentes, muda automaticamente para o modo de reindexação completa e avisa o usuário.
- Escaneamento de arquivos. Percorre as pastas permitidas, coletando caminhos de arquivos e mtimes.
- Detecção de alterações. Compara com os dados armazenados.
- Processamento em lotes. Recria chunks e embeddings dos arquivos alterados em lotes de 64.
- Relatório de progresso. Imprime a contagem de arquivos processados e o tempo decorrido.
- Encerramento gradual. Lida com 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 recuperação.
O problema
Uma nota sobre debugging de uma integração com 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 com 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 todos os chunks antes do armazenamento, comparando 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 >4,5 bits/caractere de entropia, 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 vira 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 “havia algo parecido com uma credencial 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 caminhos
O arquivo .indexignore oferece exclusão ampla por caminho. O filtro de credenciais oferece limpeza detalhada dentro dos arquivos indexados. Os dois 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 inseridos acidentalmente em conteúdo que, de outra forma, poderia ser indexado
Classificação de dados
Para cofres 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
Os servidores Model Context Protocol (MCP) expõem o mecanismo de recuperação como uma ferramenta que agentes de IA podem chamar. Esta seção aborda 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 dois modos de transporte:
STDIO — A ferramenta de IA inicia o servidor MCP como um processo filho e se comunica via 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 é executado 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. Ele é mais simples, mais seguro (sem exposição à rede) e o ciclo de vida do servidor é gerenciado pela ferramenta de IA. Use HTTP apenas 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 (schemas de retorno tipados) e elicitation (prompts de usuário iniciados pelo servidor). A versão de novembro de 2025 trouxe Streamable HTTP como modo de transporte de primeira classe, descoberta por URL
.well-knownpara navegação automática das capacidades do servidor, anotações estruturadas de ferramentas que declaram se uma ferramenta é somente leitura ou mutante, e um sistema de padronização por níveis SDK.79 A próxima versão da especificação (prevista provisoriamente para meados de 2026) propõe operações assíncronas para tarefas de longa duração, extensões de protocolo específicas de domínio para setores como saúde e finanças, e padrões de comunicação agente-para-agente para workflows multiagente.9 Para servidores de vaults pessoais, STDIO continua sendo o caminho mais simples. O transporte Streamable HTTP e a descoberta.well-knownbeneficiam principalmente implantações HTTP corporativas com roteamento multi-tenant e balanceamento de carga. Acompanhe 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 por 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 rigorosos:
-
Somente leitura. O servidor lê o vault e o banco de dados do í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.
-
Restrito ao vault. O servidor lê apenas arquivos dentro do caminho configurado do vault. Tentativas de path traversal (
../../etc/passwd) devem ser rejeitadas. -
Saída com filtro de credenciais. Mesmo que o banco de dados contenha conteúdo pré-filtrado, aplique filtragem de credenciais na saída como uma medida de defesa em profundidade.
-
Respostas limitadas por tokens. Imponha
max_tokensem todas as respostas de ferramentas para evitar que a ferramenta de IA receba blocos de contexto grandes demais.
Tratamento de erros
As 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 aborda a configuração de MCP, a integração com hooks e o padrão obsidian_bridge.py.
Configuração de 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 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 Obsidian:
Hook PreToolUse — Consulta o cofre antes que o agente processe uma chamada de ferramenta. Injeta contexto relevante automaticamente.
#!/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 importantes das ferramentas de volta para o cofre 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 uma API de 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 cofre:
/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 o 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 cofre em comandos nomeados. Profissionais criaram bibliotecas de comandos específicos para Obsidian que tratam o cofre 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 no cofre 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 cofre específicas por tópico. O cofre se torna o consumidor downstream de um pipeline automatizado de inteligência.
Diário de bordo. Um comando /captains-log agrega a atividade diária do git em todos os repositórios, grava uma entrada estruturada de diário no cofre 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 tudo 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 cofre 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 cofre: criar MOCs, atualizar notas de status de projetos, vincular sinais relacionados ou gerar resumos semanais a partir de 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 que cobrem revisões diárias, planejamento de projetos, captura de pesquisa e fluxos de conteúdo.1 Outro criou uma skill “Visual Explainer” que gera notas com diagramas no cofre a partir de análise de código.2 Os comandos variam, mas a arquitetura é consistente: skills do Claude Code como interface, notas do cofre como camada de armazenamento e infraestrutura de recuperação como mecanismo de consulta.
Gerenciamento da janela de contexto
A integração deve levar em conta 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 as informações principais. - 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 cofre. Operações de 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 de 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ção sobre pesquisa no cofre:
## 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 de MCP | settings.json |
config.toml |
| Hooks | ~/.claude/hooks/ |
Sem suporte |
| Skills | ~/.claude/skills/ |
Sem suporte |
| Arquivo de instruções | CLAUDE.md |
AGENTS.md |
| Modos de aprovação | --dangerously-skip-permissions |
suggest / auto-edit / full-auto |
Principal diferença: 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 cofre 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 de ferramentas comuns.
Cursor
Adicione ao .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 cofre:
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 | UI de configurações |
| Claudian (plugin do Obsidian) | N/A (incorporado) | Claude Code CLI | configurações do plugin do Obsidian |
| Agent Client (plugin do Obsidian) | N/A (incorporado) | ACP | configurações do plugin do Obsidian |
Alternativa para ferramentas sem MCP
Para ferramentas que não oferecem suporte a MCP, o mecanismo de recuperação pode ser empacotado como um 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
O 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.
Cache de prompt a partir de notas estruturadas
Notas estruturadas no cofre podem servir como blocos de contexto reutilizáveis que reduzem o uso de tokens nas 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 em toda interação, pré-construa blocos de contexto a partir de notas bem estruturadas do cofre 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 do cache
A invalidação do cache se baseia em dois sinais:
- Expiração do TTL. Cada bloco de contexto tem um tempo de vida. Quando o TTL expira, o bloco é reconstruído ao consultar o cofre novamente.
- Detecção de alterações no cofre. Quando o indexador 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. Os 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âmica preenchem o orçamento restante por consulta. Essa abordagem hybrid dá ao agente uma base de contexto necessário com frequência, preservando orçamento para consultas específicas.
Uso de tokens antes/depois
Sem cache: Toda consulta relevante aciona uma busca no cofre, retornando 1.500-2.000 tokens de contexto. Ao longo de 10 consultas em uma sessão, o agente consome 15.000-20.000 tokens de contexto do cofre.
Com cache: Três blocos de contexto pré-construídos consomem 4.500 tokens no total. Buscas adicionais acrescentam 1.500-2.000 tokens por consulta única. Ao longo de 10 consultas em que 6 são cobertas por blocos em cache, o agente consome 4.500 + (4 * 1.500) = 10.500 tokens — cerca de 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 comprimir essas saídas antes que elas consumam espaço da janela de contexto.
O problema
Uma chamada da ferramenta Bash que executa testes pode 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 passed, 1 failed.
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 acionamento recursivo
Um hook de compressão que emite saída poderia acionar a si mesmo se não houvesse 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 |
| Status do Git | modified: / new file: |
Resumir contagens por status |
| Saída de build | warning: / error: |
Remover linhas informativas, manter warnings/errors |
Pipeline de ingestão e triagem de sinais
A camada de ingestão determina o que entra no cofre. Sem curadoria, o cofre 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, notas de versão
- Bookmarks via Web Clipper: A extensão oficial Obsidian Web Clipper (Chrome, Firefox, Safari) é o caminho de ingestão de maior fidelidade para capturas no navegador. O ciclo de lançamento de abril de 2026 tornou a extensão bem mais útil para workflows de AI:22
- 1.4.0 (9 de abril): 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 um clique direto para o modo Reader.
- 1.5.0–1.5.1 (15 de abril): Visualizador de destaques — navegue e pesquise destaques capturados em todo o cofre. Transição fade-in para o Reader. Play/pause do YouTube mais suave. A versão 1.5.1 corrigiu uma regressão de compilação do webpack.
- 1.6.0–1.6.2 (21–23 de abril): Revisão da UX do marcador com suporte para mobile. Defuddle 0.18 adiciona extratores específicos por fonte para LinkedIn, Threads, Bluesky, Discourse e Medium. A versão 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 GitHub e artigos longos sejam salvos em notas com nomes sensatos e o frontmatter correto para o pipeline de pontuação abaixo.
- Newsletters: Trechos importantes de newsletters por email
- Captura manual: Notas escritas durante leituras, conversas ou pesquisas
- 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, de redes sociais e de outros apps diretamente no cofre, sem abrir o Obsidian.19 Isso cria um caminho de ingestão mobile com baixo atrito — compartilhe um artigo do Safari e ele chega como uma nota do cofre pronta para pontuação.
- Obsidian CLI: Shell scripts e hooks podem criar notas via
obsidian file createou anexar conteúdo a notas existentes viaobsidian file append, permitindo pipelines de ingestão automatizados no desktop.
Dimensões de pontuação
Cada sinal recebe uma 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 | Isso 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 grafo de conhecimento
O grafo de wiki-links do Obsidian codifica relações entre notas. Esta seção cobre a semântica dos links, a travessia do grafo para expansão de contexto e anti-patterns que degradam a qualidade do grafo.
Semântica de backlinks
Cada 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 mais detalhes” |
| Link de cabeçalho | “Tem subtópico” | ”## Relacionados\n- [[Token Rotation]]\n- [[Session Management]]” |
| Link em formato de tag | “É categorizado como” | ”[[type/reference]]” |
| Link de MOC | “Faz parte de” | Uma nota Map of Content listando 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)
Isso não está implementado no retriever atual, mas representa uma extensão natural da estrutura do grafo.
Anti-patterns
Clusters órfãos. Grupos de notas que apontam umas para as outras, mas não têm conexões com o restante do cofre. O painel de grafo no Obsidian torna esses grupos visíveis 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 refinadas demais em excesso. Um cofre 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 mapeiem para suas pastas de domínio.
Notas com muitos links e pouco conteúdo. Notas compostas inteiramente por wiki-links, sem prosa. Essas notas são mal indexadas porque o chunker não tem texto para incorporar em embeddings. 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 forneça contexto útil.
Receitas de fluxo de trabalho para desenvolvedores
Fluxos de trabalho práticos que combinam recuperação do cofre 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 sistema de recuperação retorna notas recentes sobre seu projeto ativo, dando a você uma revisão rápida de onde parou. É mais eficaz do que reler as mensagens de commit de ontem.
Captura de pesquisa durante a programação
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 constroem um corpus de conhecimento específico de implementação.
Início de projeto
Ao começar um novo projeto ou recurso:
- Pesquise no cofre: “O que eu sei sobre [tecnologia/padrão]?”
- Revise os 5 principais resultados em busca de decisões anteriores e armadilhas
- Verifique se existe um MOC para o domínio; se não existir, crie um
- Pesquise modos de falha: “problemas com [tecnologia]”
Debugging com busca no cofre
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 cofre 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 cofre retorna decisões anteriores, restrições arquiteturais e padrões de código relevantes para o código em revisão. A revisão é orientada por conhecimento institucional, não apenas pelo diff.
Ajuste de desempenho
Esta seção cobre estratégias de otimização para diferentes tamanhos de cofre e padrões de uso.
Gerenciamento do tamanho do índice
| Tamanho do cofre | 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 batch de 64 para 128 para acelerar embeddings - Usar modo WAL (padrão) para acesso concorrente - Executar a reindexação completa fora do horário de pico
Otimização de consultas
Modo WAL. O modo Write-Ahead Logging do SQLite permite leituras concorrentes enquanto o indexador escreve:
db.execute("PRAGMA journal_mode=WAL")
Isso é crítico quando o servidor MCP lida com consultas enquanto o indexador executa uma atualização incremental.
Pool 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 diz ao SQLite para usar I/O mapeado em memória para o arquivo do banco de dados. Para um banco de dados de 83 MB, mapear o arquivo inteiro na memória elimina a maior parte das leituras em disco.
Otimização de FTS5. Depois de uma reindexação completa, execute:
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');
Isso mescla os segmentos b-tree internos do FTS5, reduzindo a latência de consultas em buscas posteriores.
Benchmarks de escala
Medido em Apple M3 Pro, 36 GB RAM, NVMe SSD:
| 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 |
| Busca 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 busca retorna resultados obsoletos ou deixa de encontrar notas adicionadas recentemente.
Causa: O indexador incremental não foi executado após a adição das 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 busca 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 do 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: Os 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 lazy), que leva de 2 a 5 segundos. O timeout padrão de MCP da ferramenta de AI pode ser menor.
Correção: Pré-aqueça o modelo na inicialização do servidor:
# In MCP server initialization
retriever = HybridRetriever(db_path, vault_path)
retriever.search("warmup", limit=1) # Trigger model load
Bloqueios 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 busy timeout:
db.execute("PRAGMA busy_timeout=5000") # Wait up to 5 seconds
sqlite-vec não carrega
Sintoma: A busca vetorial está desativada; o sistema de recuperação 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 cofres grandes
Sintoma: Erros de falta de memória durante a reindexação completa de um cofre grande (50.000+ notas).
Causa: O tamanho do batch de embeddings é grande demais, ou todo o conteúdo dos arquivos é carregado na memória de uma vez.
Correção: Reduza o tamanho do batch e processe os arquivos incrementalmente:
BATCH_SIZE = 32 # Reduce from 64
Garanta também que o indexador processe os arquivos um por vez (lendo, fazendo chunking e gerando embeddings para 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 pela opção “Export All” (macOS) ou use uma ferramenta de migração como
apple-notes-liberator - Converta exportações HTML para markdown usando
markdownifyoupandoc - Mova os arquivos convertidos para a pasta
00-inbox/do seu cofre - 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 cofre - Corrija artefatos de markdown específicos do Notion:
- Notion usa
- [ ]para checklists — isso é markdown padrão - Notion inclui tabelas de propriedades como HTML — converta para frontmatter YAML
- 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 cofre, adicione frontmatter e organize em pastas
De markdown simples (sem Obsidian)
Se você já tem um diretório de arquivos markdown:
- Abra o diretório como um cofre do Obsidian (Obsidian → Open Vault → Open folder)
- Adicione
.obsidian/ao.gitignorese o diretório estiver sob controle de versão - Crie templates de frontmatter e aplique aos arquivos existentes
- Comece a vincular notas com
[[wiki-links]]enquanto 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ê estiver migrando de outro sistema de embeddings/busca:
- 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 cofre são a fonte da verdade. O índice é um artefato derivado.
- Verifique depois da migração. Execute 10-20 consultas cujas respostas você conhece e verifique se os resultados correspondem às suas expectativas.
Registro de alterações
| Data | Alteração |
|---|---|
| 2026-05-28 | Obsidian 1.13.0 desktop + 1.13.0 mobile (Catalyst early-access) lançados. Desktop: painel de configurações reformulado, que abre em uma janela própria com busca integrada e navegação por teclado; Obsidian URIs agora exibem uma caixa de diálogo de confirmação antes de executar ações; novo aviso antes de carregar recursos HTML de unidades de rede; busca adicionada à visualização Bookmarks; tratamento de imagens no editor aprimorado; melhorias em File Explorer / Properties / Sync; várias correções para developer-API e bugs. Mobile: nova iOS Share Sheet com locais de destino configuráveis; reordenação de abas pelo seletor de abas; gestos de pressionar e segurar em tablets para redimensionar divisões e barras laterais fixadas; Bases ganhou 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 IA: a caixa de diálogo de confirmação em Obsidian URIs adiciona uma barreira deliberada a integrações MCP/agent acionadas por URI; o menu de redimensionamento de colunas do Bases torna o Bases mais usável como um índice frontal do vault que agents consultam; o destino configurável da iOS Share Sheet torna o caminho de captura pelo iPhone (já documentado como a entrada principal) mais rápido de conectar a pipelines Claude/Codex. |
| 2026-05-06 | Atualiza a verificação de atualidade baseada em fontes: Smart Connections v4.5.0 moveu conexões do rodapé para Core; releases estáveis sqlite-vec v0.1.8/v0.1.9 atualizaram o empacotamento e o comportamento de DELETE; Model2Vec v0.8.x atualizou componentes internos de tokenizer/persistência e tabelas de benchmark; corrige a cronologia do Obsidian CLI de “1.12.7 introduziu CLI” para “1.12.0 introduziu CLI, 1.12.7 melhorou a instalação/o empacotamento em 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 de 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 no Safari). Reposiciona o Web Clipper como o principal caminho de entrada no navegador para workflows de IA, em vez de uma menção passageira como bookmark. Sem releases 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, ambiente cross-plugin Substrate). Documenta a onda de plugins AI-native de abril de 2026 (Cortex, VaultSearch, LLM Wiki, Drift, EngramQuest, Hybrid Search MCP). Marca MarkusPfundstein/mcp-obsidian como em modo de manutenção (último commit em junho de 2025). Dataview inativo; Bases é o sucessor para novos trabalhos. Obsidian CLI 1.12.7 continua sendo a ponte preferida para assistentes de IA. |
| 2026-04-01 | Adiciona seção do Obsidian CLI (comandos v1.12 para workflows de IA). Adiciona seção de plugin de agent (Claudian, Agent Client). Documenta o plugin core Bases para organização do vault. Atualiza contagem de plugins para 2.500+. Adiciona iOS Share Extension como fonte de entrada. Atualiza matriz de compatibilidade com plugins de agent 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 | Documenta 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 um próximo release. |
| 2026-03-07 | Adiciona 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 | Atualiza a evolução da especificação MCP (lançado em nov. de 2025: Streamable HTTP, .well-known, tool annotations). Adiciona fine-tuning de Model2Vec e suporte a tokenizer BPE/Unigram. Adiciona tabela de comparação de servidores MCP da comunidade. Atualiza Smart Connections para v4. |
| 2026-03-02 | Adiciona potion-base-32M e potion-retrieval-32M à comparação de modelos. Adiciona seção de quantização/redução de dimensionalidade. Adiciona nota sobre a evolução da especificação MCP. |
| 2026-03-01 | Release 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 slash commands, 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 atualmente mostram 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 mostram 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 por URL .well-known, anotações estruturadas de ferramentas e padronização do nível SDK. A próxima versão está prevista provisoriamente para meados de 2026, com operações async, extensões específicas por domínio e comunicação agent-to-agent. ↩↩
-
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 de Python 3.9, atualizações de resultados MTEB V2 e compatibilidade com caminhos do Windows. ↩↩
-
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 embeddings estáticos em 101 idiomas, os embeddings estáticos multilíngues com melhor desempenho. Mesma dependência somente de numpy dos outros modelos potion. ↩
-
MCPVault v0.11.0. Março de 2026. Nova ferramenta
list_all_tagspara escanear frontmatter e hashtags com contagens. Melhorias no tratamento de pastas com pontos, suporte a arquivos.basee.canvas. Pacote renomeado para@bitbonsai/mcpvaultno npm. ↩ -
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 fuzz testing. Indexação aproximada de vizinhos mais próximos DiskANN anunciada para versão futura. ↩↩↩
-
Introduction to Bases. Plugin principal do Obsidian introduzido na v1.9.10. Visualizações semelhantes a 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 baseada em terminal; a v1.12.7 melhorou a instalação/empacotamento de 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 com reconhecimento de contexto, suporte a visão, slash commands e modos de permissão. ↩
-
Agent Client. Plugin do Obsidian que oferece 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. As 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. Último commit em 28 de junho de 2025. Sem releases com tag. Discussões no fórum (abril de 2026) relatam a migração da comunidade para integração baseada em CLI desde que o Obsidian 1.12.x lançou o CLI nativo. Preservado neste guia por contexto histórico e para usuários com configurações existentes, mas não recomendado para novas implantações. ↩↩
-
Smart Connections v4.5.0 Release. 5 de maio de 2026. Conexões no rodapé viraram um recurso Core; releases recentes da v4 também incluem visualizações de grafo para listas de conexões, locais configuráveis para o painel de conexões, recuperação aprimorada de block-embedding, estado cross-plugin Substrate, correções de fallback de transformer e redução de cálculos duplicados de conexão. ↩
-
obsidianmd/obsidian-clipper releases — fonte primária para o mapeamento de 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 para 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 da área de transferência 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 e sqlite-vec v0.1.10-alpha.3. A v0.1.8 corrigiu o empacotamento npm; a v0.1.9 corrigiu um bug de DELETE para colunas de texto de metadados com mais de 12 caracteres; a v0.1.10-alpha.3 adiciona suporte adequado a
INSERT OR REPLACE INTO, mas ainda é prerelease. ↩↩↩