For AI agents

AI systems make decisions. InvariantDB proves what they knew, when they knew it, and why they changed their mind.

Your agent recalls a customer risk score from Tuesday. On Wednesday the underlying evidence is retracted. On Thursday an auditor asks: what did the agent actually see when it approved the loan? InvariantDB answers with one Cypher line — because valid time and recorded time are first-class query verbs, and every belief carries lineage.

MCP-native · 14 tools Bitemporal · two clocks, first-class Belief revision + lineage Crypto-shred erasure
The three questions

Every audit of an autonomous system reduces to three questions. InvariantDB answers all three in one query surface.

Not a log line to grep, not a snapshot to rehydrate, not an event bus to replay. A belief is an addressable node with a claim, a confidence, and its evidence. Time is a query verb. Revisions are edges, not overwrites.

01
Knew?
Every belief is a queryable node with claim, confidence, and evidence pointers — not a log line.
02
When?
Two clocks, first-class. AT VALID for the world; AT RECORDED for the engine's knowledge.
03
Why changed?
New evidence records a successor with a reason. Old and new coexist; the chain is walkable.
MCP quickstart

Point your agent at a graph. Speak Cypher.

Every graph exposes a JSON-RPC endpoint. Any Model Context Protocol client — Claude Desktop, an SDK, your own agent — can call it. The engine advertises fourteen tools on tools/list. The workhorse is cypher_query; every other tool is a shortcut around the equivalent CALL db.* procedure.

invariantdb / mcp.quickstart protocolVersion 2024-11-05
A · Graph-scoped endpoint
# One URL per graph. JSON-RPC 2.0 over HTTPS.
POST https://your-tenant.invariantdb.com/graphs/{name}/mcp
Authorization: Bearer $INVARIANTDB_TOKEN
Content-Type: application/json

# The transport announces itself as
# "invariantdb-mcp" on the initialize call.
B · Claude Desktop mcp.json
{
  "mcpServers": {
    "invariantdb": {
      "command": "npx",
      "args": ["invariantdb-mcp"],
      "env": {
        "INVARIANTDB_ENDPOINT":
          "https://your-tenant.invariantdb.com/graphs/agent/mcp",
        "INVARIANTDB_TOKEN": "..."
      }
    }
  }
}
Heads up. cypher_query rejects a top-level atTime argument on purpose. Time travel belongs inside the Cypher body — put AT VALID or AT RECORDED on the MATCH pattern.

The fourteen tools.

Every proc-wrapper tool dispatches to the equivalent CALL db.* form, so callers can drop to raw Cypher at any point without giving up the MCP contract.

cypher_queryRun any Cypher against the bound graph. Returns columns + rows.
search_fulltextBM25 search over a (label, property). Top-k hits with score.
search_vectorVector search over a (label, property). Top-k hits with score.
get_node_by_strFetch one node by its string id.
get_edge_by_strFetch one edge by its string id.
engine_infoMetadata for the bound graph: current version + auth summary.
record_episodeAppend one event to an agent's session (episodic memory).
replay_episodesReplay a session in time order — last N events.
belief_lineageWalk every version of a belief back through its evidence.
property_provenanceFull history + provenance for one node property.
derived_fromFollow derivation edges to trace a value to its sources.
acl_eventsReplay ACL audit events — who tried, what, when, denied?
subject_exportGDPR Art. 20 per-subject export — every node/edge/version.
destroy_subject_keyGDPR Art. 17 crypto-shred with a signed audit-chain receipt.

Record. Revise. Explain.

Belief revision in four Cypher lines. Yield columns match the runtime procedure catalog exactly — every snippet is copy-runnable against a fresh graph.

01 / RECORD

Form a belief.

The agent forms a claim; the engine stamps confidence and evidence pointers at record time and returns a belief id.

See the CALL →
02 / REVISE

Contradict without erasing.

Contradicting evidence arrives. The old belief is superseded, not overwritten. The successor gets its own id — the chain stays intact.

See the CALL →
03 / EXPLAIN

Answer the auditor.

Walk the lineage backward, filter by createdAt, and you have proof of what the agent could have known on any given day.

