Engram: memória persistente para agentes no Linux

Mascote do LinuxPro encaixando um cartucho de memória no SQLite, com o elefante do Engram na bancada

O agente de terminal é ótimo até a sessão acabar. Na seguinte, ele redescobre o mesmo bug, relê o mesmo README e pergunta de novo se a API usa JWT. O Engram é um cérebro local para isso: um binário em Go, um SQLite com FTS5 em ~/.engram/engram.db, e o mesmo banco para Claude Code, Codex, Cursor, Grok e qualquer outro cliente MCP.

Não é lixeira de transcript. O agente decide o que vale a pena lembrar — decisão, bug, convenção — e grava com mem_save. Na sessão seguinte, mem_search e mem_context devolvem o pedaço certo. O mapa das alternativas (mnemo, Leteo, Subcog…) está em Alternativas ao Claude-Mem em Go, Rust e C; o mapa dos agentes no terminal, em Assistentes de IA no terminal Linux. Este post é o passo a passo do Engram no Linux: instalar, ligar nos agentes, acertar o nome do projeto e deixar o daemon no boot.

O que é — e o que não é

Engram (/ˈen.ɡræm/, o traço físico de uma memória no cérebro) é um binário Go com SQLite embutido via modernc.org/sqlite — puro Go, sem CGO, sem Node, sem Python, sem Docker para o uso diário. Licença MIT. A linha estável em julho de 2026 é a v1.20.0.

Quatro portas para o mesmo banco:

Porta Comando Para quê
MCP stdio engram mcp --tools=agent O agente fala com a memória (Claude, Grok, Codex…)
CLI engram search, save, context Você consulta e grava na mão
TUI engram tui Navegar sessões e observações no terminal
HTTP local engram serve (porta 7437) API JSON. Não é página de navegador

O dashboard HTML (/dashboard) é o Engram Cloud — outro processo, Postgres, opcional. Sem Cloud, o visualizador local é o TUI.

A filosofia, explícita no README: o agente já tem o LLM e o contexto. Em vez de capturar cada tool call e comprimir depois (o modelo do claude-mem), o Engram pede que o agente grave só o que dura. Resultado: busca FTS5 limpa, zero chamada extra de API, um arquivo que você controla.

Instalar no Ubuntu/Linux

Não existe pacote apt nem .deb nas releases. O que a documentação de produção pede é o binário. Um arquivo, zero runtime: sem Node, sem Python, sem Docker. A linha estável em julho de 2026 é a v1.20.0.

Os releases oferecem binários Linux prontos para amd64 e arm64. O executável oficial é estaticamente ligado, sem dependências de runtime; escolha apenas o arquivo da arquitetura da máquina. Para compilar do código-fonte, o requisito é Go 1.24+.

Ubuntu amd64 e arm64

sudo apt-get update
sudo apt-get install -y curl ca-certificates

VER=1.20.0
case "$(dpkg --print-architecture)" in
  amd64) FILE=engram_${VER}_linux_amd64.tar.gz ;;
  arm64) FILE=engram_${VER}_linux_arm64.tar.gz ;;
  *) echo "sem binário pronto para $(dpkg --print-architecture)"; exit 1 ;;
esac

cd /tmp
curl -fsSL -O "https://github.com/Gentleman-Programming/engram/releases/download/v${VER}/${FILE}"
curl -fsSL -O "https://github.com/Gentleman-Programming/engram/releases/download/v${VER}/checksums.txt"
sha256sum -c checksums.txt --ignore-missing

mkdir -p ~/.local/bin
tar -xzf "$FILE" engram
install -m 755 engram ~/.local/bin/engram

# o ~/.profile do Ubuntu só acrescenta ~/.local/bin no próximo login,
# e só se o diretório já existir
export PATH="$HOME/.local/bin:$PATH"
hash -r
engram version

A saída esperada é engram 1.20.0. O tarball traz o executável na raiz, mais README, LICENSE e CHANGELOG. Banco padrão: ~/.engram/engram.db.

Para o PATH ficar permanente, abra um terminal novo depois da instalação. O ~/.profile padrão do Ubuntu já tem o bloco if [ -d "$HOME/.local/bin" ] — por isso o mkdir vem antes do install.

go install

Se você já tem Go 1.24+ (o da documentação). O pacote golang-go do Ubuntu 24.04 é 1.22 e o do 22.04 é 1.18 — não dá para go install por aí; use o binário da release ou instale o Go pelo site:

go install github.com/Gentleman-Programming/engram/cmd/engram@latest
# cai em $(go env GOPATH)/bin — em geral ~/go/bin/

go install carimba a versão como dev. Se quiser o git-describe no engram version, clone e passe -ldflags — um go install e um go build no mesmo PATH deixam dois binários e a versão “dev” ganha. Há uma linha v2 (github.com/Gentleman-Programming/engram/v2/cmd/engram) para release candidates; produção continua na v1.

Homebrew no Linux

