Neuroloom

Reference

Relationships API

Navigate the directed relationship graph that connects your workspace memories. Relationships are typed, directed edges discovered post-hoc by multiple heuristics: file overlap, concept overlap, embedding similarity, and session context. Use these endpoints to explore clusters of related knowledge, visualise how concepts connect, and find the shortest path between two memories.

See Relationships Concepts for a full explanation of relationship types and discovery methods.

Base URL and Authentication

https://api.neuroloom.dev

All requests require an API key:

Authorization: Token $MEMORIES_API_TOKEN

Relationship Types

ValueDirectionMeaning
referencesA → BA explicitly references or depends on B (file/symbol overlap)
related_toA → BGeneral semantic relatedness; default for heuristic discovery
caused_byA → BA is the consequence of B (LLM only; directed)
contradictsA ↔ BA and B conflict on the same topic (LLM only; symmetric)
supersedesA → BA replaces B; B is the older knowledge (LLM only; directed)
similar_toA ↔ BDiscovered by embedding cosine similarity (symmetric)
depends_onA → BA requires B to hold; never heuristic-assigned (LLM/manual only)

Get Raw Graph Data

GET /api/v1/memories/graph

Return all nodes and edges in the workspace's memory graph. Use this for full-graph visualisation or to build a local relationship index. For large workspaces, prefer the explore endpoint to fetch a bounded subgraph.

Response200 OK

{
  "nodes": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "title": "Prefer async SQLAlchemy for all DB calls",
      "memory_type": "pattern",
      "importance_score": 0.9,
      "pagerank_score": 0.51,
      "community_label": "database-patterns"
    }
  ],
  "edges": [
    {
      "source_memory_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "target_memory_id": "b9987766-5544-aabb-ccdd-eeff00112233",
      "relationship_type": "similar_to",
      "discovery_method": "embedding_similarity",
      "confidence": 0.87,
      "is_bidirectional": false,
      "created_at": "2026-03-20T09:00:00Z"
    }
  ]
}
curl "https://api.neuroloom.dev/api/v1/memories/graph" \
  -H "Authorization: Token $MEMORIES_API_TOKEN"
Note

pagerank_score and community_label are computed by the background graph analysis job. They are null for memories whose embeddings have not yet been processed.


Explore a Topic Subgraph

POST /api/v1/memories/explore

Seed a graph traversal with a query, then expand outward through relationship edges to return a bounded subgraph. Useful for understanding how a topic connects through your workspace knowledge, and for building contextual memory injections without retrieving the entire graph.

memory_explore(
  query="async database patterns and performance",
  max_nodes=30,
  relationship_types=["similar_to", "references", "related_to"],
  min_edge_confidence=0.7,
  seed_limit=5
)

The MCP memory_explore tool exposes all the same parameters as the REST endpoint.

import httpx, os

response = httpx.post(
    "https://api.neuroloom.dev/api/v1/memories/explore",
    headers={"Authorization": f"Token {os.environ['MEMORIES_API_TOKEN']}"},
    json={
        "query": "async database patterns and performance",
        "max_nodes": 30,
        "relationship_types": ["similar_to", "references", "related_to"],
        "min_edge_confidence": 0.7,
        "seed_limit": 5,
    },
)
subgraph = response.json()
print(f"Nodes: {len(subgraph['nodes'])}, Edges: {len(subgraph['edges'])}")
curl -X POST "https://api.neuroloom.dev/api/v1/memories/explore" \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "async database patterns and performance",
    "max_nodes": 30,
    "relationship_types": ["similar_to", "references", "related_to"],
    "min_edge_confidence": 0.7,
    "seed_limit": 5
  }'

Request body

FieldTypeRequiredDefaultDescription
querystringYesNatural language topic or question used to find seed memories via semantic search.
max_nodesintegerNo50Maximum nodes to include in the returned subgraph. Maximum value: 200.
relationship_typesarray of stringsNoall typesRestrict traversal to these edge types. Omit to traverse all relationship types.
min_edge_confidencefloatNo0.0Minimum edge confidence for an edge to be traversed. Set 0.7 or higher to filter noise.
seed_limitintegerNo5Number of seed memories to start the traversal from. Seeds are chosen by semantic similarity to query.

Response200 OK

{
  "nodes": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "title": "Prefer async SQLAlchemy for all DB calls",
      "memory_type": "pattern",
      "importance_score": 0.9,
      "pagerank_score": 0.51,
      "community_label": "database-patterns"
    },
    {
      "id": "c3344556-6677-ccdd-eeff-001122334455",
      "title": "Configure connection pool for production load",
      "memory_type": "decision",
      "importance_score": 0.82,
      "pagerank_score": 0.38,
      "community_label": "database-patterns"
    }
  ],
  "edges": [
    {
      "source_memory_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "target_memory_id": "c3344556-6677-ccdd-eeff-001122334455",
      "relationship_type": "references",
      "confidence": 0.81
    }
  ],
  "seed_memories": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
}

seed_memories lists the memory IDs used as traversal starting points. All remaining nodes were reached via graph traversal from those seeds.


Find Shortest Path

POST /api/v1/memories/path

Find the shortest relationship path between two memories using BFS traversal. Returns the sequence of memory IDs and the edges connecting them. Useful for understanding how two apparently unrelated concepts connect through the workspace's relationship graph.

Request body

FieldTypeRequiredDefaultDescription
source_memory_idstring (UUID)YesStarting memory UUID.
target_memory_idstring (UUID)YesDestination memory UUID.
max_depthintegerNo5Maximum BFS depth. Higher values find longer paths but take more time.
relationship_typesarray of stringsNoall typesRestrict path search to these edge types.

