> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Gentleman-Programming/engram/llms.txt
> Use this file to discover all available pages before exploring further.

# Memory Protocol

> When to save, when to search, and the mandatory session close protocol

## Overview

The **Memory Protocol** is a set of behavioral rules that teaches AI agents **when** and **how** to use Engram's memory tools. Without it, agents have the tools but no guidance on when to call them.

The protocol is injected via:

* **System prompt** (OpenCode, Gemini CLI, Codex, VS Code)
* **Skill file** (Claude Code)
* **Agent rules** (Cursor, Windsurf, Antigravity)

<Info>
  The protocol is enforced as **mandatory** — not optional. This ensures memory continuity across sessions and context resets.
</Info>

## When to Save (Mandatory)

Call `mem_save` **IMMEDIATELY** after any of these:

<CardGroup cols={2}>
  <Card title="Bug Fix Completed" icon="bug">
    Save what was wrong, why it broke, how you fixed it, and any gotchas.
  </Card>

  <Card title="Architecture/Design Decision" icon="sitemap">
    Save the decision, tradeoffs considered, and why this choice was made.
  </Card>

  <Card title="Non-Obvious Discovery" icon="magnifying-glass">
    Save anything surprising about the codebase that future sessions should know.
  </Card>

  <Card title="Configuration Change" icon="gear">
    Save environment setup, config changes, or tool installations.
  </Card>

  <Card title="Pattern Established" icon="repeat">
    Save naming conventions, code structure patterns, or team standards.
  </Card>

  <Card title="User Preference Learned" icon="user">
    Save user constraints, preferences, or coding style requirements.
  </Card>
</CardGroup>

### Format for `mem_save`

Every saved observation must follow this structure:

<CodeGroup>
  ```typescript Decision Example theme={null}
  {
    title: "Chose Zustand over Redux for state",
    type: "decision",
    scope: "project",
    topic_key: "architecture/state-management",
    content: `
  **What**: Replaced Redux with Zustand for state management

  **Why**: Redux boilerplate (actions, reducers, connect) was slowing feature velocity. Team wanted something simpler but still debuggable.

  **Where**: 
  - src/store/ (deleted entire Redux setup)
  - src/hooks/useAppStore.ts (new Zustand store)
  - src/components/**/*.tsx (updated imports)

  **Learned**: 
  - Zustand devtools require wrapping create() with devtools() — not automatic
  - Zustand doesn't have built-in async middleware — use immer for complex updates
  - Migration took 3 hours, removed 400 lines of boilerplate
    `
  }
  ```

  ```typescript Bugfix Example theme={null}
  {
    title: "Fixed N+1 query in user list endpoint",
    type: "bugfix",
    scope: "project",
    content: `
  **What**: Added eager loading for user.posts relationship in UserList query

  **Why**: /api/users endpoint was making N+1 queries (1 for users, then 1 per user for posts), causing 2-3 second page loads with 100+ users.

  **Where**:
  - src/models/User.ts — added posts relationship with hasMany
  - src/controllers/UserController.ts — added .include('posts') to query

  **Learned**:
  - Sequelize relationships are NOT eager-loaded by default — must explicitly include
  - Can verify with Sequelize logging: set logging: console.log in config
  - Page load dropped from 2.3s to 180ms after fix
    `
  }
  ```

  ```typescript Discovery Example theme={null}
  {
    title: "FTS5 requires quoted strings for special chars",
    type: "discovery",
    scope: "personal",
    content: `
  **What**: Discovered FTS5 MATCH syntax errors when queries contain special characters

  **Why**: User searches like "fix auth bug" were crashing with "fts5: syntax error near 'bug'"

  **Where**: internal/store/store.go — sanitizeFTS() function wraps each word in quotes

  **Learned**:
  - FTS5 MATCH is NOT the same as LIKE — interprets chars like - and * as operators
  - Solution: split query into words, wrap each in double quotes, rejoin
  - Example: "fix auth" becomes '"fix" "auth"'
    `
  }
  ```
</CodeGroup>

