Sincronização de memória sem “a última gravação vence”

· 5 min de leitura

Duas máquinas, um conjunto de notas, uma delas editada enquanto a outra estava dormindo. Todo sistema de sincronização responde a isso, e a maioria responde com uma comparação de timestamps que descarta silenciosamente um dos lados. Isso serve para um rascunho que você pode redigitar. Não serve para o arquivo que um agente lê antes de cada turno, porque o que ele descarta é a linha que você escreveu para impedir que algo aconteça de novo.

Por isso a sincronização de memória do OHarness não tem nenhum caminho de “a última gravação vence”. Existe a reconciliação de três vias e, onde ela não consegue decidir, um conflito que espera por você.

Local primeiro, e só local se você quiser

As notas ficam em <project>/.oharness/memory/*.md. Elas funcionam sem login, funcionam offline e são Markdown puro, que você pode editar em qualquer editor. Nada na nuvem é estrutural: a sincronização é um recurso em camada sobre arquivos que já estão completos sem ela.

Fazer login ativa a sincronização automática, detectada em cerca de quinze segundos enquanto o harness está rodando. A página Memória oferece desativá-la e sincronizar na hora. A desativação persiste entre reinícios do processo e novos logins, e bloqueia solicitações automáticas e manuais até você reativar — um interruptor que volta sozinho na próxima inicialização não é um interruptor.

Um limite honesto, declarado na documentação em vez de descoberto depois: desativar cancela as solicitações em andamento, mas dados que a nuvem já aceitou não podem ser retirados. Desativar impede o próximo envio; não apaga o que já está lá.

De três vias, não de duas

A reconciliação precisa de três estados, não de dois: o que está aqui, o que está lá e aquilo em que os dois lados concordaram pela última vez. Esse último é a linha de base, mantida em ~/.oharness/memory-sync/, e é ele que faz a diferença entre “estes são diferentes” e “este mudou”.

A partir daí os casos são triviais, e essa é a ideia:

  • sem mudança nos dois lados — ignorado, sem leitura, sem gravação
  • mudou em um lado — copiado para o outro
  • mudou nos dois lados — um conflito, exibido e deixado para você

Exclusões são tombstones, e não ausências, porque um arquivo ausente é indistinguível de um arquivo que ainda não chegou, e tratar o segundo como o primeiro é como um sistema de sincronização apaga o seu trabalho em uma rede lenta.

Do lado da nuvem, o R2 guarda revisões imutáveis em Markdown mais um manifesto que é substituído atomicamente:

users/<server-verified-user-id>/projects/<project-id>/memory/
  manifest.json
  objects/<note-id>/<revision-id>.md

As gravações do manifesto usam compare-and-swap com ETag, então uma atualização concorrente desatualizada é rejeitada em vez de aplicada. As revisões são imutáveis, então o lado perdedor de um conflito continua sendo um objeto que existe. E, quando o manifesto não mudou, só o manifesto é buscado — o caso comum, uma máquina que passou a tarde toda rodando sem nada para fazer, custa uma leitura pequena.

A identidade de um projeto é o commit raiz do Git, e é isso que permite que o mesmo projeto em dois clones, em dois caminhos diferentes, seja um só projeto. Projetos sem Git recorrem a um id baseado no caminho absoluto e, portanto, não são mapeados entre dispositivos automaticamente. É uma limitação real, e não uma aresta a ser disfarçada: a alternativa é uma heurística que de vez em quando mescla dois diretórios sem relação, e não existe versão boa dessa falha.

Cada diretório de memória local fica vinculado à primeira conta e à primeira origem de nuvem que o sincronizaram. Mudar qualquer uma delas pausa a sincronização e pede que você use um diretório separado. De propósito, não existe reatribuição com um clique, porque a versão com um clique dessa operação é a que envia as notas de uma pessoa para a conta de outra.

O que ela não é

Duas coisas sobre as quais vale ser direto.

Ela não tem criptografia de ponta a ponta. O R2 é privado e tudo passa por TLS, mas a nuvem consegue ler o conteúdo das notas. Se essa troca não serve para o que você anota, desative a sincronização e mantenha os arquivos locais, o que é uma configuração suportada, e não uma configuração degradada.

Só as notas de memória são sincronizadas. Não os logs de sessão, não os arquivos, não as credenciais e não o registro de auditoria de permissões — este último fica na máquina que tomou as decisões e é apagado junto com a sua sessão.

Também há limites, e eles são do tipo de primeira versão: 500 entradas de manifesto por projeto, incluindo tombstones, 128 KiB por corpo de nota, 2 MiB por snapshot serializado. Revisões antigas são mantidas; a coleta de lixo de revisões e tombstones ainda não foi implementada. Notas excluídas e versões perdedoras de conflitos têm backup em ~/.oharness/memory-backups/ e podem ser restauradas pelo editor, embora ainda não exista um navegador de backups.

Por que um plugin

A memória é um plugin de arquitetura embutido, e não um servidor MCP. Ela registra sua ferramenta, seu índice de system prompt por turno, sua página e seu sincronizador em segundo plano pelo mesmo PluginHost por onde passam os plugins de modelo, de ferramentas e de auditoria — e { "id": "memory", "enabled": false } em plugins.json remove os quatro.

Esse é o teste em que um sistema de plugins passa ou é reprovado. Se os recursos que vêm de fábrica chegam ao runtime por uma porta privada, a porta pública é decoração, e todo mundo que desenvolve para ela descobre isso aos poucos. A extensão de páginas continua pequena pelo mesmo motivo: descritores registrados e renderizadores controlados pelo host, e não JavaScript de frontend arbitrário nem um SDK de iframe. Uma superfície que pode fazer qualquer coisa é uma superfície que ninguém consegue mudar depois.


O OHarness é um harness de agentes open source, sob licença MIT. A referência de memória e sincronização documenta por completo as regras de conflito, a estrutura de armazenamento e os limites de configuração, e o servidor de sincronização auto-hospedado explica como rodar tudo isso na sua própria infraestrutura.