Response200 OK

{
  "path": [
    "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "c3344556-6677-ccdd-eeff-001122334455",
    "b9987766-5544-aabb-ccdd-eeff00112233"
  ],
  "edges": [
    {
      "source_memory_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "target_memory_id": "c3344556-6677-ccdd-eeff-001122334455",
      "relationship_type": "references",
      "confidence": 0.81
    },
    {
      "source_memory_id": "c3344556-6677-ccdd-eeff-001122334455",
      "target_memory_id": "b9987766-5544-aabb-ccdd-eeff00112233",
      "relationship_type": "references",
      "confidence": 0.91
    }
  ],
  "depth": 2
}

If no path exists within max_depth, returns:

{ "path": [], "edges": [], "depth": 0 }
curl -X POST "https://api.neuroloom.dev/api/v1/memories/path" \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_memory_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "target_memory_id": "b9987766-5544-aabb-ccdd-eeff00112233",
    "max_depth": 5,
    "relationship_types": ["references", "related_to", "similar_to"]
  }'

How Relationships Are Discovered

Relationships are created automatically by background jobs that run after each memory is stored or updated. The four discovery heuristics are:

MethodHow It Works
embedding_similaritypgvector cosine similarity between memory embeddings. Creates similar_to edges above a confidence threshold.
file_overlapMemories sharing one or more source_files entries. Creates references or related_to edges.
concept_overlapMemories sharing concepts labels. Creates related_to edges weighted by overlap count.
session_contextMemories created in the same session or temporally proximate sessions. Creates related_to edges.

Declare a Relationship Manually

The four heuristics above discover edges automatically. When you already hold ground-truth a heuristic can't reliably infer — this decision replaces that one, this task depends on that one — declare the edge yourself instead of waiting for discovery to find it. This is the same "declare what you know, the engine discovers what you don't" split that runs through the rest of Neuroloom: you assert the connections you're certain of, and the discovery pipeline keeps filling in the ones you didn't think to name.

POST /api/v1/relationships
DELETE /api/v1/relationships

Request body (POST)

FieldTypeRequiredDescription
source_idstring (UUID)YesSource memory id.
target_idstring (UUID)YesTarget memory id. Must differ from source_id.
relationship_typestringYes — no defaultOne of supersedes, related_to, depends_on. Every other type is discovery-only and rejected with a 422.
contextstringNoOptional human-readable explanation of why the relationship exists.

There is no workspace_id field — the workspace is resolved from your authenticated API key. The created edge is stamped discovery_method: "manual" and confidence: 1.0, both server-fixed and not caller-settable, and is immune to the nightly reclassifier that would otherwise silently retype a discovered edge.

curl -X POST "https://api.neuroloom.dev/api/v1/relationships" \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "target_id": "b9987766-5544-aabb-ccdd-eeff00112233",
    "relationship_type": "supersedes",
    "context": "Replaces the Redis-based caching approach."
  }'

Response201 Created

{
  "relationships": [
    {
      "id": "c3344556-6677-ccdd-eeff-001122334455",
      "source_memory_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "target_memory_id": "b9987766-5544-aabb-ccdd-eeff00112233",
      "relationship_type": "supersedes",
      "discovery_method": "manual",
      "confidence": 1.0,
      "is_bidirectional": false,
      "context": "Replaces the Redis-based caching approach.",
      "created_at": "2026-07-15T10:30:00Z"
    }
  ]
}

relationships is always a list — one row for a directed type (supersedes/depends_on), two mirrored rows for the symmetric related_to type.

DELETE /relationships retracts a manual edge, by relationship_id or by the natural key (source_id + target_id + relationship_type) — not both, not neither. Deleting a discovered (non-manual) edge returns 409.

Only supersedes, related_to, and depends_on are writable. contradicts is excluded because a false edge does asymmetric damage to the epistemic-confidence score it feeds; caused_by is excluded because it asserts a causal claim with its own liability if wrong. See Relationships Concepts for the full allowlist rationale, and the Decision Tracking cookbook for a worked example.


Error Responses

StatusWhen
401 UnauthorizedMissing or invalid Authorization header.
404 Not FoundA memory UUID supplied in the path request does not exist.
422 Unprocessable EntityInvalid parameter value (e.g. max_nodes > 200, unknown relationship_types value).
422 Unprocessable Entity (self_edge_not_allowed)POST /relationshipssource_id and target_id refer to the same memory. A memory cannot hold a relationship with itself.
422 Unprocessable Entity (excluded_relationship_type)POST /relationshipsrelationship_type is not one of the three caller-writable types (supersedes, related_to, depends_on). contradicts, caused_by, references, and similar_to are discovery-only.
409 Conflict (duplicate_manual_relationship)POST /relationships — a manual edge already exists between these two memories in this direction. Includes the cross-direction case: a manual related_to(A,B) edge mirrors to (B,A,manual), which blocks a later manual supersedes(B,A). Delete the existing edge and recreate it with the desired type instead.
409 Conflict (relationship_not_manual)DELETE /relationships — the targeted edge exists but was created by automatic discovery, not declared by a caller. Only manual edges can be deleted through this endpoint.
429 Too Many RequestsPOST/DELETE /relationships — the workspace has exceeded its relationship-write rate. Response includes a Retry-After header (uncoded — no code field).
429 Too Many RequestsPOST /relationships — the workspace has reached its manual-relationship edge-count cap, proportional to its memory count (uncoded — no code field). Delete unused manual edges, or ask us to raise the ceiling.

Ready to get started?

Start building with Neuroloom for free.

Start Building Free