Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ All endpoints return JSON. Server listens on `127.0.0.1:7437`.
### Sessions

- `POST /sessions` β€” Create session. Body: `{id, project, directory}`
- `POST /sessions/{id}/end` β€” End session. Body: `{summary}`
- `POST /sessions/{id}/end` β€” End session and set `ended_at`. Body: `{summary}`. If an existing non-empty summary is already stored, low-signal shutdown metadata summaries (`shutdown reason=... target=...`) are ignored to preserve the higher-signal summary.
- `GET /sessions/recent` β€” Recent sessions. Query: `?project=X&limit=N`

### Observations
Expand Down
182 changes: 182 additions & 0 deletions PRD-pi-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# PRD: Soporte oficial de Engram para pi.dev

## Contexto

Pi (`pi-coding-agent`) es un coding agent con extensiones nativas en TypeScript, skills, hooks de ciclo de vida y tools personalizadas. Hoy Engram no tiene soporte oficial de primera clase para pi, lo que obliga a una integraciΓ³n manual y no aprovecha las capacidades nativas del ecosistema de pi.

## Problema

Los usuarios de pi no tienen una experiencia oficial, simple y comparable a OpenCode para usar Engram. La integraciΓ³n manual genera fricciΓ³n y no habilita de forma coherente:

- protocolo de memoria nativo
- ciclo de vida de sesiΓ³n
- resiliencia frente a compaction
- auto-start del backend
- una instalaciΓ³n con un solo comando

## Objetivo

Agregar soporte oficial para pi mediante:

```bash
engram setup pi
```

La integraciΓ³n debe ser nativa, global, offline/local y comparable a la experiencia actual de OpenCode.

## Objetivos del producto

La soluciΓ³n debe:

- instalarse con un solo comando
- funcionar de forma global
- ser offline/local, sin depender de npm o git durante el setup
- usar una extensiΓ³n nativa de pi
- auto-arrancar Engram cuando sea necesario, igual que OpenCode
- exponer tools de memoria dentro de pi
- aplicar el Memory Protocol
- soportar session lifecycle
- manejar compaction recovery
- usar una polΓ­tica de memoria inicial asistida pero no intrusiva

## No objetivos

Por ahora no buscamos:

- integraciΓ³n MCP como experiencia principal
- instalaciΓ³n por proyecto
- inyecciΓ³n automΓ‘tica de memoria previa al abrir sesiΓ³n
- reimplementar lΓ³gica de memoria en TypeScript
- introducir una UX inconsistente respecto al resto de Engram

## Experiencia esperada del usuario

### Setup

El usuario ejecuta:

```bash
engram setup pi
```

Y queda listo para usar Engram dentro de pi sin pasos manuales adicionales.

### Uso inicial

Al abrir pi:

- la integraciΓ³n estΓ‘ disponible globalmente
- Engram puede auto-iniciarse si no estΓ‘ corriendo
- el agente cuenta con tools de memoria
- el protocolo de memoria estΓ‘ disponible
- si existe memoria relevante, se notifica su disponibilidad, pero no se inyecta automΓ‘ticamente en el contexto

### Durante la sesiΓ³n

El agente puede:

- guardar memorias relevantes
- consultar memorias cuando el usuario lo pida
- consultar memoria de forma proactiva solo cuando haya alta probabilidad de continuidad ΓΊtil

### En compaction

La integraciΓ³n debe preservar continuidad de trabajo sin romper la polΓ­tica conservadora del inicio de sesiΓ³n.

## Requisitos funcionales

### RF1 β€” Setup oficial

Debe existir `engram setup pi`.

### RF2 β€” InstalaciΓ³n global

La integraciΓ³n se instala en el espacio global de pi, no por proyecto.

### RF3 β€” DistribuciΓ³n embebida

La extensiΓ³n y skill necesarias deben poder instalarse desde el binario de Engram, sin depender de fetch remoto durante setup.

### RF4 β€” Tools de memoria

La integraciΓ³n debe exponer tools para buscar, guardar, contextualizar y cerrar sesiΓ³n de memoria.

### RF5 β€” Memory Protocol

La integraciΓ³n debe enseΓ±ar al agente:

- cuΓ‘ndo guardar
- cuΓ‘ndo buscar
- cΓ³mo cerrar sesiΓ³n
- cΓ³mo recuperarse tras compaction

### RF6 β€” Session lifecycle

Debe existir integraciΓ³n con inicio y fin de sesiΓ³n.

### RF7 β€” Auto-start backend

Debe comportarse como OpenCode: si Engram no estΓ‘ corriendo, se intenta levantar automΓ‘ticamente.

