📄 Configurando USER.md com o Contexto do Vault
A integração mais simples e imediata: sem código. Adicione ao USER.md um catálogo do vault e o Intelecto passará a ter consciência do seu segundo cérebro em todas as conversas.
# Contexto do Usuário
Nome: João Silva
Profissão: Engenheiro de Software
Linguagem favorita: Python
Preferências:
- Respostas diretas e curtas
- Exemplos de código práticos
Intelecto não sabe nada sobre o vault
# Contexto do Usuário
Nome: João Silva
Profissão: Engenheiro de Software
## Segundo Cérebro (Obsidian)
Vault: ~/vault | Páginas: ~150
### Domínios principais
- Python, FastAPI, SQLite
- LLMs e Agentes de IA
- Gestão de Conhecimento
### Projetos ativos
- api-gateway (produção)
- intelecto-bridge (dev)
### Conceitos-chave no vault
[[bm25]], [[fts5]], [[rag-vs-wiki]]
[[agente-ingestao]], [[index-estrutura]]
Ao mencionar tópicos do vault,
referencie as páginas relevantes.
Intelecto sabe do vault e sugere páginas
💡 Resultado imediato
Com o USER.md atualizado, o Intelecto começa a responder: "Você tem uma página sobre BM25 no seu vault — quer que eu expanda a comparação com embeddings para adicionar lá?". Zero código, zero infraestrutura. Apenas edição de Markdown.
🔧 Script de Bridge
O bridge.py é o componente central da integração: lê o vault e injeta conhecimento compilado no SQLite do Intelecto. Cerca de 80 linhas Python que fecham o loop entre as duas memórias.
#!/usr/bin/env python3
"""
bridge.py — Sincroniza vault Obsidian com memória SQLite do Intelecto
Uso: python bridge.py [--incremental]
"""
import sqlite3, pathlib, re, hashlib, sys
from datetime import datetime
VAULT_DIR = pathlib.Path.home() / "vault"
WIKI_DIR = VAULT_DIR / "wiki"
DB_PATH = pathlib.Path.home() / ".intelecto" / "intelecto.db"
SYNC_LOG = VAULT_DIR / ".last_sync"
def get_db():
conn = sqlite3.connect(DB_PATH)
# Garante que a tabela existe
conn.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS memories
USING fts5(content, source UNINDEXED, page_id UNINDEXED)
""")
return conn
def parse_index(index_path: pathlib.Path) -> list[dict]:
"""Extrai entradas do index.md: [[page]] — resumo"""
entries = []
pattern = re.compile(r'\[\[([^\]]+)\]\].*?—\s*(.+)$', re.MULTILINE)
text = index_path.read_text(encoding='utf-8')
for match in pattern.finditer(text):
page_name, summary = match.groups()
entries.append({'page': page_name.strip(), 'summary': summary.strip()})
return entries
def sync_page(conn, page_name: str, summary: str):
"""Lê a página wiki e insere no SQLite como memória estruturada"""
page_file = WIKI_DIR / f"{page_name}.md"
if not page_file.exists():
return
content = page_file.read_text(encoding='utf-8')
# Extrai apenas o corpo (sem frontmatter YAML)
body = re.sub(r'^---.*?---\n', '', content, flags=re.DOTALL)[:600]
page_id = hashlib.md5(page_name.encode()).hexdigest()[:8]
memory_text = f"[VAULT:{page_name}] {summary}\n{body}"
# Remove entrada anterior desta página se existir
conn.execute("DELETE FROM memories WHERE page_id = ?", [page_id])
conn.execute(
"INSERT INTO memories(content, source, page_id) VALUES (?, 'vault', ?)",
[memory_text, page_id]
)
def main():
incremental = '--incremental' in sys.argv
conn = get_db()
index_path = WIKI_DIR / "index.md"
if not index_path.exists():
print("index.md não encontrado. Configure o vault primeiro.")
return
entries = parse_index(index_path)
synced = 0
for entry in entries:
page_file = WIKI_DIR / f"{entry['page']}.md"
if incremental and SYNC_LOG.exists():
last_sync = SYNC_LOG.stat().st_mtime
if page_file.exists() and page_file.stat().st_mtime < last_sync:
continue # Não modificada desde último sync
sync_page(conn, entry['page'], entry['summary'])
synced += 1
conn.commit()
SYNC_LOG.write_text(datetime.now().isoformat())
print(f"Sincronizadas {synced} páginas do vault → SQLite Intelecto")
if __name__ == "__main__":
main()
python bridge.py
Sincroniza todas as páginas
python bridge.py \
--incremental
Só páginas modificadas
# crontab -e
0 */6 * * * python \
~/bridge.py --incremental
A cada 6 horas
📥 Ingestão pelo Telegram
O Telegram como interface de captura torna a ingestão tão natural quanto enviar uma mensagem. O fluxo completo: Telegram → raw/ → LLM compila → wiki/ atualizado.
📥 Fluxo de Ingestão via Telegram
from telegram import Update
from telegram.ext import CommandHandler, ContextTypes
import httpx, pathlib, datetime
VAULT_RAW = pathlib.Path.home() / "vault" / "raw"
async def ingere_handler(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
"""Handler para /ingere [URL ou texto]"""
args = ' '.join(ctx.args) if ctx.args else ''
if not args:
await update.message.reply_text("Uso: /ingere [URL ou texto a ingerir]")
return
# Se for URL, busca o conteúdo
if args.startswith('http'):
await update.message.reply_text("⏳ Buscando conteúdo da URL...")
async with httpx.AsyncClient() as client:
resp = await client.get(args, timeout=15)
content = f"URL: {args}\n\n{resp.text[:5000]}"
else:
content = args
# Salva em raw/
timestamp = datetime.datetime.now().strftime('%Y-%m-%d-%H%M')
filename = VAULT_RAW / f"raw-{timestamp}.md"
filename.write_text(f"---\norigem: telegram\ndata: {timestamp}\n---\n\n{content}")
await update.message.reply_text(
f"✅ Salvo em raw/raw-{timestamp}.md\n"
f"Execute o pipeline de ingestão para compilar no wiki."
)
# Registrar o handler no Application
app.add_handler(CommandHandler("ingere", ingere_handler))
🔀 Consulta Híbrida
Na consulta híbrida, o Intelecto combina contexto de conversa (SQLite BM25) com conhecimento estruturado (página wiki) antes de gerar cada resposta, produzindo sínteses muito mais ricas.
Como funciona o BM25 do Intelecto?
BM25 é um algoritmo de ranking para busca de texto. Usa TF-IDF com normalização de comprimento. O Intelecto usa via SQLite FTS5.
Resposta genérica, sem o detalhe do seu vault
Como funciona o BM25 do Intelecto?
Conforme sua página [[bm25]] no vault: o Intelecto usa k1=1.2 e b=0.75 por padrão. Para suas memórias curtas (~100 tokens), você documentou que reduzir k1 para 0.9 melhora o recall em 23%. Quer atualizar a config?
Resposta com dados específicos do seu vault
import re, pathlib, sqlite3
WIKI_DIR = pathlib.Path.home() / "vault" / "wiki"
WIKI_PATTERN = re.compile(r'\[\[([^\]]+)\]\]')
def find_wiki_page(query: str, db_path: str) -> str | None:
"""Busca no SQLite e retorna página wiki relevante se encontrada"""
conn = sqlite3.connect(db_path)
# Busca memórias do vault (source='vault') relevantes à query
rows = conn.execute(
"SELECT content FROM memories WHERE memories MATCH ? "
"AND source = 'vault' ORDER BY bm25(memories) LIMIT 1",
[query]
).fetchall()
if not rows:
return None
# Extrai nome da página do padrão [VAULT:page_name]
match = re.search(r'\[VAULT:([^\]]+)\]', rows[0][0])
if not match:
return None
page_name = match.group(1)
page_file = WIKI_DIR / f"{page_name}.md"
if page_file.exists():
return page_file.read_text()[:1500] # Primeiros 1500 chars
return None
# No handler de mensagens, antes de chamar o LLM:
wiki_context = find_wiki_page(user_message, DB_PATH)
if wiki_context:
system_extra = f"\n\n## Conhecimento do vault do usuário:\n{wiki_context}"
# Adicionar ao system prompt desta chamada
🔄 Sincronização Automática
Com um watcher Python monitorando o vault, cada nova página wiki dispara automaticamente a sincronização com o SQLite do Intelecto — sem cron, sem intervenção manual.
#!/usr/bin/env python3
"""
watcher.py — Monitora wiki/ e sincroniza com SQLite automaticamente
Dependência: pip install watchdog
"""
import time, subprocess, pathlib
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
WIKI_DIR = pathlib.Path.home() / "vault" / "wiki"
BRIDGE_SCRIPT = pathlib.Path.home() / "bridge.py"
DEBOUNCE_SECONDS = 5 # Evita sync duplo em saves rápidos
class WikiChangeHandler(FileSystemEventHandler):
def __init__(self):
self._last_sync = 0
def on_modified(self, event):
if event.is_directory or not event.src_path.endswith('.md'):
return
now = time.time()
if now - self._last_sync < DEBOUNCE_SECONDS:
return # Debounce
self._last_sync = now
page = pathlib.Path(event.src_path).stem
print(f"Mudança detectada: {page} — sincronizando...")
subprocess.run(
["python", str(BRIDGE_SCRIPT), "--incremental"],
capture_output=True
)
print(f"Sync concluído para {page}")
if __name__ == "__main__":
observer = Observer()
observer.schedule(WikiChangeHandler(), str(WIKI_DIR), recursive=False)
observer.start()
print(f"Monitorando {WIKI_DIR}...")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
# Em background
nohup python watcher.py > \
~/.intelecto/watcher.log 2>&1 &
# Como serviço systemd (recomendado)
# Ver arquivo intelecto-watcher.service
- • Mudança no vault detectada: <1s
- • Debounce (evita duplicatas): 5s
- • Execução do bridge.py: <3s
- • Total: <10s do save ao SQLite
🎯 Exemplo Completo — Ponta a Ponta
Veja o sistema completo em ação: da leitura de um artigo à consulta de conhecimento pelo Telegram — o ciclo completo do segundo cérebro integrado.
Captura via Telegram
/ingere https://arxiv.org/abs/2024.12345 — artigo sobre otimização de BM25 para textos curtos
✅ Salvo em raw/raw-2026-01-15-1430.md com metadados. Execute /compilar para adicionar ao wiki.
Compilação pelo LLM
O pipeline de ingestão (Trilha 1) lê raw/raw-2026-01-15-1430.md e gera:
# wiki/bm25-short-text-optimization.md
---
tipo: pesquisa
relacionados: [[bm25]], [[intelecto-memoria]]
data: 2026-01-15
---
# BM25 para Textos Curtos — Otimizações
## Problema
BM25 padrão (k1=1.2, b=0.75) foi calibrado
para documentos longos. Para memórias curtas (<150 tokens)...
## Solução proposta
Reduzir k1 para 0.8-0.9 aumenta recall em 18-25%...
Watcher sincroniza automaticamente
# No terminal do watcher:
Mudança detectada: bm25-short-text-optimization — sincronizando...
Sync concluído para bm25-short-text-optimization
# SQLite agora tem a nova memória com source='vault'
Consulta enriquecida pelo Telegram
Devo mudar os parâmetros do BM25 no Intelecto?
Sim! Conforme sua pesquisa em [[bm25-short-text-optimization]] (15/jan): para as memórias curtas do Intelecto (~100 tokens), reduzir k1 de 1.2 para 0.9 melhora o recall em ~23%. Quer que eu mostre como alterar no código?
✅ Resumo do Módulo 5.3
Próximo Módulo:
5.4 — Telegram como Interface do Segundo Cérebro: design de captura, comandos customizados, arquivos multi-modal e notificações proativas.