See the CALL →
invariantdb / belief-flow.cypher production
Step 1 — Record
CALL db.recordBelief(
  "belief-99",
  "customer:c-77 risk = LOW",
  0.82,
  ["episode-482", "episode-491"]
)
YIELD beliefId
RETURN beliefId;
Step 2 — Revise
CALL db.reviseBelief(
  "belief-99",
  "customer:c-77 risk = HIGH",
  0.91,
  "address-mismatch document arrived 2026-03-04"
)
YIELD oldBeliefId, newBeliefId, revisedAt
RETURN oldBeliefId, newBeliefId, revisedAt;
Step 3 — Lineage
CALL db.beliefLineage("belief-99", 3)
YIELD beliefId, claim, confidence,
      createdAt, supersededAt, depth, evidence
RETURN beliefId, claim, confidence, depth
ORDER BY depth DESC;
Step 4 — The auditor question
// What did the agent know about c-77 on March 5?
CALL db.beliefLineage("belief-99", 3)
YIELD beliefId, claim, createdAt
WHERE createdAt <= datetime("2026-03-05T00:00:00Z")
RETURN beliefId, claim, createdAt
ORDER BY createdAt DESC;
Receipts
belief-99 · LOW · 0.82r7a1…9cc2
recorded2026-02-28
revisionrev 1
evidenceep-482, ep-491
superseded2026-03-04
chain intact
belief-99 · HIGH · 0.91bd41…0f73
recorded2026-03-04
revisionrev 2
reasonaddress-mismatch doc
supersedesrev 1
both revisions remain provable

Two search modes. One graph.

Agents fetch context by keyword and by embedding — then follow edges from whatever they found. BM25 for lexical hits, vector search for semantic proximity, Cypher expansion for the neighbourhood around each hit.

Fulltext · BM25

Keyword recall, ranked.

Point gds.fulltextSearch at a (label, property) pair and a query string. Yield gives node id, score, the full node record, and the human-facing string id.

CALL gds.fulltextSearch("Note", "body", "address mismatch", 20)
YIELD nodeId, score, node, strId
RETURN strId, score, node.body
ORDER BY score DESC;
"Find every note where a bureau analyst flagged the address mismatch — then follow the edges to the beliefs it produced."
Vector · semantic

Semantic recall, ranked.

Pass the embedded query vector to gds.vectorSearch. Yield is intentionally narrow — just node id and score — so you can pipe straight into a MATCH to enrich or expand.

CALL gds.vectorSearch("Doc", "embedding", $queryVector, 10)
YIELD nodeId, score
MATCH (d:Doc) WHERE id(d) = nodeId
RETURN d.title, score ORDER BY score DESC;
"Retrieve semantically-similar documents, then walk one hop to the customers who authored them."
Episodic memory

Session-scoped replay.

Every agent has a session log. db.recordEpisode appends one event; db.replayEpisodes hands the last N back in time order — kind, timestamp, text, and any payload the agent attached.

CALL db.recordEpisode("session-1", "observation",
  "customer address does not match KYC document")
YIELD eventId, ts RETURN eventId, ts;

CALL db.replayEpisodes("session-1", 50)
YIELD eventId, kind, ts, text, payload
RETURN kind, ts, text ORDER BY ts;
"Replay the last N events in this agent session — inputs, tool calls, outputs — exactly as they happened."
Property provenance

Every value carries its receipts.

Every write is stamped with the actor, source, reason, request id, and confidence. Ask any property for its story — you get the full version history, provenance attached.

MATCH (c:Customer {strId: "c-77"})
CALL db.propertyProvenance(id(c), "risk")
YIELD value, validFrom, validTo, version,
      txnAt, actor, source, reason, requestId, confidence
RETURN version, value, actor, reason, txnAt ORDER BY version;
"Who wrote this value, when, from which source, and with what confidence — for every version, without a separate audit query."
Bitemporal recall

Two clocks. One MATCH clause.

Every fact carries two intervals. Attach a clock verb to the pattern and the whole query travels there — edges included, indexes included, deletes reversed if the delete came later.

Valid time · the world clock

When was the fact true out in reality? Reprice a portfolio at last quarter's prices. Reread a customer's permissions at consent grant.

AT VALID '2026-03-05T00:00:00Z'

Recorded time · the system clock

When did the engine learn the fact? Reconstruct what the agent could have known before a bug fix. Prove there was no future-info leakage into training.

AT RECORDED '2026-03-04T09:00:00Z'
invariantdb / auditor.cypher production
The auditor query
// What did the agent's memory look like at record-time
// March 4, as of what the world knew at valid-time March 5?
MATCH (c:Customer {strId: "c-77"})-[:HAS_BELIEF]->(b:Belief)
  AT VALID "2026-03-05T00:00:00Z"
  AT RECORDED "2026-03-04T09:00:00Z"
