Engram: memoria persistente para agentes en Linux

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

El agente de terminal es genial hasta que termina la sesión. En la siguiente, redescubre el mismo bug, vuelve a leer el mismo README y pregunta otra vez si la API usa JWT. Engram es un cerebro local para eso: un binario en Go, un SQLite con FTS5 en ~/.engram/engram.db, y la misma base de datos para Claude Code, Codex, Cursor, Grox y cualquier otro cliente MCP.

No es un cubo de transcripts. El agente decide qué vale la pena recordar: decisión, bug, convención, y lo guarda con mem_save. En la siguiente sesión, mem_search y mem_context devuelven el trozo adecuado. El mapa de alternativas (mnemo, Leteo, Subcog…) está en Alternativas a Claude-Mem en Go, Rust y C; el mapa de los agentes en terminal, en Asistentes de IA en el terminal Linux. Este post es el paso a paso de Engram en Linux: instalar, conectarlo a los agentes, ajustar el nombre del proyecto y dejar el daemon en el arranque.

Qué es — y qué no es

Engram (/ˈen.ɡræm/, el rastro físico de un recuerdo en el cerebro) es un binario Go con SQLite integrado mediante modernc.org/sqlite: Go puro, sin CGO, sin Node, sin Python, sin Docker para el uso diario. Licencia MIT. La línea estable en julio de 2026 es la v1.20.0.

Cuatro puertas al mismo banco:

Puerta Comando Para qué
MCP stdio engram mcp --tools=agent El agente habla con la memoria (Claude, Grok, Codex…)
CLI engram search, save, context Consultas y grabas a mano
TUI engram tui Navegar sesiones y observaciones en el terminal
HTTP local engram serve (puerto 7437) API JSON. No es una página de navegador

El dashboard HTML (/dashboard) es el Engram Cloud, otro proceso, Postgres, opcional. Sin Cloud, el visor local es el TUI.

La filosofía, explícita en el README: el agente ya tiene el LLM y el contexto. En lugar de capturar cada tool call y comprimir después (el modelo de claude-mem), Engram pide al agente que registre solo lo que dura. Resultado: búsqueda FTS5 limpia, cero llamadas extra a la API, un archivo que tú controlas.

Instalar en Ubuntu/Linux

No existe paquete apt ni .deb en las releases. Lo que pide la documentación de producción es el binario. Un archivo, cero runtime: sin Node, sin Python, sin Docker. La línea estable en julio de 2026 es la v1.20.0.

Los releases ofrecen binarios Linux listos para amd64 e arm64. El ejecutable oficial está enlazado estáticamente, sin dependencias en tiempo de ejecución; elige únicamente el archivo de la arquitectura de la máquina. Para compilar desde el código fuente, el requisito es Go 1.24+.

Ubuntu amd64 y 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

La salida esperada es engram 1.20.0. El tarball trae el ejecutable en la raíz, además de README, LICENSE y CHANGELOG. Base de datos por defecto: ~/.engram/engram.db.

Para que el PATH quede permanente, abre una terminal nueva después de la instalación. El ~/.profile por defecto de Ubuntu ya trae el bloque if [ -d "$HOME/.local/bin" ] — por eso el mkdir va antes que el install.

go install

Si ya tienes Go 1.24+ (el de la documentación). El paquete golang-go de Ubuntu 24.04 es 1.22 y el de 22.04 es 1.18 — no se puede go install por ahí; usa el binario de la release o instala Go desde su web:

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

go install estampa la versión como dev. Si quieres el git-describe en el engram version, clona y pasa -ldflags — un go install y un go build en el mismo PATH dejan dos binarios y gana la versión “dev”. Hay una línea v2 (github.com/Gentleman-Programming/engram/v2/cmd/engram) para release candidates; producción sigue en v1.

Homebrew en Linux

brew install gentleman-programming/tap/engram

El tap cubre la línea estable v1.20.0. Actualización: brew update && brew upgrade engram. Cambiar el binario mata un engram serve suelto — por eso el servicio systemd, más abajo.

Primer contacto

engram version
engram stats
engram projects list
engram tui