brew install gentleman-programming/tap/engram

O tap cobre a linha estável v1.20.0. Upgrade: brew update && brew upgrade engram. Trocar o binário mata um engram serve solto — por isso o serviço systemd, mais abaixo.

Primeiro contato

engram version
engram stats
engram projects list
engram tui

Banco padrão: ~/.engram/engram.db. Override: ENGRAM_DATA_DIR. No TUI, j/k navega, Enter abre, / busca, Esc volta. Tema Catppuccin Mocha.

A API local, se você subir o daemon:

engram serve          # 127.0.0.1:7437
curl -s http://127.0.0.1:7437/health
# {"service":"engram","status":"ok","version":"0.1.0"}

/ e /dashboard nessa porta devolvem 404. É JSON, não site. GET /project/current usa o cwd do processo do serve — no systemd com WorkingDirectory=%h, isso vira o basename da home, não o repo em que você está editando.

Ligar nos agentes

engram setup <agente> escreve o MCP no formato de cada cliente. Não configura Cloud. Reinicie o agente depois.

Agente Comando
Claude Code claude plugin marketplace add Gentleman-Programming/engram e claude plugin install engram — ou engram setup claude-code
Codex engram setup codex
OpenCode engram setup opencode
Cursor engram setup cursor
Gemini CLI engram setup gemini-cli
VS Code Copilot engram setup vscode-copilot
Windsurf, Qwen, Kiro, Kilo, Pi, Antigravity engram setup <nome> — lista em engram --help

Perfis MCP: agent (o conjunto que o agente usa no dia a dia), admin, ou all. O default do engram mcp sem flag é all. Para o agente, use --tools=agent.

Grok Build (manual)

Não há engram setup grok. Em ~/.grok/config.toml:

[mcp_servers.engram]
command = "/home/SEU_USER/.local/bin/engram"
args = ["mcp", "--tools=agent"]
enabled = true

Confira com grok mcp doctor engram — handshake ok e as tools do perfil agent. Recarregue a sessão do Grok: o MCP só entra na que sobe depois da config. O banco é o mesmo do Claude. O nome do projeto, não: cada processo detecta pelo próprio cwd.

Qualquer cliente MCP

{
  "mcpServers": {
    "engram": {
      "command": "engram",
      "args": ["mcp", "--tools=agent"]
    }
  }
}

O cliente dispara um processo stdio por sessão. Isso não substitui o engram serve do systemd — são coisas diferentes. MCP lê e grava o SQLite direto; o serve é a API HTTP (e o autosync Cloud, se você ligar).

Como o Engram escolhe o projeto

Ele não indexa o path. Resolve um nome e filtra o SQLite por esse nome. Precedência:

  1. argumento explícito (mem_context com project, engram context teste);
  2. override de processo (engram mcp --project … ou ENGRAM_PROJECT);
  3. detecção pelo cwd.

A detecção do diretório, em ordem:

# source O que usa
0 config .engram/config.json com project_name
1 git_remote repo com origin — nome do remote, gravado num binding privado do clone
2 git_root git sem origin — basename da raiz
3 git_child cwd tem exatamente um filho git — promove esse
4 ambiguous vários filhos git — não escolhe sozinho
5 dir_basename último recurso: filepath.Base(cwd)

Pasta sem git vira o basename. Claude gravando em /home/você/teste e Grok em …/site-linuxpro são dois projetos. A memória não aparece “do outro lado” até você buscar com o nome certo ou all_projects=true.

Lock estável na raiz do repo:

{
  "project_name": "site-linuxpro"
}

O Engram usa o config mais próximo abaixo da raiz git — dá para ter backend/.engram/config.json e frontend/.engram/config.json no monorepo. Fora de git, só vale o config do diretório atual: ~/.engram/config.json não vaza para os filhos. Primeira chamada útil de qualquer sessão: mem_current_project — devolve project, project_source e, se for o caso, available_projects.

Se a escrita voltar ambiguous_project, o agente não pode chutar. Você escolhe um nome da lista e a tool retenta com project_choice_reason=user_selected_after_ambiguous_project.

Subir o serve no boot

Esta seção é opcional. Claude Code, Codex e os demais clientes MCP via stdio usam engram mcp e não precisam de engram serve. Suba o serviço se precisar da API HTTP local, do autosync do Cloud ou de integrações HTTP, como OpenCode e Pi.

Quando ele for necessário, um supervisor evita que engram serve morra no reboot ou durante a troca do binário.

Unit de usuário, no template oficial:

# ~/.config/systemd/user/engram.service
[Unit]
Description=Engram Memory Server
After=network.target

[Service]
WorkingDirectory=%h
ExecStart=%h/.local/bin/engram serve
Restart=always
RestartSec=3
Environment=ENGRAM_DATA_DIR=%h/.engram
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=default.target
mkdir -p ~/.engram ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable --now engram.service
curl -s http://127.0.0.1:7437/health
journalctl --user -u engram -f