### RF8 β€” Privacidad

El contenido dentro de `<private>` no debe salir de la integraciΓ³n sin ser sanitizado.

### RF9 β€” Memoria inicial conservadora

Al inicio:

- no inyectar contexto automΓ‘ticamente
- no cargar memoria completa
- sΓ­ notificar si existe memoria relevante

### RF10 β€” Compaction resilience

La integraciΓ³n debe ayudar a no perder continuidad tras compaction.

## Decisiones ya tomadas

Estas decisiones ya estΓ‘n acordadas:

- instalaciΓ³n mediante `engram setup pi`
- distribuciΓ³n local/offline
- alcance global
- auto-start del backend igual que OpenCode
- polΓ­tica de memoria inicial: notificar memoria relevante sin insertarla
- objetivo de calidad: experiencia comparable a OpenCode

## Decisiones abiertas

Estas decisiones requieren diseΓ±o tΓ©cnico posterior:

1. naming de tools (`mem_*` vs `engram_*`)
2. forma exacta de la notificaciΓ³n inicial
3. criterio de β€œmemoria relevante”
4. estrategia exacta de compaction recovery
5. shape final del adaptador: extensiΓ³n sola vs extensiΓ³n + skill + assets auxiliares

## Principios de diseΓ±o

- adaptador fino
- lΓ³gica real en Engram, no en TypeScript
- experiencia consistente con OpenCode
- sin UX mΓ‘gica o intrusiva
- coherencia de producto antes que soluciones ad hoc

## Riesgos

- compaction difΓ­cil de diseΓ±ar correctamente
- sobrecargar el contexto inicial
- divergencia de naming o semΓ‘ntica respecto a otros agentes
- mover lΓ³gica de negocio a la extensiΓ³n por conveniencia

## Criterios de Γ©xito

Consideraremos exitosa la integraciΓ³n si:

- un usuario puede activar Engram en pi con `engram setup pi`
- no necesita configurar MCP manualmente
- la experiencia se siente first-class
- hay continuidad ΓΊtil entre sesiones
- no se inserta memoria al inicio sin demanda
- existe seΓ±al clara cuando hay memoria relevante disponible
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,14 @@ Windows, Linux, and other install methods β†’ [docs/INSTALLATION.md](docs/INSTAL
| OpenCode | `engram setup opencode` |
| Gemini CLI | `engram setup gemini-cli` |
| Codex | `engram setup codex` |
| Pi | `engram setup pi` |
| VS Code | `code --add-mcp '{"name":"engram","command":"engram","args":["mcp"]}'` |
| Cursor / Windsurf / Any MCP | See [docs/AGENT-SETUP.md](docs/AGENT-SETUP.md) |

Full per-agent config, Memory Protocol, and compaction survival β†’ [docs/AGENT-SETUP.md](docs/AGENT-SETUP.md)

> Pi note: `engram setup pi` uses Pi's official installer (`pi install <local-embedded-package>`) from offline embedded assets.

That's it. No Node.js, no Python, no Docker. **One binary, one SQLite file.**

## How It Works
Expand Down Expand Up @@ -136,7 +139,7 @@ Full CLI with all flags β†’ [docs/ARCHITECTURE.md#cli-reference](docs/ARCHITECTU
| [Installation](docs/INSTALLATION.md) | All install methods + platform support |
| [Agent Setup](docs/AGENT-SETUP.md) | Per-agent configuration + Memory Protocol |
| [Architecture](docs/ARCHITECTURE.md) | How it works + MCP tools + project structure |
| [Plugins](docs/PLUGINS.md) | OpenCode & Claude Code plugin details |
| [Plugins](docs/PLUGINS.md) | OpenCode, Claude Code, and Pi integration details |
| [Comparison](docs/COMPARISON.md) | Why Engram vs claude-mem |
| [Intended Usage](docs/intended-usage.md) | Mental model β€” how Engram is meant to be used |
| [Obsidian Brain](docs/beta/obsidian-brain.md) | Export memories as Obsidian knowledge graph (beta) |
Expand Down
8 changes: 7 additions & 1 deletion cmd/engram/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,12 @@ func printPostInstall(agent string) {
fmt.Println(" 1. Restart Codex so MCP config is reloaded")
fmt.Println(" 2. Verify ~/.codex/config.toml has [mcp_servers.engram]")
fmt.Println(" 3. Verify model_instructions_file + experimental_compact_prompt_file are set")
case "pi":
fmt.Println("\nNext steps:")
fmt.Println(" 1. Restart pi-coding-agent so the installed package is loaded")
fmt.Println(" 2. Verify startup banner includes Engram extension/skill")
fmt.Println(" 3. Setup materializes ~/.config/pi-coding-agent/packages/engram and runs 'pi install <that-path>'")
fmt.Println(" 4. Re-run 'engram setup pi' after package changes to re-install from local embedded assets")
}
}

Expand Down Expand Up @@ -1548,7 +1554,7 @@ Commands:
Merge similar project names into one canonical name
--all Scan ALL projects for similar name groups
--dry-run Preview what would be merged (no changes)
setup [agent] Install/setup agent integration (opencode, claude-code, gemini-cli, codex)
setup [agent] Install/setup agent integration (opencode, claude-code, gemini-cli, codex, pi)
sync Export new memories as compressed chunk to .engram/
--import Import new chunks from .engram/ into local DB
--status Show sync status (local vs remote chunks)
Expand Down
24 changes: 24 additions & 0 deletions cmd/engram/main_extra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,30 @@ func TestCmdMCPAndTUIBranches(t *testing.T) {
}
}

