Reference
Search API
Run semantic and keyword search across your workspace memories. The search endpoint combines pgvector cosine similarity with keyword frequency scoring and ranks results using a weighted formula. Use it to surface relevant past decisions, patterns, and context before starting new work.
See Memory Concepts for how memories are structured, or Knowledge Base Ingestion cookbook for bulk ingestion patterns.
Base URL and Authentication
https://api.neuroloom.devAll requests require an API key:
Authorization: Token $MEMORIES_API_TOKENSearch Memories
POST /api/v1/memories/searchCombined keyword and semantic search. Results are ranked by a weighted formula and returned ordered by score descending.
Ranking Formula
score = (keyword_score × 0.3) + (semantic_score × 0.6) + (importance_score × 0.1)Semantic search uses pgvector cosine similarity on precomputed embeddings. It requires an OpenAI API key configured for the workspace — if not available, the endpoint falls back to keyword-only ranking.
memory_search(
query="database connection pooling strategy",
memory_types=["pattern", "decision"],
min_importance=0.6,
limit=10
)The MCP memory_search tool accepts one additional parameter not available in the REST API:
| Parameter | Type | Default | Description |
|---|---|---|---|
tag_prefixes | array of strings | — | Filter to memories whose tags start with any of these prefixes. Useful for namespaced tagging schemes. |
The memory_by_file MCP tool is a convenience wrapper that calls search with a files filter:
memory_by_file(
file_path="api/neuroloom_api/routers/memories.py",
limit=10
)import httpx, os
response = httpx.post(
"https://api.neuroloom.dev/api/v1/memories/search",
headers={"Authorization": f"Token {os.environ['MEMORIES_API_TOKEN']}"},
json={
"query": "database connection pooling strategy",
"memory_types": ["pattern", "decision"],
"min_importance": 0.6,
"limit": 10,
"use_semantic": True,
},
)
results = response.json()
for r in results["results"]:
print(r["memory"]["title"], r["score"])curl -X POST "https://api.neuroloom.dev/api/v1/memories/search" \
-H "Authorization: Token $MEMORIES_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "database connection pooling strategy",
"memory_types": ["pattern", "decision"],
"min_importance": 0.6,
"limit": 10
}'Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | No | "" | Free-text query used for both keyword matching and semantic similarity. Can be a question, phrase, or concept label. |
memory_types | array of strings | No | null | Filter to one or more memory type values (e.g. ["decision", "pattern"]). Note: plural field name, unlike the list endpoint's singular memory_type. |
tags | array of strings | No | null | Filter to memories that include ANY of these tags (OR semantics). |
files | array of strings | No | null | Filter to memories that reference ANY of these file paths. Note: this field is files, not source_files. |
min_importance | float | No | null | Only return memories with importance_score >= this value. |
min_confidence | float | No | null | Only return memories with confidence_score >= this value. |
use_semantic | boolean | No | true | Enable semantic (embedding) search. Set false for pure keyword search. |
limit | integer | No | 20 | Max results to return (min 1, max 200). |
offset | integer | No | 0 | Results to skip for pagination. |
The search endpoint uses memory_types (plural array) while the list endpoint uses memory_type (singular string). Using the wrong one silently drops your filter.
File filtering uses files (not source_files). Using source_files in a search request body is silently ignored.
Response
200 OK
{
"count": 2,
"query": "database connection pooling strategy",
"filters": {
"workspace_id": "ws-xyz789",
"memory_types": ["pattern", "decision"],
"tags": null,
"min_importance": 0.6
},
"results": [
{
"memory": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"memory_id": "mem-a1b2c3d4e5f6g7h8",
"workspace_id": "ws-xyz789",
"title": "Use connection pooling for all DB connections",
"narrative": "Configure SQLAlchemy with pool_size=10, max_overflow=20. Never create engines per-request — share a single engine per process.",
"memory_type": "pattern",
"tags": ["sqlalchemy", "database", "performance"],
"concepts": ["connection-pooling", "database"],
"source_files": ["api/neuroloom_api/database.py"],
"importance_score": 0.88,
"confidence_score": 0.9,
"pagerank_score": 0.45,
"community_label": "database-patterns",
"access_count": 8,
"retrieval_count": 22,
"created_at": "2026-03-15T10:00:00Z"
},
"score": 0.92,
"keyword_score": 0.0,
"semantic_score": 0.0,
"match_type": "combined"
}
]
}SearchResult fields
| Field | Type | Description |
|---|---|---|
memory | object | Full memory object. |
score | float | Combined ranking score, 0.0–1.0. |
keyword_score | float | Reserved for future use; currently always 0.0. |
semantic_score | float | Reserved for future use; currently always 0.0. |
match_type | string | Which component(s) contributed: "keyword", "semantic", or "combined". |
count is the number of results returned on this page, not a total record count. Search is bounded by limit. There is no total_count or cursor field.
Common Search Patterns
Find memories by file
Surface decisions and patterns captured while working on a specific file:
curl -X POST "https://api.neuroloom.dev/api/v1/memories/search" \
-H "Authorization: Token $MEMORIES_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"files": ["api/neuroloom_api/routers/memories.py"],
"limit": 20
}'Keyword-only search
Disable semantic ranking for exact phrase matching:
curl -X POST "https://api.neuroloom.dev/api/v1/memories/search" \
-H "Authorization: Token $MEMORIES_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "HNSW ef_construction",
"use_semantic": false,
"limit": 10
}'High-importance decisions only
Retrieve only well-established decisions above an importance threshold:
curl -X POST "https://api.neuroloom.dev/api/v1/memories/search" \
-H "Authorization: Token $MEMORIES_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "database schema migration strategy",
"memory_types": ["decision", "architecture"],
"min_importance": 0.8,
"limit": 5
}'Filter by tags
Find all memories tagged with specific labels:
curl -X POST "https://api.neuroloom.dev/api/v1/memories/search" \
-H "Authorization: Token $MEMORIES_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tags": ["pgvector", "performance"],
"limit": 20
}'Semantic Search Fallback
When semantic search is enabled (use_semantic: true) but embeddings are unavailable — either because the workspace has no OpenAI API key configured or because a memory's embedding has not yet been generated — the endpoint falls back to keyword-only ranking. Results are still returned; only the scoring changes.
To check whether a memory has an embedding, inspect whether pagerank_score is non-null (both are populated by the same background job). Embeddings are generated asynchronously after memory creation, typically within seconds.
Error Responses
| Status | When |
|---|---|
401 Unauthorized | Missing or invalid Authorization header. |
422 Unprocessable Entity | Invalid parameter value (e.g. limit > 200, min_importance > 1.0). |
{
"detail": [
{
"loc": ["body", "limit"],
"msg": "Input should be less than or equal to 200",
"type": "less_than_equal"
}
]
}Related
- What is a Memory — memory types, fields, and data model
- Memory Lifecycle — how importance scores affect search ranking
- Knowledge Base Ingestion — bulk ingestion patterns for semantic search