> ## 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.

# mem_save

> Save important observations to persistent memory

## Overview

Save significant work, decisions, discoveries, and learnings to persistent memory. Call this **proactively** after completing important tasks — don't wait to be asked.

<Note>
  This is a **core tool** in the agent profile, always loaded in the MCP context.
</Note>

## When to Save

Call `mem_save` after each of these:

* **Architectural decisions or tradeoffs** — chose JWT over sessions, microservices vs monolith
* **Bug fixes** — what was wrong, why it happened, how you fixed it
* **New patterns or conventions** — established a naming convention, file structure
* **Configuration changes** — environment setup, build config, CI/CD changes
* **Important discoveries or gotchas** — API behavior, edge cases, performance findings
* **File structure changes** — created new directories, reorganized modules

## Parameters

<ParamField path="title" type="string" required>
  Short, searchable title

  **Examples:**

  * "JWT auth middleware"
  * "Fixed N+1 query in user list"
  * "FTS5 query sanitization"
  * "Switched to TypeScript strict mode"

  Keep it concise (under 80 characters) and focused on the what, not the why.
</ParamField>

<ParamField path="content" type="string" required>
  Structured content using the **What/Why/Where/Learned** format

  Use this exact structure:

  ```
  **What**: [concise description of what was done]
  **Why**: [the reasoning, user request, or problem that drove it]
  **Where**: [files/paths affected, e.g. src/auth/middleware.ts]
  **Learned**: [gotchas, edge cases, or decisions — omit if none]
  ```

  **Focus on:**

  * What was changed (concise, high-level)
  * Why it was needed (the problem or goal)
  * Where the changes are (file paths, line numbers)
  * What you learned (non-obvious insights, gotchas)

  **Don't include:**

  * Full code diffs (the git repo has that)
  * Step-by-step instructions (focus on outcomes)
  * Obvious implementation details
</ParamField>

<ParamField path="type" type="string">
  Category for the observation

  **Recognized types:**

  * `decision` — architectural or technical decisions
  * `architecture` — system design, structure, patterns
  * `bugfix` — bug fixes and incident resolutions
  * `pattern` — conventions, guidelines, code patterns
  * `config` — configuration, setup, environment changes
  * `discovery` — technical findings, investigations
  * `learning` — lessons learned, gotchas
  * `manual` (default) — general observations

  The type affects:

  * Search filtering (users can filter by type)
  * Topic key generation (used for upserts)
  * Categorization in the TUI
</ParamField>

<ParamField path="session_id" type="string">
  Session ID to associate with this observation

  **Default:** `manual-save-{project}` or `manual-save` if no project

  Links the observation to a coding session for timeline context.
</ParamField>

<ParamField path="project" type="string">
  Project name

  Associates the observation with a specific project for filtering and scoping.

  **Example:** `my-api`, `engram`, `frontend`
</ParamField>

<ParamField path="scope" type="string">
  Visibility scope for this observation

  **Options:**

  * `project` (default) — visible only within this project
  * `personal` — cross-project, personal knowledge

  Use `personal` for:

  * Language-specific patterns (e.g., "Go error handling pattern")
  * Tool usage tips (e.g., "Git rebase vs merge")
  * General learnings that apply across projects

  Use `project` (default) for:

  * Project-specific decisions
  * Architecture choices
  * Bug fixes tied to this codebase
</ParamField>

<ParamField path="topic_key" type="string">
  Optional topic identifier for upserts

  Format: `family/segment` (e.g., `architecture/auth-model`, `bug/fts5-sanitization`)

  **When to use:**

  * Evolving architectural decisions that should update a single observation
  * Ongoing bug investigations that refine over time
  * Living documentation that gets revised

  **How it works:**

  * If an observation with the same `topic_key`, `project`, and `scope` exists, it's **updated** (revision count increments)
  * If not, a new observation is created

  **Get a stable topic key:**
  Use [`mem_suggest_topic_key`](/mcp/mem-suggest-topic-key) to generate a normalized key:

  ```json theme={null}
  {
    "type": "architecture",
    "title": "Database schema design"
  }
  // Returns: "architecture/database-schema-design"
  ```
</ParamField>

## Response

<ResponseField name="result" type="string">
  Confirmation message with the saved observation details
</ResponseField>

**Example responses:**

```
Memory saved: "JWT auth middleware" (decision)
```

```
Memory saved: "Fixed N+1 query" (bugfix)
Suggested topic_key: bug/n1-query-user-list
```

## Usage Examples

### Bug Fix

```json theme={null}
{
  "title": "Fixed FTS5 syntax error on special chars",
  "type": "bugfix",
  "content": "**What**: Wrapped each search term in quotes before passing to FTS5 MATCH\n**Why**: Users typing queries like 'fix auth bug' would crash because FTS5 interprets special chars as operators\n**Where**: internal/store/store.go — sanitizeFTS() function\n**Learned**: FTS5 MATCH syntax is NOT the same as LIKE — always sanitize user input",
  "project": "engram"
}
```

### Architectural Decision

```json theme={null}
{
  "title": "Switched from sessions to JWT",
  "type": "decision",
  "content": "**What**: Replaced express-session with jsonwebtoken for auth\n**Why**: Session storage doesn't scale across multiple instances\n**Where**: src/middleware/auth.ts, src/routes/login.ts\n**Learned**: Must set httpOnly and secure flags on the cookie, refresh tokens need separate rotation logic",
  "project": "my-api",
  "scope": "project"
}
```

### Pattern with Topic Key

```json theme={null}
{
  "title": "Go error handling pattern",
  "type": "pattern",
  "content": "**What**: Established consistent error wrapping with fmt.Errorf and %w\n**Why**: Makes error traces debuggable without stack traces\n**Where**: All internal/* packages\n**Learned**: Use %w for wrapping, %v for formatting — errors.Is() requires %w",
  "scope": "personal",
  "topic_key": "pattern/go-error-handling"
}
```

### Discovery

```json theme={null}
{
  "title": "SQLite WAL mode performance",
  "type": "discovery",
  "content": "**What**: Enabled WAL mode with PRAGMA journal_mode=WAL\n**Why**: Default DELETE mode causes lock contention on concurrent reads\n**Where**: internal/store/store.go line 299\n**Learned**: WAL allows simultaneous reads+writes but creates -wal and -shm files. Safe to delete only when DB is closed.",
  "project": "engram"
}
```

## Structured Format

Always use the **What/Why/Where/Learned** format in the `content` field:

<Accordion title="What">
  **Concise description of what was done**

  Focus on the outcome, not the steps:

  * ✅ "Added JWT authentication to API endpoints"
  * ✅ "Refactored UserService to use repository pattern"
  * ❌ "First I created a new file, then I imported jwt, then..."
</Accordion>

<Accordion title="Why">
  **The reasoning, problem, or user request that drove it**

  Explain the motivation:

  * ✅ "Session cookies don't scale across multiple server instances"
  * ✅ "User requested ability to export data as CSV"
  * ❌ "Because it's better" (too vague)
</Accordion>

<Accordion title="Where">
  **Files and paths affected**

  Be specific:

  * ✅ `src/auth/middleware.ts` (line 45)
  * ✅ `internal/store/store.go`, `internal/mcp/mcp.go`
  * ❌ "The auth files" (too vague)
  * ❌ Full file paths with absolute directories (use relative paths from project root)
</Accordion>

<Accordion title="Learned">
  **Gotchas, edge cases, non-obvious insights**

  Capture the surprises:

  * ✅ "FTS5 requires quotes around search terms with special chars"
  * ✅ "Must close WAL files before SQLite backup"
  * ❌ "It works now" (no insight)

  **Omit if there are no notable learnings** — not every save needs a Learned section.
</Accordion>

## Deduplication

Engram automatically detects duplicate observations:

* **Duplicate detection window**: 15 minutes (configurable)
* **Matching criteria**: Same session + same content hash
* **Behavior**: Updates `duplicate_count` instead of creating a new entry

<Tip>
  If you call `mem_save` twice with identical content within 15 minutes, the duplicate count increments but only one observation is stored.
</Tip>

## Topic Key Upserts

When `topic_key` is provided:

1. Engram searches for an existing observation with:
   * Same `topic_key`
   * Same `project`
   * Same `scope`
2. If found:
   * Content is **replaced** with new content
   * `revision_count` increments
   * `updated_at` timestamp refreshes
3. If not found:
   * New observation is created

<Info>
  Use topic keys for **evolving knowledge** — architecture decisions, ongoing investigations, living documentation.
</Info>

## When NOT to Save

* **Raw tool calls** — don't save every `edit`, `bash`, or `read` action
* **Trivial changes** — typo fixes, formatting, minor refactors
* **Work in progress** — save when a task is complete, not mid-implementation
* **Duplicate context** — if you already saved it, don't save again (unless using topic\_key for updates)

<Warning>
  The agent decides what's worth remembering. Only save high-signal observations — not a firehose of raw activity.
</Warning>

## Related Tools

* [`mem_search`](/mcp/mem-search) - Search saved observations
* [`mem_suggest_topic_key`](/mcp/mem-suggest-topic-key) - Generate stable topic keys for upserts
* [`mem_update`](/mcp/mem-update) - Update an existing observation by ID
* [`mem_session_summary`](/mcp/mem-session-summary) - Save end-of-session summaries