func TestCmdSetupInteractiveListsPi(t *testing.T) {
stubRuntimeHooks(t)
stubExitWithPanic(t)

// Trigger interactive mode by passing a flag-like second arg.
withArgs(t, "engram", "setup", "--interactive")
scanInputLine = func(a ...any) (int, error) {
ptr := a[0].(*string)
*ptr = "1"
return 1, nil
}
setupInstallAgent = func(agent string) (*setup.Result, error) {
return &setup.Result{Agent: agent, Destination: "/tmp/dest", Files: 1}, nil
}

stdout, stderr, recovered := captureOutputAndRecover(t, func() { cmdSetup() })
if recovered != nil {
t.Fatalf("setup should not exit in interactive mode, panic=%v stderr=%q", recovered, stderr)
}
if !strings.Contains(stdout, "pi") {
t.Fatalf("expected interactive setup list to include pi, got: %q", stdout)
}
}

func TestCmdSetupDirectAndInteractive(t *testing.T) {
stubRuntimeHooks(t)
stubExitWithPanic(t)
Expand Down
4 changes: 4 additions & 0 deletions cmd/engram/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ func TestPrintUsage(t *testing.T) {
if !strings.Contains(stdout, "search <query>") || !strings.Contains(stdout, "setup [agent]") {
t.Fatalf("usage missing expected commands: %q", stdout)
}
if !strings.Contains(stdout, "setup [agent] Install/setup agent integration (opencode, claude-code, gemini-cli, codex, pi)") {
t.Fatalf("usage missing pi setup target: %q", stdout)
}
}

func TestPrintPostInstall(t *testing.T) {
Expand All @@ -174,6 +177,7 @@ func TestPrintPostInstall(t *testing.T) {
{agent: "opencode", expects: []string{"Restart OpenCode", "engram serve &"}},
{agent: "gemini-cli", expects: []string{"Restart Gemini CLI", "~/.gemini/settings.json"}},
{agent: "codex", expects: []string{"Restart Codex", "~/.codex/config.toml"}},
{agent: "pi", expects: []string{"Restart pi-coding-agent", "pi install", "~/.config/pi-coding-agent/packages/engram"}},
{agent: "unknown", expects: nil},
}

Expand Down
88 changes: 88 additions & 0 deletions docs/AGENT-SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Engram works with **any MCP-compatible agent**. Pick your agent below.
| OpenCode | `engram setup opencode` | [Details](#opencode) |
| Gemini CLI | `engram setup gemini-cli` | [Details](#gemini-cli) |
| Codex | `engram setup codex` | [Details](#codex) |
| Pi | `engram setup pi` | [Details](#pi) |
| VS Code | `code --add-mcp '{"name":"engram","command":"engram","args":["mcp"]}'` | [Details](#vs-code-copilot--claude-code-extension) |
| Antigravity | Manual JSON config | [Details](#antigravity) |
| Cursor | Manual JSON config | [Details](#cursor) |
Expand Down Expand Up @@ -170,6 +171,93 @@ args = ["mcp"]

---

## Pi

Recommended: one command for global, offline setup:

```bash
engram setup pi
```

`engram setup pi` materializes a local embedded package and runs Pi's official installer:
- Local package path: `~/.config/pi-coding-agent/packages/engram`
- Package assets:
- `package.json` (with top-level `pi` manifest)
- `extensions/engram.ts`
- `skills/engram/SKILL.md`
- Installer invocation: `pi install ~/.config/pi-coding-agent/packages/engram`

No guessed edits to `~/.config/pi-coding-agent/config.json` are performed by Engram.

Policy defaults for Pi support:
- notify-only at session start when relevant memory exists
- no automatic full-context injection
- extension lifecycle uses validated events: `session_start`, `session_shutdown`, `input`, `session_before_compact`, `session_compact`
- native Pi tools are registered via `pi.registerTool()` with canonical names: `mem_search`, `mem_context`, `mem_save`, `mem_session_summary`, `mem_get_observation`, `mem_save_prompt`
- compaction recovery guidance is available via extension command `/engram-recovery`

After install, run `/reload` in Pi so the extension and tools are reloaded in the current client process.

> Pi contract fields (hook names, manifest schema, notification API) are tracked in `internal/setup/testdata/pi-contract.json` and exercised by deterministic runtime harness tests (`go test ./internal/setup -run TestPiExtensionRuntimeHarnessDeterministic`). Update both if upstream behavior differs.

### Pi Manual E2E Checklist

Use this when validating a real Pi installation outside CI:

1. **Global install + offline path**
- Disconnect network (or block outbound) and run `engram setup pi`.
- Confirm local package exists at `~/.config/pi-coding-agent/packages/engram`.
- Confirm `engram setup pi` invokes `pi install <local-package-dir>`.
2. **Extension load**
- Start Pi and verify startup banner lists Engram extension/skill.
3. **Auto-start parity**
- Stop Engram backend, then call native mem_search from Pi in a fresh session (`stop Engram backend, then call native mem_search`).
- Confirm extension checks `/health` and attempts `engram serve` before tool/lifecycle calls.
4. **Session lifecycle hooks**
- Start Pi, run `/reload`, then begin and quit a session.
- Verify `session_start` emits `POST /sessions` and `session_shutdown` emits `POST /sessions/{id}/end` (shutdown metadata must not overwrite an existing non-empty/high-signal summary).
- Search for session start/end evidence in Engram storage/logs if those traces are available in your environment.
5. **Native memory tools + prompt capture**
- Confirm Pi lists native tools `mem_search`, `mem_context`, `mem_save`, `mem_session_summary`, `mem_get_observation`, `mem_save_prompt`.
- Trigger an input turn and verify `input` hook emits `POST /prompts`.
- Verify extension-generated input (`event.source === "extension"`) is not double-captured.
6. **Notify-only startup policy**
- Seed memory for the project, start a new Pi session.
- Confirm extension announces memory availability through `ctx.ui.notify(...)` but does **not** auto-fetch/inject `/context`.
7. **Recovery guidance + compaction hooks**
- Run `/engram-recovery` and verify message starts with `FIRST ACTION REQUIRED`.
- Run `/compact`, then verify compaction summary persistence (`run `/compact`, then verify compaction summary persistence`) via `POST /sessions/{id}/end` or recovery notification fallback.
- After compaction, call `mem_context` manually (no automatic context injection).
8. **Privacy sanitization**
- Start/end session values containing `<private>...</private>` and verify outbound payloads are `[REDACTED]`.

### Pi Troubleshooting: Duplicate package installs

If Pi reports shortcut/skill conflicts that reference unrelated packages (for example stale `pi-btw` temp installs), clean those duplicates separately from Engram:

1. List installed Pi packages and identify duplicate or malformed temporary paths.
2. Remove only the stale duplicate package directories (do **not** remove `~/.config/pi-coding-agent/packages/engram`).
3. Re-run `pi install ~/.config/pi-coding-agent/packages/engram` or `engram setup pi`.

These conflicts are environment cleanup issues, not Engram runtime behavior.

### Pi Troubleshooting: Auto-start cannot find Engram binary

If native `mem_*` calls report auto-start failures, Pi could be resolving an old/invalid `engram` binary from `PATH`.

1. Verify `engram` in your shell resolves to the expected binary (`which engram` / `command -v engram`).
2. Ensure that binary is available in the environment used to launch Pi.
3. If needed, launch Pi with an explicit override: `ENGRAM_BIN=/path/to/engram pi`

`ENGRAM_BIN` takes precedence over the default binary lookup inside the Pi extension.

If any checkpoint fails due to Pi API differences, update:
- `internal/setup/testdata/pi-contract.json` (assumptions)
- `plugin/pi/extensions/engram.ts` + embedded copy via `go generate ./internal/setup/`
- this checklist section

---

## VS Code (Copilot / Claude Code Extension)

VS Code supports MCP servers natively in its chat panel (Copilot agent mode). This works with **any** AI agent running inside VS Code β€” Copilot, Claude Code extension, or any other MCP-compatible chat provider.
Expand Down
Loading