enable amarra no login. Para subir no boot sem sessão gráfica, o usuário precisa de linger:

loginctl enable-linger "$USER"
loginctl show-user "$USER" -p Linger

Se a 7437 já estiver ocupada por um serve órfão, a unit falha no bind. Mate o processo antigo (ss -tlnp | grep 7437) e systemctl --user restart engram.

O contrato de memória

O README trata o Engram como memória curada, não como dump. O ciclo:

  1. Orientarmem_current_project, depois mem_context / mem_search.
  2. Buscar antes de repetir — decisão, bug, convenção que já podem estar no banco.
  3. Revelar por camadasmem_search devolve preview (~300 caracteres); mem_get_observation traz o texto inteiro; mem_timeline mostra o antes/depois na sessão.
  4. Gravar o que duramem_save com título curto, tipo (decision, bugfix, config, architecture…) e corpo What / Why / Where / Learned. Não grave saída crua de ferramenta.
  5. Assunto que evoluitopic_key estável (architecture/auth-model). Mesmo projeto + scope + topic vira upsert, não uma linha nova.
  6. Fechar a sessãomem_session_summary com Goal, Discoveries, Accomplished, Next Steps, Files.

Scope: project (default), personal ou global. Um personal no mesmo topic_key não sobrescreve o de projeto.

O que não vai para o SQLite: senha, token, dump de journalctl. O git continua sendo o registro — a história está em A história do Git. Tags <private> são removidas em duas camadas no Engram; mesmo assim, não grave o que não pode vazar.

Cloud e dashboard no navegador

O Cloud é replicação opcional + UI. SQLite local continua autoritativo. Caminho smoke com Docker, no clone do repositório:

docker compose -f docker-compose.cloud.yml up -d
engram cloud config --server http://127.0.0.1:18080
engram cloud enroll meu-projeto
engram sync --cloud --project meu-projeto

Dashboard local: http://127.0.0.1:18080/dashboard. No compose smoke, /dashboard/login redireciona sem pedir token. Rotas úteis: /dashboard/browser, /dashboard/projects, /dashboard/activity.

Para o dia a dia num laptop, Cloud é extra. TUI + MCP bastam.

Dicas que evitam dor

  • Um cérebro, nomes certos. Claude, Grok e Codex só compartilham memória se o project for o mesmo. Coloque .engram/config.json no repo no primeiro dia.
  • Não instale três servidores de memória no mesmo agente. Eles competem pelo contexto. Um de sessão (Engram) + o grafo do código (codebase-memory-mcp) já é o teto útil — o encaixe no fluxo está em Vibe coding no Linux.
  • MCP ≠ serve. O Grok/Claude sobe engram mcp via stdio. O systemd sobe engram serve na 7437. Os dois podem coexistir; um não substitui o outro.
  • Cwd do serve. Unit com WorkingDirectory=%h faz /project/current responder o basename da home. Para leitura de projeto, use o MCP do agente (cwd do repo) ou passe --project.
  • Busca FTS5 é AND por padrão. match_mode=any alarga. Preview não é o registro completo — abra o id.
  • Doctor. engram doctor (ou mem_doctor) checa lock do SQLite, mismatch de sessão e binding. Quatro checks ok é o estado saudável.
  • Linger. Sem loginctl enable-linger, a unit de usuário só vive enquanto houver sessão. Com linger, sobrevive ao reboot headless.
  • Upgrade do binário. Homebrew ou um install por cima mata o processo se não houver systemd com Restart=always.
  • Não misture autosync nativo e wrappers de cron. A documentação pede um modo só.
  • HTTP token. ENGRAM_HTTP_TOKEN protege delete/export/import na API local. Sem ele, essas rotas ficam abertas em 127.0.0.1 — ok no laptop, ruim se você publicar a 7437 na LAN.

Engram ou claude-mem?

O Engram nasceu inspirado no claude-mem, com decisões opostas: binário único, qualquer agente MCP, FTS5 em vez de worker + ChromaDB, o agente comprime na hora em vez de um pipeline à parte. Se a sua vida é só Claude Code e você já está no ecossistema de hooks dele, o original continua válido. Se Claude, Codex e Grok precisam lembrar a mesma decisão, comece pelo Engram. Comparação lado a lado e as outras opções em Go/Rust/C: Alternativas ao Claude-Mem.

Fechando

Instale o binário da release, trave o nome do projeto num .engram/config.json, ligue o MCP em cada agente e deixe o engram serve no systemd de usuário. O resto é disciplina: gravar o que dura, buscar antes de repetir, fechar a sessão com um resumo. O agente da manhã seguinte já sabe que a autenticação é JWT — e você não paga um segundo modelo só para lembrar disso.

Para continuar: assistentes de IA no terminal, Ollama se a inferência também for local, e a história do Go — a língua em que o Engram é um arquivo só.

Links oficiais: github.com/Gentleman-Programming/engram · releases · engram.gentlemanprogramming.com · Installation · Agent Setup