memory_save
Persist decisions, conventions, and lessons to recall in future sessions. Captures rationale and context so knowledge survives across Claude Code sessions.
Instructions
Save a durable lesson, decision, or convention to persistent memory.
Use this to capture knowledge that should survive across Claude Code sessions: user preferences, architecture decisions with rationale, environment quirks, non-obvious bug fixes, or anything you'd otherwise have to re-explain in the next session.
Behaviour:
MUTATION. Writes a new markdown file under
/obsidian-brain/cortex/memories/, appends to the FTS5 index (/.cortex/search.db), updates ~/obsidian-brain/cortex/_index.md, and writes an append-only entry to ~/.cortex/events.jsonl. Writes are atomic (tmp + fsync + os.replace) and fcntl-locked.No authentication required. Local-first; no credentials.
No rate limits. Typical latency 50-200ms including the security scan, dedup check, and write sync.
Data access scope: writes stay entirely on the local filesystem. Nothing is sent over the network.
Not idempotent: calling twice with identical content triggers the dedup check and the second call returns a "Memory already exists" error instead of a duplicate write.
Failure modes: rejected inputs return a string error ("Memory already exists", "Memory rejected: "); they never raise to the caller.
Every save goes through:
Prompt-injection + credential-exfil security scan (rejects matches)
Fuzzy deduplication against existing memories (word+bigram+trigram overlap — rejects near-duplicates with clear reason)
Automatic related-memory linking (adds
relatedfrontmatter field)Write to Obsidian markdown file + FTS5 index + _index.md
Use memory_save for:
"We decided to use X because Y" (decision + rationale)
"User prefers small focused PRs, not big bundled ones" (preference)
"Database connection pool must be at least 20 for prod" (invariant)
"bcrypt.compare is async — always await" (gotcha)
Do NOT use for:
"Today I worked on X" (session logs — use transcript_search to find those)
Trivial facts easily re-discovered from reading code
Speculative or unverified claims
Duplicates of existing memories (the dedup check will reject them anyway)
Returns: A confirmation like "Memory saved: 63d6570e... 'JWT auth uses RS256'" on success, or an error message (starting with "Memory already exists" or "Memory rejected") on failure.
Example: memory_save( content="Use RS256 (not HS256) for JWT in production. HS256 " "requires sharing the signing secret across services " "which leaked via an env var export last quarter (#1247).", title="JWT algorithm — RS256 only in prod", tags="auth,jwt,security,postmortem", scope_id="my-webapp", )
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Comma-separated tag list (e.g. "auth,jwt,security"). Tags are used for filtering in `memory_list` and contribute to recall scoring. Keep them lowercase and topical. | |
| title | No | Short descriptive title, <120 characters. If empty, the first 60 chars of content are used. A good title is a declarative summary ("Use RS256 JWTs in prod"), not a question. | |
| content | Yes | The full memory body, written as natural-language prose. Should be atomic (one idea per save): capture ONE decision, convention, lesson, or preference with enough context to be useful in a future session. Include the rationale, not just the outcome. Max ~2000 characters recommended. | |
| scope_id | No | Project scope for the memory. "default" for cross-project global memories (user preferences, general lessons). A specific project name for project-scoped memories (e.g. "cortex-plugin", "my-webapp"). | default |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |