Skip to content

Relationship Operations

The /associate endpoint creates typed relationships between memories to build a knowledge graph in FalkorDB. These associations enable graph traversal during recall, allowing multi-hop reasoning and discovery of related context beyond direct semantic similarity.

Unlike semantic similarity (which is computed automatically via vector embeddings), associations capture explicit logical relationships such as causation (LEADS_TO), evolution (EVOLVED_INTO), or contradiction (CONTRADICTS).

Associations serve two primary purposes:

  1. Structural Knowledge Graph — Organize memories into a queryable graph with semantic meaning
  2. Enhanced Recall — Surface related memories during graph expansion that semantic search alone would miss

POST /associate
Content-Type: application/json
Authorization: Bearer <AUTOMEM_API_TOKEN>

Key characteristics:

  • Creates directed edges (memory1 → memory2)
  • Requires both memories to exist in FalkorDB
  • Stores relationships as graph edges, not separate nodes
  • Supports 11 semantic relationship types
  • Optional strength score (0.0–1.0) for weighting connections

FieldTypeRequiredDescription
memory1_idstringYesSource memory UUID
memory2_idstringYesTarget memory UUID
typestringYesRelationship type (must be in ALLOWED_RELATIONS)
strengthfloatNoEdge weight 0.0–1.0 (default: 0.5)
propertiesobjectNoAdditional edge metadata (stored in graph)
Terminal window
curl -X POST https://your-automem-instance/associate \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"memory1_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"memory2_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"type": "LEADS_TO",
"strength": 0.9
}'
Terminal window
curl -X POST https://your-automem-instance/associate \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"memory1_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"memory2_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"type": "PREFERS_OVER",
"strength": 0.9,
"properties": {
"reason": "ACID compliance required",
"context": "transaction-heavy workload"
}
}'

AutoMem supports 11 semantic relationship types that enable rich knowledge graph construction.

graph TB
    subgraph "Causal & Temporal"
        M1["Memory: Problem"]
        M2["Memory: Solution"]
        M3["Memory: Planning"]
        M4["Memory: Execution"]

        M1 -->|LEADS_TO| M2
        M3 -->|OCCURRED_BEFORE| M4
    end

    subgraph "Preference & Pattern"
        M5["Memory: PostgreSQL Decision"]
        M6["Memory: MongoDB Evaluation"]
        M7["Memory: Code Review"]
        M8["Memory: Best Practice"]

        M5 -->|PREFERS_OVER| M6
        M7 -->|EXEMPLIFIES| M8
    end

    subgraph "Knowledge Evolution"
        M9["Memory: Initial Design"]
        M10["Memory: Final Design"]
        M11["Memory: Old Docs"]
        M12["Memory: New Docs"]

        M9 -->|EVOLVED_INTO| M10
        M11 -->|INVALIDATED_BY| M12
    end

    subgraph "Hierarchical"
        M13["Memory: User Story"]
        M14["Memory: Epic"]
        M15["Memory: Feature Spec"]
        M16["Memory: Implementation"]

        M13 -->|PART_OF| M14
        M16 -->|DERIVED_FROM| M15
    end
TypeDirectionUse CaseExample
RELATES_TOBidirectionalGeneral connection, default choiceBug report → Related issue
LEADS_TOA → B (Causal)Cause → Effect, A caused/resulted in BProblem analysis → Solution implemented
OCCURRED_BEFOREA → B (Temporal)Earlier → Later (without causation)Planning meeting → Execution sprint
PREFERS_OVERA → B (Preference)Chosen → RejectedPostgreSQL → MongoDB
EXEMPLIFIESB → A (Pattern)Concrete example → Abstract patternCode review feedback → Best practice rule
CONTRADICTSBidirectionalConflicting informationAlternative approach A ↔ Alternative approach B
REINFORCESB → A (Supporting)Additional evidence strengthening originalPerformance test → Design decision
INVALIDATED_BYA → B (Superseding)Outdated → CurrentOld documentation → Updated docs
EVOLVED_INTOA → B (Evolution)Initial → Final formDraft design → Shipping implementation
DERIVED_FROMB → A (Source)Implementation → SpecFeature code → Requirements document
PART_OFB → A (Hierarchical)Component → ContainerUser story → Epic

The /associate endpoint enforces the following validation:

  1. Memory Existence: Both memory1_id and memory2_id must reference existing Memory nodes in FalkorDB
  2. Relationship Type: type must be in the ALLOWED_RELATIONS configuration set
  3. Strength Bounds: If provided, strength must be between 0.0 and 1.0 (inclusive)
  4. Required Fields: memory1_id, memory2_id, and type are mandatory
  5. Authentication: Valid AUTOMEM_API_TOKEN required via Authorization header
flowchart TD
    Request["POST /associate Request"]
    AuthCheck{"Valid API Token?"}
    FieldCheck{"Required Fields Present?"}
    TypeCheck{"type in ALLOWED_RELATIONS?"}
    StrengthCheck{"strength in 0.0-1.0?"}
    Memory1Check{"memory1_id Exists?"}
    Memory2Check{"memory2_id Exists?"}
    CreateEdge["Create FalkorDB Edge"]
    Success["Return 201 Success"]

    Err401["401 Unauthorized"]
    Err400Field["400 Missing Field"]
    Err400Type["400 Invalid Type"]
    Err400Strength["400 Invalid Strength"]
    Err404Mem1["404 Memory1 Not Found"]
    Err404Mem2["404 Memory2 Not Found"]
    Err503["503 FalkorDB Unavailable"]

    Request --> AuthCheck
    AuthCheck -->|No| Err401
    AuthCheck -->|Yes| FieldCheck
    FieldCheck -->|No| Err400Field
    FieldCheck -->|Yes| TypeCheck
    TypeCheck -->|No| Err400Type
    TypeCheck -->|Yes| StrengthCheck
    StrengthCheck -->|No| Err400Strength
    StrengthCheck -->|Yes| Memory1Check
    Memory1Check -->|No| Err404Mem1
    Memory1Check -->|Yes| Memory2Check
    Memory2Check -->|No| Err404Mem2
    Memory2Check -->|Yes| CreateEdge
    CreateEdge -->|Success| Success
    CreateEdge -->|DB Down| Err503

{
"status": "success",
"relationship": {
"memory1_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"memory2_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"type": "LEADS_TO",
"strength": 0.9,
"created_at": "2025-01-15T10:30:00Z"
}
}

404 Not Found — One or both memories don’t exist:

{
"error": "Memory not found: a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

400 Bad Request — Invalid relationship type:

{
"error": "Invalid relationship type: INVALID_TYPE. Must be one of: RELATES_TO, LEADS_TO, ..."
}

400 Bad Request — Missing required fields:

{
"error": "Missing required field: memory2_id"
}

503 Service Unavailable — FalkorDB unavailable:

{
"error": "Graph database unavailable"
}

Relationships are stored as edges in FalkorDB, not as separate nodes. This enables efficient graph traversal queries.

The endpoint executes a Cypher MERGE query to create or update the relationship:

MATCH (m1:Memory {id: $id1})
MATCH (m2:Memory {id: $id2})
MERGE (m1)-[r:LEADS_TO]->(m2)
SET r.strength = $strength,
r.created_at = $created_at
graph LR
    M1["Memory Node<br/>id: mem-1<br/>content: 'PostgreSQL'<br/>type: Decision"]
    M2["Memory Node<br/>id: mem-2<br/>content: 'MongoDB'<br/>type: Decision"]

    M1 -->|"PREFERS_OVER<br/>strength: 0.9<br/>reason: 'ACID'<br/>created_at: '2025-01-15'"| M2
AspectImplementation
Storage LayerFalkorDB only (not replicated to Qdrant)
Edge DirectionDirected (m1 → m2)
Edge LabelRelationship type (e.g., :PREFERS_OVER)
Edge Propertiesstrength, created_at, custom properties from properties field
IndexingFalkorDB automatically indexes edge types for traversal
Query CostO(1) for direct edge lookup, O(k) for k-hop traversal

Relationships created via /associate are utilized during recall operations when expand_relations=true is specified. See Recall Operations for the full parameter reference.

ParameterDefaultDescription
expand_relationstrueEnable graph traversal from seed results
relation_limit5Max edges to follow per seed memory
expansion_limit25Total max expanded memories to return
expand_min_strength0.0Minimum edge strength to traverse
expand_min_importance0.0Minimum importance of expanded memories

Relationship strength contributes to the hybrid scoring formula:

relation_score = Σ (edge.strength × related_memory.importance)
final_score = vector_score × 0.25
+ keyword_score × 0.15
+ relation_score × 0.25 ← Relationship contribution
+ ... (6 other components)

Relationships enable AutoMem to answer queries requiring multiple traversal steps.

Example: “What is Sarah’s sister’s job?”

Section titled “Example: “What is Sarah’s sister’s job?””

Step 1: Store memories with relationships:

// Memory 1
{ "content": "Sarah's sister is Rachel", "tags": ["family", "sarah", "rachel"] }
// Memory 2
{ "content": "Rachel is a software engineer at Tech Corp", "tags": ["career", "rachel"] }

Create association:

{
"memory1_id": "<id of memory 1>",
"memory2_id": "<id of memory 2>",
"type": "RELATES_TO",
"strength": 0.95
}

Step 2: Query with entity expansion:

Terminal window
curl "https://your-automem-instance/recall?query=Sarah%27s+sister%27s+job&expand_entities=true" \
-H "Authorization: Bearer YOUR_TOKEN"

Step 3: AutoMem traverses the graph:

graph TB
    Query["Query: 'What is Sarah's sister's job?'"]
    Entity["Entity Extraction:<br/>sarah, sister, job"]

    Seed["Seed Memory:<br/>'Sarah's sister is Rachel'<br/>tags: family, sarah, rachel"]

    Related1["RELATES_TO (0.95)"]
    Bridge["Related Memory:<br/>'Rachel is a software engineer'<br/>tags: career, rachel"]

    Related2["RELATES_TO (0.8)"]
    Context["Context Memory:<br/>'Tech Corp projects'<br/>tags: work, tech-corp"]

    Result["Answer:<br/>'Rachel is a software engineer at Tech Corp'"]

    Query --> Entity
    Entity --> Seed
    Seed --> Related1
    Related1 --> Bridge
    Bridge --> Related2
    Related2 --> Context

    Bridge --> Result
    Context --> Result

The associate_memories MCP tool corresponds to POST /associate.

ParameterTypeRequiredConstraintsDescription
memory1_idstringYesSource memory ID (from store_memory or recall_memory results)
memory2_idstringYesTarget memory ID to link to
typestring (enum)Yes11 predefined typesRelationship type
strengthnumberYes0.0–1.0Relationship strength

Relationship type enum values:

  1. RELATES_TO — General relationship
  2. LEADS_TO — Causal relationship
  3. OCCURRED_BEFORE — Temporal ordering
  4. PREFERS_OVER — Chosen alternative
  5. EXEMPLIFIES — Concrete example of pattern
  6. CONTRADICTS — Conflicts with
  7. REINFORCES — Strengthens validity
  8. INVALIDATED_BY — Superseded by
  9. EVOLVED_INTO — Updated version
  10. DERIVED_FROM — Implementation of decision
  11. PART_OF — Component of larger effort
FieldTypeRequiredDescription
successbooleanYesWhether association was created
messagestringYesConfirmation message

The tool is annotated idempotentHint: true — creating the same relationship multiple times is safe (MERGE semantics).

sequenceDiagram
    participant Client
    participant Flask["@app.route('/associate')<br/>POST"]
    participant Falkor["FalkorDB"]

    Client->>Flask: POST /associate<br/>{memory1_id, memory2_id, type}
    Flask->>Flask: validate relationship type
    Flask->>Falkor: MATCH (m1:Memory {id: $id1})<br/>MATCH (m2:Memory {id: $id2})
    Flask->>Falkor: MERGE (m1)-[r:TYPE]->(m2)
    Flask->>Falkor: SET r.strength = $strength
    Flask-->>Client: 200 OK

The strength parameter (0.0–1.0) quantifies the confidence or importance of the relationship. This value is used during graph expansion to filter weak connections via the expand_min_strength parameter in recall_memory.

RangeInterpretationExamples
0.9–1.0Direct causation, critical dependencyBug fix directly caused by root cause discovery; feature implementation directly derived from architecture decision
0.7–0.9Strong relationship, high confidencePattern strongly relates to multiple implementations; new decision reinforces established convention
0.5–0.7Moderate relationship, relevant connectionFeature relates to broader system architecture; alternative approach considered during decision
0.3–0.5Weak relationship, tangential connectionLoosely related topics; historical context with minimal current relevance
< 0.3Very weak — consider not creatingRisk of noise during graph expansion

Always create immediately:

  • User corrections (always link to what was corrected)
  • Bug fixes (link to root cause if stored separately)
  • Decisions (link to rejected alternatives)

Defer until meaningful:

  • Pattern discovery (wait to accumulate examples before linking)
  • Speculative relationships (verify the connection is meaningful first)

Target: 1–3 associations per stored memory. Avoid creating RELATES_TO for memories that are already semantically similar — vector search will find those automatically.

When a user corrects a previous statement or approach, link the correction to what was corrected:

// Store the correction
{ "content": "Do NOT use --force flag with git push to main", "importance": 0.95 }
// Associate: old approach INVALIDATED_BY new correction
{
"memory1_id": "<old approach memory id>",
"memory2_id": "<new correction memory id>",
"type": "INVALIDATED_BY",
"strength": 0.95
}

Rationale: Prevents the AI from repeating invalidated approaches. During recall, if the old memory surfaces, the INVALIDATED_BY relationship signals it has been superseded.

Link bug fixes to their root cause discoveries:

// Bug discovery → Bug fix
{
"memory1_id": "<bug discovery memory id>",
"memory2_id": "<bug fix memory id>",
"type": "LEADS_TO",
"strength": 0.9
}
// Bug fix ← Architecture decision (fix derived from)
{
"memory1_id": "<bug fix memory id>",
"memory2_id": "<architecture decision memory id>",
"type": "DERIVED_FROM",
"strength": 0.8
}

Rationale: Creates a causal chain from problem discovery through resolution. If a similar bug occurs, graph expansion can traverse from the new bug discovery to related fixes.

Architectural Decisions (PREFERS_OVER, PART_OF)

Section titled “Architectural Decisions (PREFERS_OVER, PART_OF)”
// Chosen solution → Rejected alternative
{
"memory1_id": "<PostgreSQL decision memory id>",
"memory2_id": "<MongoDB evaluation memory id>",
"type": "PREFERS_OVER",
"strength": 0.9
}

Rationale: Captures the decision context (why A was chosen over B) and system structure (how components relate to the whole).

Pattern Evolution (EVOLVED_INTO, EXEMPLIFIES)

Section titled “Pattern Evolution (EVOLVED_INTO, EXEMPLIFIES)”

Track how patterns change over time and connect abstract patterns to concrete examples:

// Old approach → New approach
{
"memory1_id": "<old pattern memory id>",
"memory2_id": "<new pattern memory id>",
"type": "EVOLVED_INTO",
"strength": 0.85
}
// Specific example → General pattern
{
"memory1_id": "<specific fix memory id>",
"memory2_id": "<general pattern memory id>",
"type": "EXEMPLIFIES",
"strength": 0.75
}

When deprecating old information, combine update_memory and associate_memories:

// 1. Update the old memory to flag it as outdated
PATCH /memory/<old-id>
{ "metadata": { "deprecated": true, "superseded_by": "<new-id>" } }
// 2. Associate: old EVOLVED_INTO new
{
"memory1_id": "<old memory id>",
"memory2_id": "<new memory id>",
"type": "EVOLVED_INTO",
"strength": 0.9
}

This pattern is preferred over deletion because it preserves history and provides context for why the approach changed.


Use PREFERS_OVER when:

  • Documenting user preferences (PostgreSQL over MongoDB)
  • Recording rejected alternatives
  • Establishing decision hierarchies

Use DERIVED_FROM when:

  • Linking implementation to specifications
  • Connecting code to requirements
  • Tracing decisions to principles

Use EVOLVED_INTO when:

  • Tracking design iterations
  • Recording refactoring history
  • Documenting process improvements

Use EXEMPLIFIES when:

  • Connecting instances to patterns
  • Building pattern libraries
  • Reinforcing best practices

Most relationships are directed (one-way):

  • LEADS_TO: Problem → Solution (not Solution → Problem)
  • INVALIDATED_BY: Old → New (not New → Old)
  • PART_OF: Component → Whole (not Whole → Component)

Use RELATES_TO for bidirectional general connections where direction doesn’t matter.

Over-association: Creating relationships for every possible connection adds noise to graph expansion and increases query latency.

Weak relationships: Associations with strength < 0.3 are rarely worth creating unless you have specific intent for that connection.

Wrong direction: Using LEADS_TO with (solution → problem) instead of (problem → solution) inverts the causal chain and confuses traversal.


To verify associations are working, use expand_relations with low thresholds during recall:

Terminal window
curl "https://your-automem-instance/recall?query=database+decisions&expand_relations=true&expand_min_strength=0.0&relation_limit=10" \
-H "Authorization: Bearer YOUR_TOKEN"

The relations field in recall results shows the relationship metadata for expanded memories, including type and strength.


Association storage cost (low):

  • Single edge creation in FalkorDB (O(1) write)
  • No vector embedding computation required
  • No impact on Qdrant

Recall expansion cost (moderate):

  • Each seed memory can trigger up to relation_limit edge traversals
  • Each expanded memory requires a Qdrant lookup for its vector embedding
  • Recommendation: Use expand_min_strength and expand_min_importance to limit expansion

Bi-directional traversal: FalkorDB supports efficient traversal in both directions — forward (m1 → m2 outgoing) and backward (m2 ← m1 incoming). The recall expansion follows edges in both directions by default, so a single LEADS_TO relationship enables discovery from either end.