### Content Structure Rules

<Steps>
  <Step title="What">
    **One sentence** — concise description of what was done.
  </Step>

  <Step title="Why">
    What motivated this? User request, bug, performance issue, tech debt?
  </Step>

  <Step title="Where">
    **File paths** — which files were affected. Format: `src/path/file.ts — description`
  </Step>

  <Step title="Learned">
    Gotchas, edge cases, things that surprised you. **Omit if none** — don't force this section.
  </Step>
</Steps>

<Warning>
  **Title should be short and searchable** — like a commit message. Bad: "Fixed a bug". Good: "Fixed N+1 query in user list".
</Warning>

## When to Search Memory

### Reactive Search (User Asks)

When the user asks to recall something — any variation of:

* "remember"
* "recall"
* "what did we do"
* "how did we solve"
* "recordar" (Spanish)
* "acordate" (Spanish)
* "qué hicimos" (Spanish)

**Protocol:**

1. First call `mem_context` — checks recent session history (fast, cheap)
2. If not found, call `mem_search` with relevant keywords (FTS5 full-text search)
3. If you find a match, use `mem_get_observation` for full untruncated content

<CodeGroup>
  ```typescript User: "Remember how we fixed the auth bug?" theme={null}
  // Step 1: Check recent context
  const context = await mem_context({ project: currentProject });

  // Step 2: If not in recent sessions, search
  if (!foundInContext) {
    const results = await mem_search({
      query: "auth bug fix",
      type: "bugfix",
      limit: 5
    });
  }

  // Step 3: Get full content if needed
  if (results[0].id) {
    const full = await mem_get_observation({ id: results[0].id });
  }
  ```
</CodeGroup>

### Proactive Search (Overlap Detection)

Search memory BEFORE starting work when:

* Starting work on something that **might have been done before**
* User mentions a topic you have **no context on** — check if past sessions covered it
* About to implement a pattern — check if the team has a **preferred approach**

<CodeGroup>
  ```typescript Agent thinking: "User wants JWT auth. Has this been discussed?" theme={null}
  const authDecisions = await mem_search({
    query: "JWT authentication",
    type: "decision",
    scope: "project"
  });

  if (authDecisions.length > 0) {
    // Found existing decision — follow that pattern
  } else {
    // New territory — proceed and save the decision
  }
  ```
</CodeGroup>

<Tip>
  Proactive search prevents duplicate work and ensures consistency with past decisions.
</Tip>

## Topic Update Rules (Mandatory)

When saving evolving topics (architecture, long-running features), follow these rules:

<AccordionGroup>
  <Accordion title="Rule 1: Different topics must NOT overwrite each other">
    Use distinct topic keys for different concerns:

    * `architecture/auth-model` ≠ `bug/auth-nil-panic`
    * `decision/state-management` ≠ `pattern/component-structure`

    Bad: Using `auth` for both architecture and bugfixes — they'll overwrite each other.
  </Accordion>

  <Accordion title="Rule 2: Reuse the same topic_key for evolving topics">
    When a decision changes over time, use the **same topic key** to update:

    ```typescript theme={null}
    // First save
    mem_save({
      title: "Auth architecture",
      topic_key: "architecture/auth-model",
      content: "Using JWT with httpOnly cookies"
    });
    // Creates observation ID 100, revision_count=1

    // Later evolution
    mem_save({
      title: "Auth architecture",
      topic_key: "architecture/auth-model",
      content: "Switched to refresh token rotation"
    });
    // UPDATES observation ID 100, revision_count=2
    ```
  </Accordion>

  <Accordion title="Rule 3: Use mem_suggest_topic_key if unsure">
    If you're not sure what topic key to use:

    ```typescript theme={null}
    const suggestion = await mem_suggest_topic_key({
      type: "architecture",
      title: "Auth token strategy"
    });
    // Returns: "architecture-auth-token-strategy"

    // Then reuse it for future updates
    await mem_save({
      topic_key: suggestion.topic_key,
      ...
    });
    ```
  </Accordion>

  <Accordion title="Rule 4: Use mem_update when you have an exact ID">
    If you know the observation ID and want to correct it:

    ```typescript theme={null}
    await mem_update({
      id: 42,
      content: "Updated content with new details"
    });
    ```

    This does **not** increment `revision_count` — it's a correction, not an evolution.
  </Accordion>
