Memory
User and agent memory, daily logs, the entity graph, semantic search, and the five memory tools.
Sophon's memory system is what keeps the agent coherent across conversations. It stores facts, preferences, and daily activity; builds an entity graph of the people, projects, and places it knows about; and injects relevant context into every LLM call. The agent can write, read, search, forget, and traverse memory during any chat.
What gets remembered
There are two persistent memory surfaces:
Long-term memory — individual entries the agent (or you) chose to keep. Each entry has content, a category (fact, preference, or observation), a scope (user or agent), and is linked into an entity graph. Examples:
- fact — "Project Atlas ships on March 15"
- preference — "User prefers dark mode"
- observation — "User opens GitHub first thing most mornings"
Short-term memory (daily logs) — timestamped summary of what happened each day. One row per interaction; the agent reads the last two days on every turn.
[2026-04-22 10:30] Discussed Atlas deadline — confirmed Mar 15
[2026-04-22 14:15] Uploaded Q1-competitors.pdf; summarized to team
[2026-04-22 16:00] Sent email summary (approved)Daily logs capture context; long-term entries capture the durable conclusions you want to survive beyond the window.
Scopes — user vs agent
Every long-term entry has a scope:
| Scope | Visible to | Typical content |
|---|---|---|
user | Every agent you own | Cross-cutting facts — where you live, who your team is, your project list |
agent | Only the writing agent | Agent-specific preferences — "Ada always uses short bullets," "Nora speaks formal German" |
When the context assembler builds the system prompt, it fetches both: all user-scoped entries + the active agent's agent-scoped entries. So if you tell the writer agent to use formal tone, the research agent is unaffected.
The entity graph
Every memory entry is automatically linked to entities (people, projects, places, dates) that appear in the content. This turns your memories into a graph you can traverse.
Two extraction paths:
- LLM link extraction — when you write a memory, a fast-tier LLM scans it for named entities and wires them in.
- Wikilinks — you can write links explicitly with
[[Entity Name]]syntax and Sophon will parse them:
User is planning a trip to [[Tirana]] with [[Ermal]] for the [[Atlas launch]]That memory links to three entities — Tirana, Ermal, Atlas launch — and any future query that mentions any of those surfaces this entry too. The Dashboard Memory page renders the graph so you can see what knows what.
The five memory tools
The agent has five tools for working with memory:
memory.write
Saves a new entry. The agent calls this when it learns something worth keeping, or when you say "remember that…".
| Parameter | Required | Description |
|---|---|---|
content | yes | The text to remember |
category | no | fact, preference, or observation |
scope | no | user (default) or agent |
links | no | Explicit entity links to wire in addition to LLM extraction |
Risk: Medium — triggers auto-extraction of entities and a write. Not gated unless part of a plan.
memory.search
Semantic + keyword hybrid search. Returns the top matches with relevance scores.
| Parameter | Required | Description |
|---|---|---|
query | yes | Natural-language query |
scope | no | Limit to user, agent, or all |
limit | no | Max results (default 10) |
Risk: None — read-only.
memory.list
Paginated listing of entries (no search). Useful for "show me everything you remember about me."
| Parameter | Required | Description |
|---|---|---|
scope | no | user, agent, or all |
limit | no | Default 50 |
cursor | no | For pagination |
Risk: None.
memory.forget
Deletes an entry by ID. Irreversible — requires user approval.
| Parameter | Required | Description |
|---|---|---|
entryId | yes | The ID from memory.list or memory.search |
Risk: Medium — triggers approval gate. "Forget everything" is a separate, Critical-risk flow handled in the Dashboard, not via this tool.
memory.traverse
Walks the entity graph. Given a starting entity, returns the memories linked to it and (optionally) the memories linked to those memories, up to a depth.
| Parameter | Required | Description |
|---|---|---|
entity | yes | Entity name (e.g., "Atlas launch") |
depth | no | Graph traversal depth (default 1, max 3) |
Risk: None.
Context assembly — what the LLM actually sees
On every turn, the context assembler builds the system prompt:
You are Sophon, an intelligent AI personal assistant.
## Shared Memory (user scope)
- User lives in Tirana, Albania
- Project "Atlas" deadline is March 15
- Prefers TypeScript over JavaScript
## Agent Memory (this agent)
- Ada uses concise responses, no emoji
- Greet user as "Enes"
## Recent Activity (last 2 days)
[2026-04-21 09:15] Reviewed PR #423, merged
[2026-04-22 10:30] Discussed Atlas deadline
[2026-04-22 14:15] Uploaded competitors.pdf, summarizedBudgets:
- Up to 50 user-scoped entries
- Up to 50 agent-scoped entries
- Last 2 days of daily logs
- Last 100 chat messages
These caps keep the prompt from ballooning. If memory grows past them, the most relevant entries float to the top — long-term entries are scored against the current message and ranked.
Dashboard — the Memory module
The Dashboard has a Memory page at /memory with four tabs:
- Entries — paginated list of long-term entries. Filter by scope, category, agent. Add, edit, or delete.
- Logs — daily activity log. Filter by agent and date range.
- Search — hybrid search UI. Results show relevance scores.
- Graph — interactive entity graph. Click an entity to expand its neighbors.
Every entry has an ID you can reference in memory.forget or memory.traverse.
CLI
sophon memory search "project deadline"
sophon memory list --scope user --limit 20
sophon memory list --agent writer
sophon memory traverse "Atlas launch" --depth 2
sophon memory forget mem_abc123 # prompts for confirmationStorage by tier
| Tier | DB | Vector store | Semantic search |
|---|---|---|---|
| Personal | SQLite (~/.sophon/db/sophon.db) | — | Keyword only |
| Pro | PostgreSQL | Qdrant | Full semantic |
| Enterprise | PostgreSQL | Qdrant / Milvus / pgvector | Full semantic |
Schema:
MemoryEntries— long-term, indexed on(UserId, AgentId)+ tenantDailyLogEntries— short-term, indexed on(UserId, AgentId, CreatedAt)+ tenantMemoryEntities/MemoryLinks— the graph, indexed on entity name
SQLite DateTimeOffset doesn't sort in queries, so the engine sorts client-side after fetch. Postgres sorts natively.
Legacy MEMORY.md migration
If you're upgrading from pre-database versions that stored memory in ~/.sophon/memory/MEMORY.md and daily log files, Sophon migrates on first startup:
- Reads
MEMORY.md, treats each-bullet as auser-scoped long-term entry. - Reads
memory/daily/*.mdfiles, imports as daily log rows. - Skips migration if the DB already has entries (idempotent).
No manual step is required.
Security and isolation
- User isolation — every query filters by authenticated user ID. Cross-user reads are impossible.
- Agent isolation —
agent-scoped entries are visible only to the owning agent. - Tenant isolation (Enterprise) — EF Core global query filters enforce tenant boundaries on every query.
- No secrets in memory — the credential vault and memory are separate stores. API keys, OAuth tokens, and other secrets never land in memory and never leak into LLM prompts.
- Approval for forgets —
memory.forgetand any "forget all" operation trigger the approval gate. - Vector metadata filtering — semantic search filters results server-side by user + agent before returning, so a malformed query can't return someone else's memories.
Where to go next
- Agents & SOUL — scope and routing rules
- Approval Gates — why
memory.forgetgates - Connections — services that populate memory automatically