Banco por defecto: ~/.engram/engram.db. Override: ENGRAM_DATA_DIR. En el TUI, j/k navega, Enter abre, / busca, Esc vuelve. Tema Catppuccin Mocha.

La API local, si levantas el 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"}

/ y /dashboard en ese puerto devuelven 404. Es JSON, no un sitio. GET /project/current usa el cwd del proceso serve — en systemd con WorkingDirectory=%h, eso se convierte en el basename del home, no el repo en el que estás editando.

Conectar a los agentes

engram setup escribe el MCP en el formato de cada cliente. No configura Cloud. Reinicia el agente después.

Agente Comando
Claude Code claude plugin marketplace add Gentleman-Programming/engram e claude plugin install engram — o 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 en engram --help

Perfiles MCP: agent (el conjunto que usa el agente en el día a día), admin, o all. El valor por defecto de engram mcp sin flag es all. Para el agente, usa --tools=agent.

Grok Build (manual)

No hay engram setup grok. En ~/.grok/config.toml:

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

Compruébalo con grok mcp doctor engram — handshake ok y las tools del perfil agent. Recarga la sesión de Grok: el MCP solo entra en la que sube después de la config. La base de datos es la misma que la de Claude. El nombre del proyecto, no: cada proceso detecta por su propio cwd.

Cualquier cliente MCP

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

El cliente lanza un proceso stdio por sesión. Esto no sustituye al engram serve de systemd — son cosas distintas. MCP lee y escribe el SQLite directamente; el serve es la API HTTP (y el autosync Cloud, si lo activas).

Cómo Engram elige el proyecto

No indexa el path. Resuelve un nombre y filtra el SQLite por ese nombre. Precedencia:

  1. argumento explícito (mem_context con project, engram context teste);
  2. override de proceso (engram mcp --project … o ENGRAM_PROJECT);
  3. detección por cwd.

La detección del directorio, en orden:

# source Qué usa
0 config .engram/config.json con project_name
1 git_remote repo con origin — nombre del remote, guardado en un binding privado del clon
2 git_root git sin origin — basename de la raíz
3 git_child cwd tiene exactamente un hijo git — promueve ese
4 ambiguous varios hijos git — no elige solo
5 dir_basename último recurso: filepath.Base(cwd)

Carpeta sin git se convierte en el basename. Claude guardando en /home/você/teste y Grok en …/site-linuxpro son dos proyectos. La memoria no aparece “en el otro lado” hasta que la busques con el nombre correcto o all_projects=true.

Lock estable en la raíz del repo:

{
  "project_name": "site-linuxpro"
}

Engram usa el config más cercano por debajo de la raíz git — se pueden tener backend/.engram/config.json y frontend/.engram/config.json en el monorepo. Fuera de git, solo vale el config del directorio actual: ~/.engram/config.json no se filtra a los hijos. Primera llamada útil de cualquier sesión: mem_current_project — devuelve project, project_source y, si procede, available_projects.

Si la escritura vuelve ambiguous_project, el agente no puede adivinar. Eliges un nombre de la lista y la herramienta reintenta con project_choice_reason=user_selected_after_ambiguous_project.

Iniciar el serve en el arranque

Esta sección es opcional. Claude Code, Codex y los demás clientes MCP a través de stdio usan engram mcp y no necesitan engram serve. Levanta el servicio si necesitas la API HTTP local, el autosync de la nube o integraciones HTTP, como OpenCode y Pi.

Cuando sea necesario, un supervisor evita que engram serve muera en el reinicio o durante el cambio del binario.

Unit de usuario, en la plantilla 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 se ata al login. Para arrancar en el boot sin sesión gráfica, el usuario necesita linger:

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

Si el 7437 ya está ocupado por un serve huérfano, la unit falla en el bind. Mata el proceso antiguo (ss -tlnp | grep 7437) y systemctl --user restart engram.

El contrato de memoria