</AccordionGroup>

## Session Close Protocol (Mandatory)

<Warning>
  **This is NOT optional.** Before ending a session or saying "done" / "listo" / "that's it", you **MUST** call `mem_session_summary`.
</Warning>

Without this, the next session starts blind.

### Session Summary Format

```markdown theme={null}
## Goal
[What we were working on this session — one paragraph]

## Instructions
[User preferences or constraints discovered during this session — skip if none]

## Discoveries
- [Technical findings, gotchas, non-obvious learnings]
- [Each discovery should be actionable or surprising]

## Accomplished
- [Completed items with key details — not just "fixed bug", but "fixed N+1 query in UserList by adding eager loading"]

## Next Steps
- [What remains to be done — for the next session]
- [Any blockers or decisions pending]

## Relevant Files
- path/to/file.ts — [what it does or what changed]
- another/file.go — [brief description]
```

<Tabs>
  <Tab title="Example: Feature Work">
    ```markdown theme={null}
    ## Goal
    Implement JWT authentication to replace the existing session-based auth system. User wanted stateless auth that works across multiple server instances.

    ## Instructions
    - User prefers httpOnly cookies over localStorage for XSS protection
    - Team coding style: async/await over .then() chains
    - All auth code should live in src/auth/ directory

    ## Discoveries
    - express-jwt middleware doesn't handle refresh tokens — had to implement custom rotation logic
    - bcrypt cost factor of 12 is the sweet spot for our server (10 was too fast, 14 too slow)
    - JWT tokens must include user role for RBAC — can't just store user ID

    ## Accomplished
    - Migrated from express-session to jsonwebtoken (removed 200 lines of session config)
    - Implemented refresh token rotation with atomic updates to prevent race conditions
    - Added JWT middleware to all protected routes in src/routes/
    - Updated login/logout endpoints to issue/revoke tokens
    - Tested with 1000 concurrent requests — no token collisions

    ## Next Steps
    - Add rate limiting to login endpoint (user mentioned this but ran out of time)
    - Write integration tests for token refresh flow
    - Update API documentation with new auth headers

    ## Relevant Files
    - src/auth/jwt.ts — JWT signing, verification, refresh token logic
    - src/middleware/authenticate.ts — Middleware to verify tokens on protected routes
    - src/routes/auth.ts — Login, logout, refresh endpoints
    - src/models/RefreshToken.ts — Database model for refresh token tracking
    ```
  </Tab>

  <Tab title="Example: Bugfix Session">
    ```markdown theme={null}
    ## Goal
    Fix the N+1 query problem in the user list endpoint that was causing 2-3 second page loads.

    ## Discoveries
    - Sequelize doesn't eager-load relationships by default — must explicitly .include()
    - Enabling Sequelize query logging (logging: console.log) helped identify the issue
    - The bug was introduced in commit a3f8c1d when we added the posts relationship but forgot to update the query

    ## Accomplished
    - Added eager loading for user.posts in UserController.index()
    - Page load time dropped from 2.3s to 180ms (tested with 150 users)
    - Added a comment in the code explaining why .include() is necessary

    ## Next Steps
    - Audit other endpoints for similar N+1 patterns

    ## Relevant Files
    - src/controllers/UserController.ts — Added .include('posts') to index query
    - src/models/User.ts — Verified posts relationship definition
    ```
  </Tab>
</Tabs>

<Info>
  The session summary is stored as a special observation with `type: "session_summary"` and is automatically injected into the next session's context.
</Info>

## After Compaction (Critical)

When you see a message about **compaction** or **context reset**, or if you see **"FIRST ACTION REQUIRED"** in your context:

