Uma arquitetura aberta, portátil e governada para criar uma base de contexto que qualquer agente possa consultar, sem virar dono dela.
A v2 vendia o Hermes como núcleo ativo com quatro papéis (roteador, gerenciador de memória, controlador de escopo, policy engine). O teste de campo e a documentação oficial do Hermes mostraram que aquele desenho não existia: o Hermes nunca foi orquestrador, é cliente. A v3 reposiciona. Memória é arquivo passivo, agente cliente é peça intercambiável, Git é a espinha que unifica versionamento e sincronização. Governança em dois modos declarados: cooperativo (contrato, o piso recomendado) e adversarial (enforcement por isolamento de sistema operacional, abaixo do agente). Captura por hooks do próprio agente (PostToolUse rodando scripts/capture-to-inbox.mjs), depositando em /90-inbox/. Auditoria risk-proportional: verified + low promove sozinho por TTL; hipóteses e high risk exigem decisão humana. MCP e Graphiti viram camadas opcionais sob dor de volume, não componentes do piso.
Toda ferramenta de IA parece brilhante nos primeiros minutos. Entende o pedido, escreve código, sugere campanha, resume reunião e até parece que acompanhou o projeto desde o começo. O problema aparece na segunda, terceira ou décima sessão: a IA esquece decisões, mistura contexto, repete perguntas e precisa ser reeducada o tempo inteiro.
A reação natural é construir um "super cérebro": jogar tudo num lugar só e mandar o agente ler. No começo, isso parece resolver. Depois, o sistema degrada. Uma tarefa de marketing puxa vício de programação. Um projeto contamina outro. Memórias antigas entram como se ainda fossem verdade. O agente sabe demais e, justamente por isso, começa a errar melhor.
Este guia propõe outro caminho: memória federada. Domínios separados, arquivos legíveis, contrato neutro, pacotes de contexto e roteamento controlado. Não é fazer um agente dominar a casa. É criar uma base que qualquer agente possa consultar sem bagunçar o ambiente.
O vault Markdown guarda a memória revisada, com Git como espinha de versão e sincronização. Context Packs entregam o menor contexto suficiente. O contrato orienta a leitura. Os agentes executam como clientes intercambiáveis, sem precisar conversar entre si. MCP e Graphiti são evolução opcional, quando a dor aparece.
Implementação de referência usando um vault Markdown versionado em Git. A arquitetura, porém, não fica presa a ferramenta nenhuma. O objetivo é uma camada de memória portátil para qualquer agente atual ou futuro.
AGENT.md como contrato neutro, sem dependência de Claude Code, Codex, Cursor ou qualquer executor.CLAUDE.md, codex.md, regras de Cursor).Não é um produto fechado. Não é um framework que precisa controlar todos os projetos. Não é uma proposta de memória automática sem revisão. A memória permanente precisa passar por curadoria humana.
Antes dos princípios, separe três camadas, porque confundi-las é o erro mais comum: o modelo (o LLM que raciocina), o agente de código (Claude Code, Cursor, Codex, Hermes, que roda o loop e mexe nos arquivos) e a memória (a base persistente e soberana, que não pertence a nenhum dos dois). A arquitetura federada existe para manter a memória fora do agente.
Memória soberana. A base pertence ao usuário. Agentes entram e saem; o contexto continua portátil. O Git é a espinha: o vault é um repositório, o que entrega versão, autoria, diff e sincronização entre máquinas numa peça só.
Domínios isolados. Marketing, programação, clientes, produtos e pesquisa não devem viver no mesmo caldo semântico. O isolamento é estrutural, por pastas, não uma instrução que o agente pode ignorar.
Contrato neutro. O AGENT.md descreve como qualquer agente deve consumir a memória. Adaptadores apenas traduzem para ferramentas específicas. Nenhum agente é o núcleo; todos são clientes intercambiáveis.
Contexto mínimo suficiente. O agente deve receber o necessário para a tarefa, não a história inteira da sua vida digital.
Humano como auditor proporcional ao risco. A captura é automática; a aprovação não é obrigatória para tudo. Entradas verificadas de baixo risco promovem sozinhas com TTL; hipóteses e alto risco exigem decisão humana. O humano é filtro de qualidade, não gargalo de captura.
Governança em dois modos. No modo cooperativo, que é o padrão, a regra vive no contrato e na estrutura, e basta. Contra um agente que pode ser hostil, contrato não basta: o enforcement vem do sistema operacional, abaixo do agente (container read-only exceto no inbox, ou usuário separado). Nunca de um núcleo do lado do agente.
Uma confusão comum em arquiteturas multi-agente é assumir que os agentes precisam falar entre si. Não precisam. Numa memória federada bem desenhada, a coordenação é assíncrona via estado compartilhado. Esse padrão tem nome: blackboard architecture.
Pense no quadro-negro de uma sala de aula. Diferentes pessoas escrevem nele em momentos diferentes. Quem entra depois lê o que está lá. Ninguém precisa estar presente quando outro escreveu. A coordenação acontece através do quadro.
Implicações práticas dessa escolha:
Quando você usar Claude Code de manhã e Codex à noite, o que muda é só o executor. A memória curada é a mesma. O agente da noite lê o que ficou aprovado pela manhã. Sem orquestração em tempo real. Sem fila de mensagens. Sem broker.
| Componente | Função | Substituível por |
|---|---|---|
| Obsidian | Base revisada por humano em Markdown | Logseq, Foam, repositório Git puro |
| Vaults / pastas | Isolam domínios e reduzem contaminação | Subpastas no mesmo vault |
| AGENT.md | Contrato neutro de consumo | Não. É o núcleo da portabilidade. |
| Context Packs | Contexto mínimo por tarefa | RAG curado, prompts modulares |
| Adaptadores | Tradução do contrato para a ferramenta | Específicos de cada agente |
| Git | Versão, autoria e sincronização do vault | Essencial. Sem substituto que entregue tudo junto. |
| MCP server | Acesso padronizado multi-agente | Leitura direta, CLI, API REST |
| Graphiti | Memória temporal e relações | Adicionar apenas quando doer |
Obsidian é a base porque trabalha bem com Markdown, links, backlinks, tags e navegação humana. A v2 do template usa onze pastas com prefixo numérico, otimizadas para leitura direta pelos agentes clientes e para crescer sem virar bagunça.
Neste guia, usamos "vaults" no sentido de domínios de memória. A implementação padrão usa um único vault Obsidian com pastas separadas por domínio. Quando houver necessidade de isolamento forte, segurança ou compartilhamento seletivo, esses domínios podem ser promovidos para vaults físicos separados.
/federated-memory
├── 00-global/ # contrato AGENT.md, regras gerais
│
├── 10-projects/ # projetos ativos (começo, meio, fim)
│ └── project-a/
│ ├── PROJECT.md
│ ├── notes/
│ └── deliverables/
│
├── 20-domains/ # domínios estáveis (engineering, writing, research...)
│ ├── engineering/
│ ├── writing/
│ └── research/
│
├── 30-clients/ # clientes, candidato a vault físico separado
│ └── <cliente>/
│
├── 40-workflows/ # fluxos repetíveis (release, incident, review...)
│
├── 50-skills/ # capacidades reutilizáveis
│
├── 60-context-packs/ # pacotes de contexto por tarefa
│ ├── linkedin-writing.md
│ ├── code-review.md
│ ├── research.md
│ └── planning.md
│
├── 70-decisions/ # decisões formais com status approved/superseded
│
├── 80-agent-adapters/ # adaptadores por agente
│ ├── claude/{CLAUDE.md, AGENTS.md}
│ ├── cursor/.cursorrules
│ ├── codex/AGENTS.md
│ └── windsurf/.windsurfrules
│
├── 90-inbox/ # sugestões pendentes de revisão humana
│ └── suggested-memory.md
│
└── 99-archive/ # logs, packs obsoletos, arquivados
├── review-log.md
├── pack-usage.log
└── pack-status.md
Critério objetivo: crie um domínio quando houver vocabulário, decisões ou estilo de saída que NÃO devem aparecer na resposta de outro domínio. Se "writing" usa "voz, hook, lead" e "engineering" usa "stack, latency, deploy", e cruzar isso confunde o agente, são dois domínios. Se duas áreas usam o mesmo vocabulário e tomam decisões compatíveis, é uma pasta dentro de um único domínio, não um domínio novo.
Quando há requisito de isolamento contratual (NDA, dados sensíveis de cliente), sincronização independente (uma conta de cloud diferente), ou compartilhamento seletivo de leitura sem expor o resto. O caso típico é 30-clients/.
Quando você ainda está começando, quando os domínios trocam contexto frequentemente, ou quando você é uma pessoa só usando uma máquina só. Comece com pastas no mesmo vault; promova depois se a dor justificar.
O vault é Markdown por padrão. Mas o suporte multimodal não exige mudar a arquitetura, exige apenas uma convenção de onde os assets ficam e como são referenciados.
Suporte multimodal é uma capacidade do LLM configurado no agente, não do agente em si. O agente passa o arquivo, o LLM processa. Verifique a documentação atualizada do provider:
Todos os principais LLMs hoje suportam ao menos imagem e PDF. Áudio e vídeo variam por provider.
Estrutura de assets no vault:
/federated-memory
/20-domains/
/engineering/
/assets/
arquitetura-v2.png
decisao-banco.pdf
/writing/
/assets/
exemplos-visuais/
/10-projects/
/project-a/
/assets/
wireframes/
screenshots/
bugs/
bug-001/
screenshot-erro.png
tentativa-01-failed.md
tentativa-02-success.md
Regra de referência no Markdown: todo asset é referenciado no arquivo .md do mesmo domínio ou projeto. O Context Pack aponta para o .md. O agente carrega o asset quando o .md o referencia.
Exemplo em um DECISION.md:
Diagrama de referência: ./assets/arquitetura-v2.png
O agente deve carregar esta imagem ao analisar decisões de stack.
Vídeos, datasets e arquivos acima de 10MB não devem ficar no vault. Referencie por URL ou caminho externo. O vault deve permanecer leve e versionável.
O AGENT.md não é um prompt gigante. É o contrato que ensina qualquer agente a consumir a memória sem bagunçar tudo. Fica em 00-global/AGENT.md.
# AGENT.md
Purpose:
This repository contains the federated memory used by AI agents.
The memory is owned by the human user. Agents are consumers,
not owners.
Rules:
1. Do not load the entire memory base.
2. Start from the relevant Context Pack in /60-context-packs/.
3. If no Context Pack exists, ask which domain is relevant.
4. Permanent writes are forbidden outside /90-inbox/ in any
execution mode (interactive, headless, scheduled).
5. Memory conflicts: the most recent entry with status: approved
wins. Entries with status: superseded stay in history but are
ignored at runtime. Never infer winner by file timestamp alone.
6. When unsure, create a suggested memory entry in
/90-inbox/suggested-memory.md instead of guessing.
Folders:
- 00-global, 10-projects, 20-domains, 30-clients, 40-workflows,
50-skills, 60-context-packs, 70-decisions, 80-agent-adapters,
90-inbox, 99-archive
Decision frontmatter (in /70-decisions/):
- id, date, status (approved | superseded | pending), supersedes,
domain, owner
O Hermes Agent carrega arquivos de contexto como AGENTS.md e .hermes.md ao montar o system prompt. Se você coloca seu AGENT.md no caminho que o Hermes lê, ou o referencia a partir do AGENTS.md dele, suas regras passam a valer automaticamente.
O AGENT.md define como o agente se comporta. O RULES.md define as regras de negócio e de stack que valem para todos os projetos. São dois arquivos distintos com responsabilidades distintas: comportamento do agente versus padrões do desenvolvedor e da empresa.
Crie 00-global/RULES.md com dois blocos:
# RULES.md
# Regras globais, valem para todos os projetos.
# Para sobrescrever uma regra em projeto específico,
# registre um override em 70-decisions/ do projeto.
## Company Rules
- stack: TypeScript, nunca MongoDB
- testes: TDD obrigatório
- segurança: nunca commitar secrets, usar variáveis de ambiente
## Dev Rules
- commits: inglês, imperativo, máximo 72 caracteres
- PR: nunca maior que 400 linhas
- revisão: auto-review antes de abrir PR
O agente carrega o RULES.md em toda sessão, logo após o AGENT.md. Isso já está instruído no AGENT.md via seção ## Global Rules.
Quando um projeto precisa sair de uma regra global, o desvio é registrado em 70-decisions/ do projeto, com campos obrigatórios. Não se altera o RULES.md.
---
id: DEC-OVERRIDE-001
date: 2026-06-01
approved-by: André
status: approved
rule-override: company/stack/mongodb
---
# Override: uso de MongoDB no projeto X
## Razão
Cliente exige MongoDB por contrato. Migração planejada para Q3 2027.
## Escopo
Válido apenas para este projeto. Não altera RULES.md.
## Revisão
review_date: 2026-12-01
O agente aplica as regras nesta ordem: Company Rules (mais amplas, mais estáveis) > Dev Rules > Regras do projeto. Um override aprovado em 70-decisions/ tem precedência sobre o RULES.md. O agente executa sem questionar, o desvio já foi decidido e está documentado.
Cada agente tem sua própria convenção de arquivo de contexto. O adaptador é curto. Ele não substitui o AGENT.md. Ele apenas aponta.
Exemplo de adaptador para Claude Code:
# CLAUDE.md
Read the shared memory protocol at:
../00-global/AGENT.md
For this project, start with:
../10-projects/project-a/PROJECT_CONTEXT.md
Use Context Packs before reading raw notes:
../60-context-packs/architecture-review.md
Do not modify permanent memory directly.
If a new memory seems useful, write a suggestion to:
../90-inbox/suggested-memory.md
Sem Context Pack, o agente precisa fuçar o vault. Com Context Pack, ele recebe um pacote enxuto, orientado à tarefa. Reduz ruído, melhora consistência, evita contaminação entre domínios.
linkedin-writing.md# Context Pack: linkedin-writing
Goal:
Help an AI agent draft LinkedIn posts in André's voice for
the technology and AI community.
Use:
- /20-domains/writing/STYLE_GUIDE.md
- /20-domains/writing/voice-examples/*.md
- /20-domains/writing/hooks-that-worked.md
- Last 5 entries from /20-domains/writing/recent-posts.md
Avoid:
- /20-domains/engineering/* (different vocabulary)
- /10-projects/* (unless explicitly mentioned)
- Generic LinkedIn templates from external sources
- Em dashes (—). Never. Forbidden.
Sources of truth:
- Voice: informal, irreverent, Brazilian Portuguese
- Structure: strong opening hook, conclusion-first
- Length: 800-1500 characters
- Tone: critical, myth-busting, no flattery
Output expected:
- Single post, ready to publish
- No subtitle or headers inside the post
- No hashtag list at the end unless requested
- No em dashes under any circumstance
Confidence / validity:
- Style guide reviewed monthly. Last update: see file metadata.
- Voice examples should not be older than 90 days.
Source notes:
- /20-domains/writing/STYLE_GUIDE.md
- /20-domains/writing/hooks-that-worked.md
Cada Context Pack v2 inclui o campo Validation:. O agente cliente registra cada uso em /99-archive/pack-usage.log via hook de pós-execução com resultado classificado (útil / parcial / ruim); três marcações ruins consecutivas flaggam o pack pra revisão. Adicionalmente, ao montar o pack, um hook inspeciona o mtime dos arquivos listados em Use:, se algum estiver com mais de 90 dias (default, configurável por pack), o output ganha um aviso de validade temporal. Pacote ruim tem meia-vida finita; conteúdo antigo merece checagem antes de virar base de decisão nova.
A v1 e a v2 deste guia chamaram o Hermes de núcleo: primeiro "orquestrador leve", depois "núcleo ativo com quatro papéis". Teste de campo e a documentação oficial do Hermes mostraram que esse núcleo não existe como descrito. O Hermes é um agente de código completo, com memória própria, não um porteiro que medeia outros agentes. Esta seção corrige isso.
Separe três camadas, porque confundi-las é o erro mais comum: o modelo (o LLM que raciocina), o agente de código (Claude Code, Cursor, Codex, Hermes, que roda o loop e mexe nos arquivos) e a memória federada (o vault Markdown, passivo e soberano).
A memória é passiva. Ela não roteia, não aplica política, não medeia nada. Os agentes de código são clientes intercambiáveis que leem e escrevem no vault guiados pelo AGENT.md e pela estrutura de pastas. O Hermes é um deles. Nenhum é o núcleo. As quatro funções que a v2 atribuía a um núcleo continuam acontecendo, mas em outro lugar.
O agente puxa o que precisa, guiado pelo contrato e por arquivos estáticos versionados. Não há roteador central decidindo por ele.
A regra de conflito não está num componente, está nos arquivos. Vence a entrada mais recente com status: approved; superseded fica no histórico e é ignorada em runtime. Qualquer agente que leia o vault aplica a mesma regra, porque ela vive no dado.
# Exemplo de decisão em /70-decisions/
---
id: db-engine-postgres
date: 2026-03-15
status: approved
supersedes: [db-engine-mysql]
domain: engineering
owner: andre
---
# Decisão: PostgreSQL como banco principal
## Contexto
MySQL não suporta os recursos de JSONB e CTEs recursivas que
precisamos. Avaliamos a migração há 2 meses.
## Decisão
Postgres 16 como banco principal a partir de 2026-Q2.
A decisão antiga com id: db-engine-mysql ganha status: superseded e fica no histórico. Qualquer agente que monte um Context Pack de engineering ignora ela, sem precisar de um núcleo para isso.
O logging de uso de pack e a captura de memória vêm de hooks do agente cliente, agnósticos de ferramenta (seção 09c), não de um gerenciador central. A captura por hooks é o caminho principal, não uma alternativa ao Hermes.
No modo cooperativo, a política de escrita é o contrato: leitura liberada, escrita permanente fora de /90-inbox/ convertida em sugestão. Não existe um hermes.policy.yml com triggers semânticos; isso foi invenção do posicionamento antigo. Enforcement de verdade, contra um agente hostil, vem do sistema operacional, abaixo do agente: container com mount read-only exceto no inbox, ou usuário separado sem escrita nas pastas protegidas.
Memória passiva não é fraqueza, é a condição da soberania. Um vault que precisa de um núcleo ativo está amarrado a esse núcleo. Um vault que é só arquivos versionados em Git pertence ao usuário e funciona com qualquer agente. Quando enforcement é necessário, ele vem do sistema operacional, nunca do lado do agente.
O maior gargalo de curadoria é lembrar de pedir ao agente para salvar algo importante. A captura automática resolve isso com hooks do próprio agente de código, independentes de qualquer núcleo central. Como o Claude Code é um dos clientes da arquitetura, ele serve de exemplo concreto, mas o mesmo padrão vale para qualquer agente que exponha hooks de ciclo de vida.
O hook PostToolUse dispara depois de uma chamada de ferramenta e passa o contexto do evento, via stdin, para um script. O script aplica heurísticas simples para identificar padrões relevantes (decisão tomada, bug resolvido, preferência identificada) e anexa uma sugestão classificada em /90-inbox/suggested-memory.md. O humano não precisa pedir: o inbox se alimenta sozinho, e a aprovação humana permanece como filtro de qualidade proporcional ao risco.
Os hooks do Claude Code são declarados em .claude/settings.json, sob a chave hooks, o mesmo arquivo que guarda as permissões. Não existe um .claude/hooks.json separado. No template do vault, adicione o bloco de hooks ao template/.claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "node scripts/capture-to-inbox.mjs"
}
]
}
]
}
}
O matcher usa regex sobre o nome da ferramenta; .* dispara após qualquer chamada.
O script scripts/capture-to-inbox.mjs usa heurísticas simples (regex sobre strings comuns) para identificar três padrões:
confidence: verified, risk: mediumconfidence: preference, risk: lowconfidence: verified, risk: lowSe nenhum padrão for encontrado, o script não faz nada. Não há dependências externas além do Node.js. O ritual de revisão (scripts/review-inbox.{sh,ps1}) processa o que o hook gravou, com TTL para verified+low e filtro por risco.
Captura automática não elimina curadoria humana. Elimina o gargalo de lembrar de pedir. O inbox cresce sozinho. O ritual de review continua sendo o mecanismo de controle de qualidade, proporcional ao risco, não obrigatório para tudo.
A instalação que importa é a do vault: uma pasta Markdown que vira repositório Git, com o AGENT.md e a estrutura de pastas. Isso está no passo a passo da seção 14 e não depende de agente nenhum. Os agentes de código (Claude Code, Cursor, Codex, Hermes) são clientes intercambiáveis que você aponta para esse vault. Esta seção mostra como conectar um cliente, usando o Hermes como exemplo porque ele lê o contrato nativamente. O mesmo princípio vale para os outros, via adaptadores (seção 08).
Hermes Agent é o framework do NousResearch. Tem loop de conversação, chamada de ferramentas, memória própria e deployment em CLI, Telegram, Discord, WhatsApp e editores via Agent Client Protocol. O que o torna um cliente conveniente para esta arquitetura é que ele já lê arquivos como AGENTS.md, SOUL.md e MEMORY.md ao montar o prompt do sistema, então o contrato federado entra sem código glue. Note que a memória própria do Hermes (MEMORY.md) é dele, não do vault: ela compete com a memória soberana se você deixar. O objetivo é apontar o Hermes para o vault, não deixar o vault virar memória interna do Hermes.
# clone e setup
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
python -m venv .venv
source .venv/bin/activate
pip install -e .
# rodar a partir do vault, para que ele leia o contrato
cd /caminho/do/seu/federated-memory
hermes
O Hermes lê arquivos de contexto do diretório de trabalho. Rode o Hermes a partir da raiz do vault e deixe um AGENTS.md lá, que aponta para o seu contrato em 00-global/AGENT.md:
# AGENTS.md (raiz do vault, lido automaticamente pelo Hermes)
This is a federated memory base. Read the consumption protocol
before doing anything:
00-global/AGENT.md
Before responding to any task:
1. Identify the domain (writing, engineering, automation, etc).
2. Load the corresponding Context Pack from /60-context-packs/.
3. Never write to /00-global/ or /20-domains/ without explicit
human approval.
4. New memory suggestions go to /90-inbox/suggested-memory.md.
Para alimentar o inbox sem ação manual, use a captura por hooks do agente cliente, descrita na seção 09c. No Claude Code isso é um hook PostToolUse em .claude/settings.json. Em qualquer cliente, o princípio é o mesmo: um script que grava sugestões em /90-inbox/suggested-memory.md, nunca direto na memória aprovada. Você não precisa de nada além disso para começar.
O cliente pode escolher e carregar contexto. O cliente não decide sozinho o que vira verdade permanente. Escrita permanente fora de /90-inbox/ é sugestão, não gravação. Se o cliente pode ser hostil, isso não se garante por contrato: garante-se por isolamento de sistema operacional (seção 09b).
O MCP server é opcional. O agente cliente já lê os Markdown direto pelo filesystem, e o piso recomendado (seção 05 do whitepaper) não exige MCP. Ele entra quando vários agentes externos (Claude Desktop, Cursor, outros clientes MCP) precisam consultar a mesma base sem cada um implementar seu próprio leitor, expondo o vault via uma camada padronizada. Existem duas abordagens prontas pela comunidade.
Instala o plugin "Local REST API" no Obsidian. O plugin sobe um endpoint HTTP local. Um MCP server se conecta a esse endpoint e expõe ferramentas padronizadas.
Ferramentas típicas expostas:
list_vault_files, lista arquivos do vaultsearch_vault, busca por conteúdocreate_vault_file, cria arquivo (use com restrição em /90-inbox/)read_vault_file, lê um arquivo específicoVantagem. Mais confiável que apontar o agente direto pra um diretório, porque as ferramentas são pré-definidas. Desvantagem. Exige Obsidian aberto.
Implementações como obsidian-mcp-server acessam o vault direto no filesystem, sem precisar do Obsidian rodando. Funciona com o app fechado, em servidor, ou via SSH.
Vantagem. Independente do app. Desvantagem. Não tem acesso a recursos do Obsidian (Dataview, plugins, links resolvidos), só ao Markdown puro.
{
"mcpServers": {
"obsidian-memory": {
"command": "node",
"args": [
"/caminho/para/obsidian-mcp-server/build/index.js",
"/caminho/para/federated-memory"
]
}
}
}
Expor memória como ferramenta também expõe risco. Configure permissões de escrita apenas para /90-inbox/. As pastas /00-global/, /20-domains/ e /10-projects/ devem ser read-only para qualquer agente. Interoperabilidade sem governança vira superfície de ataque.
O agente nunca grava memória permanente. Quando identifica algo que merece virar verdade, escreve uma sugestão no inbox. O humano revisa, aprova, edita ou rejeita. Só depois disso a memória entra na base estável.
Até aqui tudo roda local. Isso funciona bem para uma máquina. Quando você precisa que dois ou mais agentes, em máquinas diferentes, acessem o mesmo vault, a arquitetura precisa de um ponto central. Esse ponto é uma VPS.
A boa notícia: a separação de responsabilidades da memória federada já resolve metade do problema. O vault é só arquivos. O MCP server é só um processo. Mover para um servidor remoto não muda os contratos, só muda onde os processos rodam.
| Componente | Onde roda | Motivo |
|---|---|---|
| Vault (arquivos markdown) | VPS | Fonte única de verdade. Sem conflito de versão. |
| MCP Server | VPS (porta local) | Nunca exposto diretamente. Acesso via tunnel. |
| Hermes Agent | VPS ou local | Se rodar na VPS, sem latência de transferência. |
| Claude Code | Máquina local | Interface do humano. Conecta via SSH tunnel. |
| Git remote | GitHub | Sincronização e histórico. Não é o vault primário. |
O vault é um repositório Git normal. Cada máquina que precisa de uma cópia local faz clone e pull. A VPS é o origin.
# Na VPS, configuração inicial
git init --bare /vault-remote.git
# No vault local, apontar para a VPS como origin
git remote add origin ssh://usuario@sua-vps:/vault-remote.git
git push -u origin main
# Em outra máquina, clonar o vault
git clone ssh://usuario@sua-vps:/vault-remote.git ~/vault
# Rotina de sincronização (antes de trabalhar)
git pull origin main
# Depois de aprovações no inbox
git add 00-global/ 10-projects/ 20-domains/ 60-context-packs/
git commit -m "feat: memória aprovada, [domínio]"
git push origin main
Rode git log --oneline -5 na VPS e em outra máquina. Os hashes devem ser idênticos. Se não forem, tem divergência, resolva antes de continuar.
O MCP server não deve ser exposto diretamente na internet. Duas opções:
O MCP roda em localhost na VPS. Você cria um tunnel que mapeia a porta local para a sua máquina.
# Cria tunnel: porta 3000 da VPS aparece como localhost:3000 na sua máquina
ssh -L 3000:localhost:3000 usuario@sua-vps -N
# Para manter em background
ssh -L 3000:localhost:3000 usuario@sua-vps -fN
# Para fechar
kill $(lsof -t -i:3000)
Com o tunnel ativo, o Claude Code enxerga o MCP remoto como se fosse local. Nenhuma configuração adicional.
Se mais de uma máquina precisa acessar o MCP simultaneamente, coloque um reverse proxy (nginx ou Caddy) na frente com TLS e autenticação básica.
# Caddy, configuração mínima (~/.caddy/Caddyfile)
mcp.seudominio.com {
basicauth /* {
agente $2a$14$HASH_GERADO_COM_caddy_hash
}
reverse_proxy localhost:3000
}
Não exponha o MCP server diretamente na porta pública sem autenticação. O MCP tem acesso de leitura (e escrita no inbox) ao vault inteiro. Um endpoint aberto é um vault aberto.
Com o SSH tunnel ativo, o Claude Code não sabe que está falando com um servidor remoto. Configure normalmente apontando para localhost.
# .claude/settings.json (na máquina local)
{
"mcpServers": {
"obsidian-vault": {
"command": "npx",
"args": ["-y", "mcp-obsidian"],
"env": {
"OBSIDIAN_API_URL": "http://localhost:3000",
"OBSIDIAN_API_KEY": "seu-token-aqui"
}
}
}
}
Critério de conclusão: rode /mcp no Claude Code e veja o servidor listado como conectado. Peça para o agente ler um arquivo do vault. Se vier, o tunnel está funcionando.
| O que proteger | Como |
|---|---|
| Acesso SSH à VPS | Chave SSH obrigatória. Desabilitar login por senha (PasswordAuthentication no no sshd_config). |
| Token do MCP server | Variável de ambiente, nunca hardcoded. Usar .env fora do vault. |
| Escrita no vault | MCP server com permissão de escrita restrita a /90-inbox/. Vault principal read-only para o agente. |
| Vault no Git | Repositório privado. Checar .gitignore para não commitar .env ou tokens. |
| Porta do MCP | Nunca aberta no firewall da VPS. Só acessível via tunnel ou proxy autenticado. |
# Verificar que a porta 3000 NÃO está exposta publicamente
# Na VPS:
ss -tlnp | grep 3000
# Deve mostrar: 127.0.0.1:3000, se mostrar 0.0.0.0:3000, feche no firewall
# UFW (Ubuntu)
ufw deny 3000
ufw allow 22 # SSH continua aberto
Harness Engineering é a disciplina de conectar o agente ao ambiente de forma controlada: quais ferramentas ele pode usar, como o output é capturado, como falhas são tratadas. Na memória federada, o harness não é uma peça separada. Está distribuído pela arquitetura.
| Componente | Função de harness |
|---|---|
MCP server (opcional) | Quando presente, expõe ferramentas ao agente de forma padronizada. Sem ele, o agente lê os arquivos direto e o contrato mais os hooks fazem o trabalho |
AGENT.md | Define regras de comportamento (harness declarativo), o agente lê e aplica antes de qualquer ação |
| Adaptadores | Traduzem o contrato neutro do AGENT.md para cada agente específico (Claude, Cursor, Windsurf...) |
capture-to-inbox.mjs | Captura output do agente via PostToolUse hook, preenche o inbox automaticamente sem intervenção manual |
SESSION.lock | Controla acesso concorrente por projeto, identifica agente, máquina e usuário em cada sessão |
review-inbox | Processa o que o agente produziu e decide o destino, audit trail completo em /99-archive/review-log.md |
/90-inbox/, com hardening por OS no modo adversarial (seção 09b)SESSION.lock)session-log.md (quem fez o quê, quando) e review-log.md (o que foi promovido ou rejeitado)/30-clients/ acessa apenas ferramentas de cliente; agente em /20-domains/engineering/ acessa apenas ferramentas de código. A camada de acesso (filesystem direto ou MCP, se em uso) expõe conjuntos diferentes dependendo do contexto de entrada.É sobre tornar o ambiente previsível o suficiente para que o agente seja confiável. Regras claras produzem comportamento consistente. Um agente num ambiente ambíguo não é mais capaz do que um agente num ambiente bem definido, só é menos previsível.
À medida que você adiciona agentes especializados ao ecossistema, surge um novo problema: cada agente aprende coisas úteis, cria skills, escreve playbooks, toma decisões técnicas. Se esse conhecimento fica isolado na memória privada de cada agente, os outros redescobrirão a roda indefinidamente.
A mente de colmeia resolve isso com uma camada federada de leitura e descoberta de conhecimento entre agentes. Cada agente pode consultar o que outros publicaram, sem ter acesso à memória privada de ninguém.
| Nível | Onde | Quem acessa | O que contém |
|---|---|---|---|
| Memória privada | ~/.hermes/ ou equivalente interno | Só o próprio agente | Aprendizados de sessão, preferências operacionais, histórico interno |
| Conhecimento publicado | /50-skills/published/ | Qualquer agente via MCP (leitura) | Skills, playbooks, templates, padrões aprovados ou promovidos por TTL |
| Conhecimento aprovado | /70-decisions/ e /20-domains/ | Qualquer agente via MCP (leitura) | Decisões formais, princípios de domínio, regras globais |
/50-skills/INDEX.md, busque por tag ou domínio para evitar duplicação/90-inbox/ com type: skill e metadados completos (author_agent, domain, confidence, risk, tags)confidence + risk:
verified + low → promovido automaticamente para /published/ em 7 diasverified + medium → aprovação lazy do humanohypothesis → fica em /proposed/ aguardando decisão humanahigh risk → aprovação explícita obrigatória/90-inbox/supersedesINDEX.md é consultado antes de qualquer criação nova50-skills/
INDEX.md # índice navegável por domínio e agente
README.md # protocolo, metadados obrigatórios, regras
published/ # skills aprovadas, read-only para agentes
proposed/ # skills pendentes de revisão
deprecated/ # skills antigas, nunca deletar, manter rastreabilidade
É conhecimento acumulado que qualquer agente pode descobrir e reutilizar. O vault federado é o quadro compartilhado. O blackboard pattern em escala, não como memória em tempo real, mas como repositório de aprendizado persistente.
Toda ferramenta tem comportamentos não-documentados, bugs conhecidos e workarounds que você descobre na prática. Sem memória estruturada, o agente repete o mesmo diagnóstico a cada sessão, e você paga o custo em tempo e frustração. Pior: o workaround que você descobriu num projeto não chega ao próximo.
A solução: um ledger de padrões por ferramenta em /50-skills/tool-patterns/, separado do contexto de projeto e de cliente. O que o agente aprende sobre o Brandcraft num projeto vale para todos os outros.
| Tier | Ocorrência | Status | O que acontece |
|---|---|---|---|
| 1 | 1ª vez | observed |
Agente registra sintoma no inbox com type: tool_pattern. Problema documentado, workaround opcional. |
| 2 | 2ª vez | auto_fix |
Agente encontra o padrão em tool-patterns/ e aplica o fix documentado sem perguntar. |
| 3 | 3ª+ vez | root_cause_pending |
Trigger para análise de causa raiz. O problema é recorrente demais para ser apenas um workaround. |
A escalada é automática: node scripts/escalate-patterns.mjs lê o inbox, incrementa o contador e atualiza o status. Na 3ª ocorrência, o script alerta explicitamente que uma análise humana é necessária.
Essa é a distinção que torna o mecanismo útil. Memória de projeto fica em /10-projects/. Memória de cliente em /30-clients/. Padrões de ferramenta ficam em /50-skills/tool-patterns/, disponíveis para qualquer projeto, sem contaminar nenhum contexto específico.
50-skills/
├── published/ ← skills aprovadas (procedimentos)
├── proposed/ ← skills aguardando aprovação
├── deprecated/ ← histórico
├── tool-patterns/ ← ledger por ferramenta ← NOVO
│ ├── README.md
│ ├── brandcraft.md ← 1 arquivo por ferramenta
│ └── puppeteer.md
└── INDEX.md
---
type: tool_pattern
tool: brandcraft
symptom: API retorna rate limit em header não-padrão X-BrandCraft-Limit-Remaining
fix: verificar X-BrandCraft-Limit-Remaining antes de X-RateLimit-Remaining
confidence: verified
risk: low
---
node scripts/escalate-patterns.mjs cria tool-patterns/brandcraft.md com status: observed.tool-patterns/brandcraft.md, encontra status: auto_fix e aplica o fix documentado sem diagnóstico.root_cause_pending e alerta que o problema precisa ser resolvido na fonte, não só contornado.Não confundir com preferências do usuário (preference), fatos de projeto (fact) ou decisões formais (decision). Tool patterns são específicos de comportamentos de ferramentas externas, não de escolhas do usuário, não de contexto de negócio.
Porque o custo de intervenção deve escalar com a frequência. Na 1ª vez, o contexto ainda é raro, documentar é suficiente. Na 2ª vez, já é recorrente, automação é justificada. Na 3ª vez, é um padrão sistêmico, exige investigação da causa raiz, não mais um workaround.
Graphiti não substitui o Obsidian. Entra quando a memória deixa de ser apenas nota e passa a exigir histórico, relações, eventos e mudanças. Algumas memórias são fatos estáveis. Outras mudam com o tempo. Essa diferença é crítica.
Note que o Graphiti não duplica a memória: ele indexa o conteúdo do vault para responder perguntas temporais e relacionais que os arquivos sozinhos não respondem com eficiência. A fonte da verdade continua sendo o Markdown; o Graphiti é índice derivado, não substituto.
Casos em que Graphiti justifica o esforço:
Se sua memória é predominantemente fatos estáveis (estilo de escrita, princípios, padrões), Graphiti é overhead. Adicione quando perguntas temporais começarem a aparecer com frequência e você sentir que o Obsidian sozinho não responde.
Algumas features que você colocaria no Graphiti já existem em ferramentas focadas apenas em decisões. O DecisionNode (github.com/decisionnode/DecisionNode) é um exemplo: armazena decisões como JSON estruturado com embeddings vetoriais, expõe via CLI e MCP server, tem history tracking, soft-delete (deprecate/activate) e conflict detection automático por similaridade semântica.
É um sub-sistema, não uma alternativa à arquitetura federada. Ele resolve o módulo de decisões com busca semântica; não cobre Context Packs, domains, style guides ou project context. Mas se a sua dor for especificamente "os agentes não lembram de decisões de arquitetura tomadas na semana passada", DecisionNode pode resolver isso antes de você precisar subir o Graphiti inteiro.
Obsidian como base geral. DecisionNode para o sub-módulo de decisões estruturadas com busca semântica. Graphiti só quando você precisar de relações entre entidades e histórico de mudanças no nível de grafo temporal. Não precisa subir tudo de uma vez.
Os passos abaixo são sequenciais. Cada um tem critério de conclusão objetivo.
mkdir federated-memory
cd federated-memory
mkdir -p 00-global 10-projects 20-domains 30-clients 40-workflows \
50-skills 60-context-packs 70-decisions 80-agent-adapters \
90-inbox 99-archive
git init
Concluído quando: a estrutura de pastas existe e o repositório git está inicializado.
Copie o template da seção 07 para 00-global/AGENT.md e ajuste a lista de domínios para os seus.
Concluído quando: o arquivo existe, lista seus domínios reais, e você consegue explicar cada regra em voz alta.
Crie uma pasta para cada domínio em 20-domains/. Use o critério da seção 06: vocabulário próprio + saídas que não devem se misturar com outros.
Concluído quando: você tem entre 3 e 6 domínios. Mais que 8 é overhead. Menos que 3 quase nunca justifica memória federada.
Crie em 60-context-packs/:
writing-style.md, tarefas de escrita no seu estilocode-work.md, tarefas de código com convenções suasarchitecture-review.md, análise de arquiteturaUse o exemplo preenchido da seção 09 como modelo. Cada um deve caber em uma tela.
Concluído quando: os três packs existem, cada um tem objetivo, listas Use e Avoid, e o campo de validade temporal.
Se for Claude Code, crie 80-agent-adapters/claude/CLAUDE.md apontando para o AGENT.md e para um Context Pack default. Use o template da seção 08. Configure também o hook de captura em .claude/settings.json (PostToolUse rodando scripts/capture-to-inbox.mjs, conforme a seção 09c). Para outros clientes, o adaptador segue o mesmo princípio: apontar para o contrato e ligar um hook de captura agnóstico.
Concluído quando: você consegue rodar o agente no diretório do vault, ele lê o adaptador automaticamente, e ações relevantes geram sugestões em /90-inbox/suggested-memory.md sem intervenção manual.
Pule este passo se você não vai usar o Hermes. O piso dos passos 1 a 5 já é suficiente para um cliente único. Para conectar o Hermes como cliente adicional, use as instruções da seção 10 e adicione um AGENTS.md na raiz do vault que referencia o 00-global/AGENT.md.
Concluído quando: ao rodar hermes dentro do diretório, ele responde respeitando a regra "não carregar tudo" e usando os Context Packs.
Pule este passo se você não tem múltiplos agentes externos consumindo a mesma base. Caso precise, escolha entre Opção A (Local REST API) ou Opção B (filesystem direto) da seção 11. Configure no seu cliente MCP de preferência. Restrinja escrita a /90-inbox/.
Concluído quando: um agente externo (Claude Desktop, Cursor, ChatGPT com MCP) consulta seu vault e respeita os limites de escrita.
Faça a mesma tarefa em dois agentes diferentes consumindo a mesma memória. Verifique três coisas:
Concluído quando: as três respostas são "sim". Se uma delas for "não", o problema está no Context Pack, não no agente.
Só execute este passo quando você sentir dor temporal: decisões substituindo decisões, perguntas sobre histórico, validade de informação. Antes disso, é over-engineering.
O maior risco de memória persistente não é falta de informação. É excesso de informação com autoridade indevida. Toda arquitetura precisa separar conversa bruta, hipótese, rascunho e memória permanente.
/90-inbox/.Aprovação humana só funciona se houver um momento marcado para fazê-la. Sem ritual fixo, o /90-inbox/ vira lixeira: sugestões acumulam, nada vira memória, e os agentes seguem repetindo as mesmas perguntas. Reserve um bloco curto por semana, 20 a 40 minutos costuma bastar, para processar o inbox até zerar.
O repositório traz dois scripts equivalentes em /scripts/ que conduzem a revisão entrada a entrada:
# Linux / macOS
VAULT_PATH=/caminho/do/vault ./scripts/review-inbox.sh
# Windows (PowerShell)
$env:VAULT_PATH = 'C:\caminho\do\vault'
./scripts/review-inbox.ps1
Para cada sugestão pendente o script mostra o bloco e oferece quatro decisões:
Destino sugerido e remove do inbox.$EDITOR ou notepad), ajusta texto ou destino e volta a perguntar.Toda decisão, inclusive rejeições e adiamentos, é registrada em /99-archive/review-log.md com data, domínio, destino e resumo. Esse log é o que permite, semanas depois, ver quantas sugestões viraram memória, quantas foram descartadas e onde os agentes erram com mais frequência. Se a taxa de rejeição estiver alta, o problema não é o inbox: é a regra de captura do agente.
| Anti-pattern | Sintoma | Antídoto |
|---|---|---|
| Super cérebro único | Marketing puxa código, código puxa pesquisa, tudo mistura | Domínios isolados desde o dia um |
| Contexto sempre ativo | Agente lento, alucinação, respostas fora do escopo | Context Packs por tarefa |
| Memória automática sem revisão | Hipóteses viram fato, base degrada em semanas | Inbox obrigatório, aprovação humana |
| Adaptador como fonte principal | Trocar de ferramenta exige reescrever tudo | AGENT.md é a fonte, adaptador só traduz |
| Orquestrador poderoso cedo demais | Hermes/LangGraph fazendo coisa que ninguém entende | Começar com leitura direta, adicionar orquestração quando doer |
| MCP/API sem escopo | Qualquer agente escreve em qualquer pasta | Escrita apenas em /90-inbox/, resto read-only |
A implementação de referência usa um vault Markdown versionado em Git. A arquitetura, porém, foi pensada para ser portátil, e qualquer parte pode ser trocada sem mexer no contrato.
Alternativas ao Obsidian. Logseq, Foam, Dendron, VSCode com pastas Markdown, repositório Git puro. O requisito é ser legível, versionável e fácil de revisar por humano.
Outros agentes clientes. LangGraph para fluxos stateful com grafos explícitos, CrewAI para equipes de agentes por papel, Letta para agentes persistentes, Microsoft Agent Framework / AutoGen para multi-agente, Hermes. O requisito é classificar tarefa, escolher domínio, selecionar Context Pack e entregar contexto sem virar dono da memória.
Camada de acesso. Leitura direta de arquivos, CLI local, API REST. MCP é recomendado quando vários agentes precisam consumir a memória de modo padronizado.
Sincronização entre máquinas. Git resolve nativamente o sync entre máquinas: push em uma, pull em outra. Sync proprietário (iCloud, Dropbox, Notion) funciona, mas adiciona um intermediário que pode conflitar com o modelo de resolução do Git. O caminho recomendado é Git + repositório remoto.
Para o sub-módulo de decisões: DecisionNode. Se você quiser trocar os arquivos de /70-decisions/ por algo com busca semântica e histórico automático, o DecisionNode (github.com/decisionnode/DecisionNode) faz exatamente isso: decisões em JSON, embeddings via Gemini, busca por cosine similarity, MCP server pronto para Claude Code, Cursor e Windsurf, conflict detection, soft-delete reversível. O requisito para usar como substituto permanece o mesmo: não pode gravar memória permanente sem aprovação humana, e a regra de status: approved/superseded precisa ser respeitada. No DecisionNode, isso se traduz em configurar o agente em modo "strict" e revisar o que entra antes de ativar.
Existe uma categoria de projetos que adota a abordagem inversa da federada: concentrar memória, automação, integrações e agentes em um único aplicativo monolítico. São frequentemente chamados de "Personal AI", "Life OS" ou "super-app de produtividade". Eles vencem em superfície de uso: UI pronta, integrações empacotadas, comunidade visível, curva de adoção quase nula.
O custo aparece depois. A memória vive dentro do aplicativo, no formato do aplicativo. Trocar de ferramenta significa começar do zero. A arquitetura é, por design, centralizadora, exatamente o anti-pattern que motivou este guia. Não há contrato neutro; o adaptador é o produto. Não há mtime exposto; a verificação de validade temporal exige inspeção manual de mtime, o agente cliente, ou um hook, faz aqui o que o aplicativo não expõe. A regra de conflito é definida pela UI, não por arquivo auditável.
| Critério | Memória federada | Sistemas centralizadores / Life OS |
|---|---|---|
| Velocidade de adoção | Lenta, exige aprender o contrato | Rápida, instalou, conectou, usou |
| Portabilidade | Total (Markdown + Git) | Presa ao aplicativo |
| Soberania | Do usuário | Do produto |
| Validade temporal por inspeção | Sim (mtime de arquivo) | Não disponível |
| Custo de troca | Trocar adaptador | Recomeçar |
Para quem prioriza velocidade de adoção sobre soberania, o caminho centralizador é a escolha certa. Para quem prioriza portabilidade e governança, é o problema vestido de solução.
Você pode trocar ferramentas. Não pode trocar os princípios: domínio separado, contrato neutro, contexto enxuto, aprovação humana, política de escrita restrita a inbox, resolução determinística de conflito, portabilidade.
# Decision: [título curto]
Date: YYYY-MM-DD
Scope: [domínio ou projeto]
Status: proposed | approved | superseded | archived
Source: [conversa, reunião, documento]
Decision: [a decisão em uma frase]
Reason: [por que decidiu isso]
Impacts: [o que muda]
Supersedes: [link para decisão anterior, se houver]
Related context packs: [packs que devem refletir essa decisão]
# Project: [nome]
Goal: [o que esse projeto deve resolver]
Current status: [onde está agora]
Stack: [tecnologias, ferramentas]
Constraints: [limites técnicos, prazo, orçamento]
Important files: [caminhos relevantes]
Relevant domains: [quais domínios da memória se aplicam]
Relevant context packs: [quais packs usar]
Open questions: [o que ainda não foi decidido]
Do not use: [o que NÃO trazer para esse projeto]
# Memory Update Proposal
Source: [conversa, agente, documento]
Suggested domain: [domínio alvo]
Suggested memory type: fact | decision | preference | workflow | risk
Confidence: low | medium | high
Why this should become memory: [justificativa]
Proposed text: [o texto exato a virar memória]
Human decision: approved | edited | rejected
Reviewer: [nome]
Decision date: YYYY-MM-DD
AGENT.md claro e neutro, sem referência a ferramentas específicas?CLAUDE.md, codex.md, etc) está funcionando?AGENT.md ou adaptador) automaticamente ao iniciar?/90-inbox/, sem gravar memória permanente sozinho?/90-inbox/suggested-memory.md recebendo sugestões dos agentes?/00-global/ ou /20-domains/?/90-inbox/? (item opcional, o piso não exige MCP)As referências abaixo ancoram os componentes técnicos. O guia não depende de uma ferramenta específica, mas usa conceitos e padrões desses ecossistemas.
Memória persistente só é útil quando existe isolamento. Sem isolamento, o sistema fica grande, lento e confuso. Com domínios separados, contrato neutro, Context Packs e blackboard como padrão de coordenação, a memória vira infraestrutura. Não ruído acumulado.
Tese final. Não crie um super cérebro. Crie uma memória federada: humana na origem, segmentada por domínio, com contrato neutro como interface e Git como espinha. Os agentes clientes leem o contrato, escrevem no inbox e nunca viram donos da memória. Eles não precisam conversar entre si. O quadro compartilhado já é a coordenação.
Uma nota sobre convergência. Ferramentas como o DecisionNode, desenvolvidas independentemente, chegaram a conclusões parecidas com as deste guia: decisões estruturadas, multi-agente via MCP, histórico auditável, padrão blackboard implícito. Isso não é coincidência. É sinal de que o problema é real e que a direção arquitetural está certa. O mercado está convergindo para memória federada. Este guia tenta nomear o padrão antes que ele vire apenas feature de produto.
Memória Federada para Agentes de IA · Guia v3.0
André Almeida · andrealmeidadc.com