Memory System

7 fields · 5 truth levels Core Invariant

What is the Memory System?

The memory system is xbrain's central invariant. Every piece of data — whether it comes from a chat, an agent, a Drive sync, or the Chrome extension — must pass through memory-api and carry exactly 7 mandatory tags. A write without any of these tags returns HTTP 422.

This is not a convention — it is enforced at the API level. The tagging contract is what makes scoped retrieval, truth-level promotion, team isolation, and audit logging possible. Remove the contract and xbrain becomes an ordinary vector database.

The Tagging Contract (7 Fields)

Enforced at the API level

Any POST to /v1/memory/upsert missing one of these 7 fields returns 422 Unprocessable Entity. This is enforced at the API level, not by convention. No exceptions.

Field Type Description Example
team_scope string Team identifier — hard isolation wall between teams. Team A can never see Team B's memories. "excalibur"
project_scope string | null Sub-project within the team. null means team-wide scope. "fundraising"
visibility enum Who can see this item within the team: team (all members), project (project members only), private (author only). "team"
confidence float Confidence score from 0.0 to 1.0. Set by the source (agent, user, or extraction pipeline). 0.85
truth_level enum Epistemic status of this data point. Progresses from EPHEMERAL to PUBLIC via the promotions workflow. "WORKING"
source string Who or what wrote this. Format: prefix:id. Used for attribution and audit. "librechat:conv_abc123"
validation_status enum Current validation state: pending (not yet reviewed), approved, rejected. "pending"

The 5 Truth Levels

Truth levels represent the epistemic status of a memory item. They form a one-way progression: you can promote a fact forward (e.g., WORKING → VALIDATED), but you cannot demote it. Promotion requires an explicit workflow — it cannot be done by patching the truth_level field directly.

EPHEMERAL Level 0 — Raw output

Raw output: chat messages, web clips, draft notes. Unverified. Expires or gets promoted. The default level for anything that enters xbrain without explicit classification.

WORKING Level 1 — In-progress knowledge

In-progress knowledge: actively used but not yet validated. Most team knowledge lives here. Facts the team is working with daily but has not yet formally reviewed.

VALIDATED Level 2 — Peer-reviewed

Peer-reviewed: at least one team member has explicitly approved this fact. Safe to reference in decisions and to surface in agent context.

CANONICAL Level 3 — Team truth

Team truth: the definitive answer your team has agreed on. CANONICAL facts are injected automatically in LLM system prompts during agent runs. Querying memory with truth_level_min=CANONICAL retrieves only authoritative facts.

PUBLIC Level 4 — Published externally

Published externally: shareable outside the team. Requires explicit promotion from CANONICAL. Only PUBLIC facts can be queried without a team_scope header.

Direct PATCH is blocked

truth_level can ONLY be promoted via the /v1/promotions workflow. A direct PATCH on truth_level returns HTTP 405 Method Not Allowed. This prevents bypassing the approval chain.

Promotion Workflow

To change a memory item's truth_level, a team member requests a promotion. An admin (or automated policy for lower levels) approves or rejects it.

bash — request a promotion# Any team member can request a promotion
POST /v1/promotions
{
  "item_id": "mem_abc123",
  "target_level": "VALIDATED",
  "justification": "Confirmed with the client on 2026-05-01"
}

# Admin approves the promotion
PATCH /v1/promotions/{promotion_id}
{
  "decision": "approved",
  "note": "Verified against signed contract doc"
}

Memory Upsert API

The primary write endpoint. Accepts a memory item with all 7 required fields. On success, returns the canonical id of the stored item. If the item already exists (same source + team_scope combination), it is updated in-place.

bashcurl -X POST https://api.grooveos.app/v1/memory/upsert \
  -H "Authorization: Bearer $JWT" \
  -H "X-Team-Scope: excalibur" \
  -H "Content-Type: application/json" \
  -d '{
    "item": {
      "content": "The Q2 fundraising target is 2M€",
      "team_scope": "excalibur",
      "project_scope": "fundraising",
      "visibility": "team",
      "confidence": 0.9,
      "truth_level": "WORKING",
      "source": "librechat:conv_abc123",
      "validation_status": "pending"
    }
  }'

# Response
{"id": "mem_a8f3c2d1..."}

Upsert with metadata and entities

Include an entities array in metadata to trigger automatic Neo4j graph enrichment:

json{
  "item": {
    "content": "Alice leads the fundraising project",
    "team_scope": "excalibur",
    "project_scope": "fundraising",
    "visibility": "team",
    "confidence": 0.85,
    "truth_level": "WORKING",
    "source": "agent-runtime:run_xyz789",
    "validation_status": "pending",
    "metadata": {
      "entities": [
        {"name": "Alice", "type": "person"},
        {"name": "fundraising", "type": "project"}
      ]
    }
  }
}

Semantic Search

Search memory items by natural language query. Results are filtered by team_scope automatically — Team A can never see Team B's memories. Use truth_level_min to restrict results to a minimum epistemic level.

bashcurl "https://api.grooveos.app/v1/memory/search?q=fundraising+target&truth_level_min=WORKING&limit=5" \
  -H "Authorization: Bearer $JWT" \
  -H "X-Team-Scope: excalibur"

Search parameters

Parameter Type Default Description
q string required Natural language search query. Converted to embedding by memory-api.
truth_level_min enum EPHEMERAL Minimum truth level filter. CANONICAL returns only authoritative facts.
project_scope string null Filter by project. Omit for all projects within the team.
limit integer 10 Maximum number of results. Max 100.
visibility enum team Filter by visibility level.

Neo4j Graph Enrichment

When a memory item includes an entities field in its metadata, memory-api asynchronously creates Entity nodes and MENTIONS edges in Neo4j. This builds a knowledge graph of who mentions what, across all conversations and agents.

Query relationships after they've been built:

bashcurl "https://api.grooveos.app/v1/graph/neighbors?entity=Alice" \
  -H "Authorization: Bearer $JWT" \
  -H "X-Team-Scope: excalibur"

# Returns: Alice's connected entities, co-mentioned projects, relationships

The Neo4j enrichment is async and fail-soft: if the Neo4j container is down or the worker is backed up, the memory upsert still returns 200. The entity processing is retried when Neo4j recovers.

Graphiti Enrichment

Every memory upsert triggers an async call to graphiti-service, which extracts temporal facts and updates the knowledge graph with time-aware relationships. Graphiti understands sentences like "Alice was the lead until Q2" and creates time-bounded edges rather than static ones.

Fail-soft by design

If graphiti-service is down, the memory upsert still succeeds. The graphiti enrichment is queued and retried when the service recovers. You can track enrichment backlog via GET /v1/graph/queue-status.

Why temporal facts matter

Standard knowledge graphs store facts as static triples: Alice → WORKS_ON → fundraising. Graphiti adds temporal context: Alice → WORKS_ON → fundraising [2026-01-01 to 2026-04-30]. When an agent retrieves context for a question about Q1, it gets the correct team structure for that period — not the current one.

See Graphiti documentation for the full extraction pipeline, configuration options, and query examples.

Error Reference

HTTP Status When Resolution
422 One or more of the 7 required fields is missing from the request body Check that all 7 fields are present: team_scope, project_scope, visibility, confidence, truth_level, source, validation_status
405 Attempted direct PATCH on truth_level field Use the /v1/promotions workflow instead
401 Missing or expired JWT in Authorization header Re-authenticate and obtain a fresh JWT
403 team_scope in request does not match X-Team-Scope header Ensure the JWT's team claim and the request body's team_scope match
404 item_id not found (for promotions or graph queries) Verify the memory item ID exists in the correct team_scope