<Steps>
  <Step title="Persist compacted work">
    **IMMEDIATELY** call `mem_session_summary` with the compacted summary content.

    This persists everything done before compaction.
  </Step>

  <Step title="Recover context">
    Call `mem_context` to load context from previous sessions.
  </Step>

  <Step title="Continue working">
    **Only then** continue with the user's request.
  </Step>
</Steps>

<Warning>
  **Do not skip step 1.** Without it, everything done before compaction is lost from memory forever.
</Warning>

### Compaction Example

```typescript theme={null}
// You receive this in context:
// "FIRST ACTION REQUIRED: Call mem_session_summary with the following content..."

// Step 1: Persist the compacted work
await mem_session_summary({
  session_id: currentSessionId,
  content: `[compacted summary from the message]`
});

// Step 2: Recover context
const context = await mem_context({ project: currentProject });

// Step 3: Now you can continue
// You have both the compacted work AND previous session context
```

## Passive Capture (Optional)

When completing a task, you can include a `## Key Learnings:` section at the end of your response:

```markdown theme={null}
## Key Learnings:

1. bcrypt cost=12 is the right balance for our server performance
2. JWT refresh tokens need atomic rotation to prevent race conditions
3. express-jwt doesn't handle refresh logic — must implement custom middleware
```

Engram will **automatically extract and save** these as observations with `type: "learning"`.

<Note>
  This is a **safety net** — it captures knowledge even if you forget to call `mem_save` explicitly. But explicit `mem_save` calls are still preferred for important work.
</Note>

## Scope: Project vs Personal

Observations can be scoped:

<Tabs>
  <Tab title="project (default)">
    **Project scope** — shared with the team, relevant to this codebase.

    Use for:

    * Architecture decisions
    * Bugfixes
    * Code patterns
    * Team conventions

    ```typescript theme={null}
    mem_save({
      title: "Auth architecture",
      scope: "project", // or omit (defaults to project)
      ...
    });
    ```
  </Tab>

  <Tab title="personal">
    **Personal scope** — private to you, not shared via git sync.

    Use for:

    * Personal preferences ("I prefer async/await over promises")
    * Learning notes ("How FTS5 MATCH syntax works")
    * Tool discoveries ("ripgrep is faster than grep")

    ```typescript theme={null}
    mem_save({
      title: "FTS5 syntax quirks",
      scope: "personal",
      ...
    });
    ```
  </Tab>
</Tabs>

<Info>
  When searching with `mem_search`, you can filter by scope: `mem_search({ query: "...", scope: "project" })` or `scope: "personal"`.
</Info>

## Privacy: The `<private>` Tag

Wrap sensitive content in `<private>` tags to strip it before storage:

```typescript theme={null}
mem_save({
  title: "OpenAI API setup",
  content: `
**What**: Configured OpenAI SDK with API key
**Where**: src/config/openai.ts
**Key**: <private>sk-abc123xyz456</private>
  `
});

// Stored as:
// **Key**: [REDACTED]
```

<Warning>
  Privacy stripping happens at **two layers** (plugin + store). Even if the plugin fails, the store layer catches it.
</Warning>

## Memory Protocol Checklist

Use this checklist to verify protocol compliance:

<AccordionGroup>
  <Accordion title="During Work" icon="check">
    * [ ] Called `mem_save` after each significant action (bugfix, decision, discovery)
    * [ ] Used structured **What/Why/Where/Learned** format for content
    * [ ] Short, searchable titles (not "fixed bug", but "fixed N+1 in UserList")
    * [ ] Used `topic_key` for evolving decisions
    * [ ] Searched memory proactively before starting overlapping work
  </Accordion>

  <Accordion title="Before Session End" icon="check">
    * [ ] Called `mem_session_summary` with Goal/Discoveries/Accomplished/Files format
    * [ ] Summary includes ALL significant work, not just the last task
    * [ ] Listed relevant files with descriptions
    * [ ] Added Next Steps for future sessions
  </Accordion>

  <Accordion title="After Compaction" icon="check">
    * [ ] Called `mem_session_summary` to persist compacted work (FIRST ACTION)
    * [ ] Called `mem_context` to recover previous session context
    * [ ] Only then continued with user's request
  </Accordion>