RETURN b.claim, b.confidence, b.createdAt;

// Every mutation in a bitemporal window —
// useful for driving downstream projections or
// verifying that an agent's writes stayed inside
// a policy budget.
CALL db.changes($fromNanos, $toNanos)
YIELD kind, op, entity_id, label, txn_at, applied_seq
RETURN kind, op, label, txn_at
ORDER BY applied_seq;
Receipt
c-77 · risk = LOWr7a1…9cc2
valid2026-03-05
recorded2026-03-04
revisionrev 1 · not yet superseded
evidence2 episodes
answer preserved exactly as the agent saw it
c-77 · risk = HIGHbd41…0f73
valid2026-03-05
recorded2026-06-01 (later)
revisionrev 2
reasonaddress-mismatch doc
today's answer, still provable

Erasure without corruption. Access with receipts.

GDPR Article 17 and Article 20 are query verbs, not tickets in a queue. Erase a subject in place and prove it happened; export everything a subject touched; verify the ACL audit chain hasn't been tampered with.

Art. 17 · erasure

Crypto-shred a subject.

The subject's encryption key is destroyed. Every ciphertext that mentioned them becomes unreadable in place. History structure survives.

CALL db.destroySubjectKey("customer:c-77")
YIELD subjectId, destroyedAtNanos
RETURN subjectId, destroyedAtNanos;
"Honour the erasure request without breaking every hash-chained audit record downstream of that customer."
Art. 17 · proof

Prove the erasure ran.

A signed receipt with anchor hashes that lets an auditor confirm the destroy happened — without ever seeing what was destroyed.

CALL db.proveErasure("customer:c-77")
YIELD receiptId, destroyedAt,
      anchorHistorySeq, anchorHistoryHash,
      ownChainHash, chainStatus
RETURN receiptId, chainStatus;
"Show the regulator a signed receipt, not the payload the regulator is not allowed to see."
Art. 20 · export

Per-subject data export.

Every node, edge, and version history the subject appears in — typed and shaped for direct download or handoff to the requester.

CALL db.subjectExport("customer:c-77")
YIELD type, id, kind, payload
RETURN type, id, kind, payload;
"Ship the requester the complete history — every fact, every revision, every derived value they touched."
Audit · chain

Verify the ACL log.

Tamper-evidence check on the ACL audit log. If any entry has been rewritten between event id A and event id B, the call flags it — and tells you where.

CALL db.verifyAclChain()
YIELD status, entries, brokenAtEventId, reason
RETURN status, entries, brokenAtEventId, reason;
"Has anyone tampered with the ACL history? If yes, at which event id — and what does the chain say the entry should be?"
Audit · access

Replay ACL events.

Who tried to read what, when, and whether the engine allowed it. Filter by principal, since-id, or limit.

CALL db.aclEvents(0, "agent-42", 100)
YIELD eventId, ts, principal, label,
      property, action, denied, reason
RETURN ts, principal, action, denied
ORDER BY eventId DESC;
"Show me every access agent-42 attempted last quarter — and every one the engine refused."
Derivation

Follow the evidence.

Walk a value backwards through the DERIVED_FROM edges. RAG citation chains, inference trees, document lineage — all in one traversal.

CALL db.derivedFrom("belief-99", 5)
YIELD strId, depth, kind
RETURN strId, depth, kind ORDER BY depth;
"Which citations, documents, and sub-inferences produced this final claim — five hops deep, in order?"
Machine-readable corpus

Two files for your crawler.

InvariantDB serves an llms.txt index and a full plain-text corpus. Both are stable, versioned, and safe to include in a training or retrieval pipeline — they contain only the capability-level narrative and public API surface. /llms.txt is the H1 + bulleted section index; /llms-full.txt is the concatenated corpus of every page linked from it. Both are declared in <link rel="alternate" type="text/plain"> so crawlers can discover them from any page on the site.

MCP-nativeFourteen tools on tools/list. protocolVersion 2024-11-05. JSON-RPC 2.0 over HTTPS.
Two clocksValid + recorded time as first-class MATCH-clause query verbs.
Belief revisionSuperseded, not overwritten. Lineage walkable, evidence attached.
Crypto-shredArt. 17 erasure with signed receipts. Art. 20 per-subject export.
Connect your agent

Give your AI a memory it can prove.

Free tier includes an MCP endpoint, a graph, and enough audit chain to run the demos on this page against your own data.