El README trata el Engram como memoria curada, no como volcado. El ciclo:

  1. Orientar — mem_current_project, después mem_context / mem_search.
  2. Buscar antes de repetir — decisión, error, convención que ya pueden estar en la base.
  3. Revelar por capas — mem_search devuelve vista previa (~300 caracteres); mem_get_observation trae el texto completo; mem_timeline muestra el antes/después en la sesión.
  4. Guardar lo que dura — mem_save con título corto, tipo (decision, bugfix, config, architecture…) y cuerpo What / Why / Where / Learned. No guarde salida cruda de herramienta.
  5. Asunto que evoluciona — topic_key estable (architecture/auth-model). Mismo proyecto + scope + topic se convierte en upsert, no en una línea nueva.
  6. Cerrar la sesión — mem_session_summary con Goal, Discoveries, Accomplished, Next Steps, Files.

Scope: project (por defecto), personal o global. Un personal en el mismo topic_key no sobrescribe el de proyecto.

Lo que no va al SQLite: contraseña, token, dump de journalctl. Git sigue siendo el registro — la historia está en El historial de Git. Las etiquetas se eliminan en dos capas en Engram; aun así, no guardes lo que no pueda filtrarse.

Cloud y panel en el navegador

Cloud es replicación opcional + UI. SQLite local sigue siendo autoritativo. Ruta smoke con Docker, en el clon del repositorio:

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. En el compose smoke, /dashboard/login redirige sin pedir token. Rutas útiles: /dashboard/browser, /dashboard/projects, /dashboard/activity.

Para el día a día en un portátil, Cloud es extra. TUI + MCP bastan.

Consejos que evitan dolores

  • Un cerebro, nombres correctos. Claude, Grok y Codex solo comparten memoria si el project es el mismo. Coloque .engram/config.json en el repo el primer día.
  • No instale tres servidores de memoria en el mismo agente. Compiten por el contexto. Uno de sesión (Engram) + el grafo del código (codebase-memory-mcp) ya es el techo útil — el encaje en el flujo está en Vibe coding en Linux.
  • MCP ≠ serve. Grok/Claude arranca engram mcp vía stdio. systemd arranca engram serve en 7437. Ambos pueden coexistir; uno no sustituye al otro.
  • Cwd del serve. Unit con WorkingDirectory=%h hace /project/current responder el basename del home. Para lectura de proyecto, usa el MCP del agente (cwd del repo) o pasa --project.
  • Búsqueda FTS5 es AND por defecto. match_mode=any amplia. La preview no es el registro completo — abre el id.
  • Doctor. engram doctor (o mem_doctor) verifica el bloqueo de SQLite, el desajuste de sesión y el binding. Cuatro comprobaciones correctas indican el estado saludable.
  • Linger. Sin loginctl enable-linger, la unidad de usuario solo vive mientras haya sesión. Con linger, sobrevive al reinicio sin interfaz.
  • Actualización del binario. Homebrew o un install encima mata el proceso si no hay systemd con Restart=always.
  • No mezcles el autosync nativo y los wrappers de cron. La documentación pide un único modo.
  • Token HTTP. ENGRAM_HTTP_TOKEN protege delete/export/import en la API local. Sin él, esas rutas quedan abiertas en 127.0.0.1 — bien en el portátil, mal si publicas la 7437 en la LAN.

Engram o claude-mem?

Engram nació inspirado en claude-mem, con decisiones opuestas: binario único, cualquier agente MCP, FTS5 en lugar de worker + ChromaDB, el agente comprime en el momento en vez de un pipeline aparte. Si tu vida es solo Claude Code y ya estás en el ecosistema de hooks de este, el original sigue siendo válido. Si Claude, Codex y Grok necesitan recordar la misma decisión, empieza por Engram. Comparación lado a lado y las demás opciones en Go/Rust/C: Alternativas a Claude-Mem.

Cerrando

Instala el binario de la release, fija el nombre del proyecto en un .engram/config.json, conecta el MCP en cada agente y deja el engram serve en systemd de usuario. El resto es disciplina: guardar lo que dura, buscar antes de repetir, cerrar la sesión con un resumen. El agente de la mañana siguiente ya sabe que la autenticación es JWT — y no pagas un segundo modelo solo para recordar eso.

Para continuar: asistentes de IA en el terminal, Ollama si la inferencia también es local, y la historia de Go — el lenguaje en el que Engram es un único archivo.

Enlaces oficiales: github.com/Gentleman-Programming/engram · releases · engram.gentlemanprogramming.com · Installation · Agent Setup