</AccordionGroup>

## Full Protocol Text (For Copy-Paste)

For agents without plugin support, add this to your agent's system prompt or rules file:

<Accordion title="Memory Protocol (Full Text)">
  ```markdown theme={null}
  ## Memory Protocol

  ### WHEN TO SAVE (mandatory — not optional)

  Call `mem_save` IMMEDIATELY after any of these:
  - Bug fix completed
  - Architecture or design decision made
  - Non-obvious discovery about the codebase
  - Configuration change or environment setup
  - Pattern established (naming, structure, convention)
  - User preference or constraint learned

  Format for `mem_save`:
  - **title**: Verb + what — short, searchable (e.g. "Fixed N+1 query in UserList", "Chose Zustand over Redux")
  - **type**: `bugfix` | `decision` | `architecture` | `discovery` | `pattern` | `config` | `preference`
  - **scope**: `project` (default) | `personal`
  - **topic_key** (optional, recommended for evolving decisions): stable key like `architecture/auth-model`
  - **content**:
  ```

  **What**: One sentence — what was done
  **Why**: What motivated it (user request, bug, performance, etc.)
  **Where**: Files or paths affected
  **Learned**: Gotchas, edge cases, things that surprised you (omit if none)

  ```

  ### Topic update rules (mandatory)

  - Different topics must not overwrite each other (e.g. architecture vs bugfix)
  - Reuse the same `topic_key` to update an evolving topic instead of creating new observations
  - If unsure about the key, call `mem_suggest_topic_key` first and then reuse it
  - Use `mem_update` when you have an exact observation ID to correct

  ### WHEN TO SEARCH MEMORY

  When the user asks to recall something — any variation of "remember", "recall", "what did we do", "how did we solve", "recordar", "acordate", "qué hicimos", or references to past work:
  1. First call `mem_context` — checks recent session history (fast, cheap)
  2. If not found, call `mem_search` with relevant keywords (FTS5 full-text search)
  3. If you find a match, use `mem_get_observation` for full untruncated content

  Also search memory PROACTIVELY when:
  - Starting work on something that might have been done before
  - The user mentions a topic you have no context on — check if past sessions covered it

  ### SESSION CLOSE PROTOCOL (mandatory)

  Before ending a session or saying "done" / "listo" / "that's it", you MUST call `mem_session_summary` with this structure:

  ```

  ## Goal

  \[What we were working on this session]

  ## Instructions

  \[User preferences or constraints discovered — skip if none]

  ## Discoveries

  * \[Technical findings, gotchas, non-obvious learnings]

  ## Accomplished

  * \[Completed items with key details]

  ## Next Steps

  * \[What remains to be done — for the next session]

  ## Relevant Files

  * path/to/file — \[what it does or what changed]

  ```

  This is NOT optional. If you skip this, the next session starts blind.

  ### AFTER COMPACTION

  If you see a message about compaction or context reset, or if you see "FIRST ACTION REQUIRED" in your context:
  1. IMMEDIATELY call `mem_session_summary` with the compacted summary content — this persists what was done before compaction
  2. Then call `mem_context` to recover any additional context from previous sessions
  3. Only THEN continue working

  Do not skip step 1. Without it, everything done before compaction is lost from memory.
  ```
</Accordion>

## Next Steps

<CardGroup cols={2}>
  <Card title="How It Works" icon="lightbulb" href="/concepts/how-it-works">
    Memory system, session lifecycle, and 3-layer pattern
  </Card>

  <Card title="Architecture" icon="sitemap" href="/concepts/architecture">
    System architecture, components, and data flow
  </Card>

  <Card title="MCP Tools" icon="wrench" href="/features/mcp-tools">
    Complete reference for all 13 memory tools
  </Card>

  <Card title="Agent Setup" icon="plug" href="/agents/overview">
    Set up Engram with your agent (OpenCode, Claude Code, etc.)
  </Card>
</CardGroup>
