Memory API
Base path: /api/memory
All endpoints require authentication. See API Overview for auth details.
Endpoints
Section titled “Endpoints”| Method | Path | Description |
|---|---|---|
GET | /api/memory/episodes | List episodes |
GET | /api/memory/episodes/{id} | Get an episode |
POST | /api/memory/episodes | Create an episode (inject memory) |
DELETE | /api/memory/episodes/{id} | Delete a single episode |
GET | /api/memory/episodes/{id}/related | Get related episodes |
GET | /api/memory/search | Full-text and semantic search |
GET | /api/memory/clusters | Get memory clusters |
GET | /api/memory/graph | Get the knowledge graph |
GET | /api/memory/stats | Get memory statistics |
POST | /api/memory/consolidate/conversations | Start a knowledge-graph rebuild job |
POST | /api/memory/generate-episodes | Start a job that generates and embeds episodes |
GET | /api/memory/jobs/{kind} | Status of a memory job (generate or consolidate) |
POST | /api/memory/backfill-entities | Backfill entity data for episodes |
GET | /api/settings/memory | Get memory settings |
PUT | /api/settings/memory | Update memory settings |
GET | /api/settings/memory/export | Export memory data as JSON |
DELETE | /api/settings/memory/data | Clear all memory data |
Episodes
Section titled “Episodes”List episodes
Section titled “List episodes”GET /api/memory/episodesQuery parameters:
| Parameter | Description |
|---|---|
limit | Max results (default: 20, max: 100) |
offset | Pagination offset (default: 0) |
cluster_id | Filter by cluster ID |
agent_id | Filter by agent ID |
Response:
{ "episodes": [ { "id": "ep_abc123", "content": "User asked about FastAPI dependency injection...", "summary": null, "source": "conversation", "valence": 0.24, "importance": 0.6, "access_count": 3, "created_at": "2026-03-02T14:00:00Z", "updated_at": "2026-03-02T14:00:00Z" } ], "total": 1247, "limit": 20, "offset": 0}Get an episode
Section titled “Get an episode”GET /api/memory/episodes/{id}Create an episode (inject memory)
Section titled “Create an episode (inject memory)”POST /api/memory/episodes{ "content": "Note: always use the snippbot_ prefix for database tables", "importance": 0.7, "valence": 0.0, "topics": ["conventions"], "agent_id": "agent_abc123"}Only content is required. All other fields are optional.
Use this to inject persistent instructions or context into an agent’s memory.
Delete an episode
Section titled “Delete an episode”DELETE /api/memory/episodes/{id}Deletes a single episode by ID.
Related episodes
Section titled “Related episodes”GET /api/memory/episodes/{id}/relatedReturns episodes related to the given episode.
Search
Section titled “Search”Full-text and semantic search
Section titled “Full-text and semantic search”GET /api/memory/search?q=database+migration+strategy&mode=hybrid&limit=10Searches across all episodes using the selected mode. Pass natural language queries to find conceptually related memories.
Query parameters:
| Parameter | Description |
|---|---|
q | Search query string (required) |
mode | Search mode: hybrid (default), keyword, or semantic |
limit | Max results (default: 10, max: 100) |
offset | Pagination offset (default: 0) |
start_date | ISO 8601 date filter (since) |
end_date | ISO 8601 date filter (until) |
source | Filter by episode source (e.g., conversation, task, insight) |
Response:
{ "query": "database migration strategy", "mode": "hybrid", "limit": 10, "offset": 0, "results": [ { "episode": { "id": "ep_abc123", "content": "User asked about database migration strategy...", "summary": null, "valence": 0.0, "importance": 0.6, "topics": [], "entities": [ { "id": "ent_xyz", "name": "Sql", "type": "concept", "mentions": 2 } ], "source": "conversation", "created_at": "2026-03-01T10:00:00Z" }, "score": 0.92, "source": "conversation", "highlights": ["...we decided on a **database migration strategy** that..."] } ], "total": 3}Clusters
Section titled “Clusters”GET /api/memory/clustersReturns memory clusters — groups of related episodes identified by the memory system.
Query parameters:
| Parameter | Description |
|---|---|
n | Number of clusters to compute (default: 4, range: 2-8) |
agent_id | Filter clusters for a specific agent |
Clusters are computed from episode embeddings, and laid out by the optional
memory visualization pack (scikit-learn + UMAP; see
feature packs). When there are no clusters, the response says
why in empty_reason:
empty_reason | Meaning |
|---|---|
no_episodes | The agent has no memories yet |
embeddings_unavailable | This install has no embedding backend (normally included); repair_command has the fix |
visualization_unavailable | The memory visualization pack isn’t installed |
missing_embeddings | Some memories have no embedding yet. POST /api/memory/generate-episodes embeds them |
too_few_embeddings | Everything is embedded, but there are too few memories to cluster |
The response also includes episodes_total, episodes_embedded,
embeddings_installed, repair_command (the non-destructive repair command
for this install), and visualization: {pack_id, installed, complete}.
Knowledge graph
Section titled “Knowledge graph”Get the graph
Section titled “Get the graph”GET /api/memory/graphReturns the full knowledge graph (entities and relationships).
Memory maintenance
Section titled “Memory maintenance”Consolidate from conversations
Section titled “Consolidate from conversations”POST /api/memory/consolidate/conversationsStarts a background job that uses the LLM to extract entities and relations from episodes into the knowledge graph. Episodes that were already extracted and haven’t changed are skipped. Extraction makes one LLM call per 5 episodes, so a run can take several minutes.
| Parameter | Description |
|---|---|
agent_id | Only process this agent’s episodes |
wipe | true clears the graph first and re-extracts everything |
Returns 202 with {"job": {...}}, or 409 with the running job if a rebuild
is already in progress. Poll GET /api/memory/jobs/consolidate
for progress and the result.
Generate episodes from conversations
Section titled “Generate episodes from conversations”POST /api/memory/generate-episodesStarts a background job that creates episodes from conversation history. It
then embeds every episode that has no embedding yet, including older ones
stored while the embedding model was unavailable. Exchanges that are already
stored as episodes are skipped, so running it again only adds new ones.
agent_id limits it to one agent.
Returns 202 with {"job": {...}}, or 409 if a job is already running. Poll
GET /api/memory/jobs/generate. The finished job’s result has
episodes_created, episodes_skipped, embeddings_generated, and a warning
if embeddings are unavailable.
Memory jobs
Section titled “Memory jobs”GET /api/memory/jobs/{kind}kind is generate or consolidate. Returns {"job": null} if no job has run
since the daemon started. Otherwise it returns the latest job:
{ "job": { "id": "memjob_1a2b3c4d5e6f", "kind": "consolidate", "agent_id": "steven", "params": { "wipe": false }, "status": "running", "started_at": "2026-09-25T16:35:24+00:00", "finished_at": null, "progress": { "phase": "extracting", "done": 10, "total": 42 }, "result": null, "error": null }}status is running, done, or error. Only one job of each kind runs at a
time. Job state is kept in memory, so it is cleared when the daemon restarts.
Backfill entities
Section titled “Backfill entities”POST /api/memory/backfill-entitiesBackfills entity extraction for episodes that were created before entity extraction was enabled.
Memory settings
Section titled “Memory settings”Memory settings are managed under the Settings API, not under /api/memory:
Get memory settings
Section titled “Get memory settings”GET /api/settings/memoryUpdate memory settings
Section titled “Update memory settings”PUT /api/settings/memoryExport memory data
Section titled “Export memory data”GET /api/settings/memory/exportReturns a JSON file containing all episodes and metadata as a download.
Clear all memory data
Section titled “Clear all memory data”DELETE /api/settings/memory/dataDeletes all episodes, the vector index, and the knowledge graph. This action is irreversible.
Response:
{ "cleared": 4821}Memory stats
Section titled “Memory stats”GET /api/memory/stats{ "total_episodes": 4821, "total_entities": 142, "total_relations": 389, "avg_importance": 0.54, "avg_valence": 0.12, "importance_distribution": [12, 45, 89, 210, 380, 920, 1100, 800, 180, 85], "source_distribution": { "conversation": 4200, "task": 400, "insight": 221 }, "entity_type_distribution": { "language": 12, "framework": 18, "tool": 30, "concept": 82 }, "recall_feedback": { "total_recalls": 320, "used_count": 210, "ignored_count": 110, "usage_rate": 0.66 }}Feature packs
Section titled “Feature packs”Optional features that Snippbot installs into its own environment after the user reviews exactly what will change. The packs are memory-visualization (Nebula clusters) and browser-chromium (the Chromium build the browser tool drives). The package list for each pack is fixed on the server; clients only choose the pack.
| Method | Path | Description |
|---|---|---|
GET | /api/features | Every optional feature with its status, plus the packs and the install kind (backs Settings → Features) |
GET | /api/features/packs | Every pack and whether it is installed |
GET | /api/features/packs/{id}/plan | What installing would do on this machine (admin) |
POST | /api/features/packs/{id}/install | Start the install job (admin). 202 {job}, or 409 if one is running |
GET | /api/features/packs/{id}/install | The latest install job and the pack’s status |
GET /api/features returns:
features: each feature’sid,title,kind(base,packorextra),source(the pack id or extra name),status(ok,missing,not-installedorunsupported),unsupported_reason,note, andcommand.commandis what a person runs to get a feature that isn’t there: the repair command for a missing base feature, or the version-pinned extra for an opt-in one. It isnullwhen there is nothing to run.packs: the same objects asGET /api/features/packsinstall:kind(pipx,uv-tool,editable,venvorsystem),label, and the installedversionrepair_command: the non-destructive repair command for this install
The plan runs pip install --dry-run against Snippbot’s own interpreter. It returns:
packages: each package with itsversion,action(new,upgrade,downgradeorreinstall),current_versionandsize_bytesdownloads: non-pip downloads such as Chromium, with their sizestotal_bytesskipped: optional packages with no build for this platform, with the reasoncommand: the exact command Snippbot will run (pipx inject,uv pip installorpip install, always--only-binary=:all:)blocked_reasonandmanual_command: set when Snippbot can’t install here, for example into a system Python marked externally managed
The install job reports progress.phase (installing, downloading or verifying) and progress.log, which is the tail of the installer output. When it finishes, the new modules can be imported immediately; no restart is needed.