memory_add
Every memory stored through Gnosis carries a type, topic tags, and content that follows a quality contract enforced through tool descriptions. The AI reads these constraints before every call. No server-side AI rewrites your content — the protocol itself teaches structured creation.
The Type System
Seven types. Each changes how a memory is stored, searched, and surfaced. Pick the wrong type and it still works — but the right type makes retrieval dramatically better.
fact
Knowledge that is true right now. One fact per memory. Default type if unspecified.
preference
How someone likes things done. First topic must be user. Add behavioral to auto-load every session.
Preferences tagged behavioral are injected into every session via init_core_memories. Preferences without that tag are search-only — found when relevant, not loaded by default.
decision
A choice that was made, with the reasoning. Prevents relitigating settled questions across sessions.
path
Where something lives — and what it is. The address alone is useless without context.
Tool descriptions explicitly teach: "Workspace is at /opt/project" is bad. "Chat backend lives at /opt/project — Express + Socket.io server" is good.
task
Actionable work with 3–10 milestone steps. Max 500 tokens. Larger work splits into multiple tasks linked by shared topics.
task_done
Completed work. You don't set this type directly — it's applied automatically when a task's status moves to done. If the status reverts, the type reverts back to task.
result
Agent-produced output linked to a task. Created via the output parameter on memory_edit. Intentionally demoted in search ranking so findings don't crowd out the source tasks and decisions they came from.
Cross-type deduplication
A task about OAuth is not a duplicate of a decision about OAuth. The deduplication engine compares incoming content against existing memories of the same type only. Cross-type matches are silently ignored, even at high similarity scores.
Content Quality Contract
First 50 Characters = Executive Summary
Every memory must make sense with zero context. The first 50 characters are effectively the subject line — truncated previews in search results show only this much. Name the subject, state the fact, include why.
The rules are not suggestions. They're embedded in the tool description that the AI reads before every memory_add call. The tool description contains explicit good/bad examples, reasoning steps the AI must follow before generating parameters, and format constraints. This is the quality mechanism — no server-side AI, no post-processing, just a protocol that makes good output the path of least resistance.
No subject. No reason. Useless in six months.
Prefixed with tags that belong in the topics field, not the content.
Names the subject (User), states the preference (Python for backend), includes why (type safety).
Additional constraints enforced through the tool description:
- One fact per memory. Compound memories degrade search — a memory about both Redis caching and database indexing gets retrieved for neither query with high confidence.
- Present tense. Memories describe current state. Past tense signals stale information.
- Self-contained. Conversation context is not stored. Only the content field survives. A memory that says "the approach we discussed" is meaningless in a future session.
- Aspirational tagging. Anything that hasn't happened yet — a task not started, a tool not installed, a preference not tested — must include
aspirationalin topics. Without this tag, a future session treats it as fact.
Topic System
Two required arrays drive retrieval from different angles.
topics[]
Search keywords. The question to ask: "What would someone type to find this memory?" Single lowercase words, no underscores or hyphens. A memory about Redis caching for sessions should include redis even if the memory is primarily about session management.
Both arrays are mandatory. Topics are injected into the searchable text alongside content, directly influencing vector similarity during retrieval.
macro_topics[]
The project or domain name. One to three entries. If you're working on a MealPlanner feature, it's ["mealplanner"]. A general Python tip is ["python"]. If the project name is unknown, use the primary technology.
Macro topics are wrapped in brackets in the searchable text — [mealplanner] redis sessions caching ttl: content... — separating project context from specific terms.
Do not repeat macro_topics in topics. They serve different retrieval functions and the system handles both independently.
Advanced Fields
ref — Parent Task Clustering
Set ref to a task's short-id (first 8 characters of its UUID) when storing findings related to that task. The ref value is automatically injected into topics — no need to duplicate it manually.
The result: searching for a task ID returns both the task itself and every finding linked to it. This creates discoverable clusters of related work without any folder structure or manual organization.
artifact — External Work Pointer
A commit SHA or filename where the actual implementation lives. Like ref, it's auto-injected into topics for searchability.
Searching for the commit SHA or filename later surfaces the memory explaining what changed and why.
collection — Shared Namespace
Controls which namespace receives the memory. Three values:
- Omit — writes to your default collection if one is configured, otherwise to your personal namespace.
"me"— always writes to your personal namespace, bypassing any default collection.- Collection name — writes to that shared collection (you must be a member with write access).
If your MCP server is configured with a default collection (via ?default_collection= or X-Default-Collection), omitting the parameter writes there — not to personal. Use "me" to override.
signal — Store and Notify
Pass a recipient (email or agent name) to immediately signal them after storing. Combines memory_add + signal(action:send) in one call. Requires a collection — signals route through shared namespaces.
ephemeral / expires_at — Time-Bound Memories
ephemeral: true sets auto-expiry at 90 days. For precise control, expires_at accepts a YYYY-MM-DD date and overrides ephemeral. Pass "never" to clear an existing expiry.
Expired memories are removed from search results. Useful for temporary context: sprint goals, short-lived API keys documentation, or meeting-specific notes.
Task Creation and Lifecycle
Tasks can be created two ways: structured mode (recommended) or raw content.
Structured Mode
Pass title + steps[] + optional status. The server renders a markdown blob with checkboxes. Maximum 10 steps — these are high-level milestones, not micro-plans. The executing agent's plan mode handles sub-steps. If work needs more than 10 milestones, split into multiple tasks linked by shared topics.
The server renders structured input into a normalized format:
Status follows a defined workflow:
pending
Default. Omitted from the rendered blob.
active
Work in progress.
blocked
Waiting on dependency.
review
Work done, awaiting human review.
done
Auto-sets type to task_done.
Tasks without checkboxes are treated as atomic — completion is all-or-nothing. Tasks with checkboxes support surgical operations through memory_edit: toggle individual steps by index, add or remove steps, rewrite step text, and attach output findings to specific steps.
The output field — linked findings
When toggling a task step via memory_edit, the optional output parameter attaches a durable finding as a separate result-type memory. The result inherits the task's topics and macro_topics, plus the task's short-id as a ref. This means searching for the task ID surfaces the task and all its findings together.
Output follows the same quality contract as memory_add: first 50 characters are the summary, self-contained, one atomic finding per call. Under 500 tokens. For operational receipts (deploy logs, timing data), don't use output — it's for findings worth keeping in search permanently.
Deduplication
Every memory_add call runs a duplicate check before storing. The process is two-stage:
- Vector similarity search — the incoming content is embedded and compared against existing memories of the same type in the target namespace (personal or collection). High-similarity matches are flagged.
- Cross-encoder reranking — embedding similarity can false-positive on shared keywords. A reranker with cross-attention validates whether the match is a genuine duplicate or just keyword overlap. Matches scoring below the reranker threshold are silently rejected as false positives.
When a duplicate is detected, the response returns the existing memory with its similarity score. The AI then decides: edit the existing memory, reword and retry, or force-add if it's genuinely different. The system never silently drops content — it surfaces the conflict and lets the caller resolve it.
Structured tasks (created with title + steps) skip deduplication entirely. Short, similarly-worded task titles produce too many false positives for the check to be useful.
The force flag bypasses deduplication. It exists for testing. In production use, the duplicate check is the right default.
Batch Mode
For three or more memories, use memory_add_batch. Each memory in the batch is independently typed, tagged, and deduplicated. The same quality rules apply — the batch tool description explicitly references the memory_add guidelines and adds batch-specific constraints.
Batch calls share a single network round-trip. Each memory gets its own embedding, its own deduplication check, and its own type validation. A failure on one memory does not block the others.