Skip to main content
Source: packages/oracle-runtime/src/plugins/memory/
AttributeValue
Visibilityalways
Stabilitystable
Categorymemory
Default stateAuto-detect (env: MEMORY_MCP_URL)
Depends on

Summary

Durable memory across conversations — who the user is, what you have made for them, and what worked. Surfaces the upstream Memory Engine MCP tools verbatim (memory-engine__search_memory_engine, memory-engine__add_memory, …). Tool list is resolved per-request because MCP headers depend on the in-flight user’s UCAN delegation.

Environment variables

VarRequiredDescription
MEMORY_MCP_URLyesMemory MCP HTTP(S) URL. Also triggers auto-detect.
MEMORY_ENGINE_URLyesMemory Engine HTTP(S) URL.

What it contributes

  • Tools (default selection):
    • memory-engine__search_memory_engine — recall stored facts.
    • memory-engine__add_memory — write a new memory.
    • memory-engine__delete_episode — delete a memory.
    • memory-engine__clear — clear (destructive; main-agent only).
  • Sub-agents: none.
  • Middleware: none directly contributed by the plugin (enrichment of state.userContext is handled upstream of the agent).
  • HTTP routes: none.
  • Shared state: userProfile — other plugins read it via rtCtx.shared.userProfile.
Tools available beyond the default selection (e.g. memory-engine__add_oracle_knowledge, memory-engine__delete_edge) can be enabled by passing selectedTools to new MemoryPlugin({ selectedTools: [...] }).

How memory reaches the prompt

Memory context does not arrive in the prompt because the agent calls a tool to fetch it. Instead, a UserContextFetcher runs before the main agent is compiled — eagerly loading all six context slots in a single pass, before any message is processed. What the fetcher loads: six slots, in this order:
  1. identity — who the user is (name, role, background)
  2. work — ongoing projects and responsibilities
  3. goals — stated objectives and priorities
  4. interests — topics and domains the user cares about
  5. relationships — people and organizations mentioned in past conversations
  6. recent — notable things from the last few sessions
When it runs: at agent-compile time, before turn 1. The fetcher runs once per session and caches the result for 5 minutes (keyed by sessionId). Subsequent turns within the same session reuse the cached context — the Memory Engine is not called again unless the cache expires. What appears in the prompt: if at least one slot is non-empty, the runtime inserts a ## What you know about the user block (section 6 of the 15-section prompt) containing all populated slots. If every slot is empty (no prior memory for this user), the block is omitted entirely. Implication for oracle authors: you do not need to instruct the agent to “look up the user’s context” or “recall memory before responding” in config.prompt.opening or anywhere else. The context is already in the system prompt when the agent sees the user’s first message. Adding such instructions is redundant and wastes tokens.
The 5-minute session cache means very-recent memory writes (e.g. the agent just called memory-engine__add_memory in the same session) may not appear in the fetched context until the next session or cache expiry. This is intentional — the fetcher is optimised for read latency, not write-through consistency.

Adding global oracle knowledge

Global knowledge is content the oracle should know on every turn, for every user — product docs, brand voice, FAQs, reference material. It’s stored on the Memory Engine and indexed under the oracle’s entity DID, not the user’s DID.
1

Confirm you are an owner or controller of the oracle entity

Only an account that is owner or controller on the oracle’s IXO entity (the entity created via qiforge-cli create-entity) can write global knowledge. The Memory Engine rejects writes from any other DID.Check with qiforge-cli update-entity or by inspecting the entity on chain. If you are not a controller, ask the entity owner to add your DID first.
2

Enable the add_oracle_knowledge tool on the memory plugin

The bundled memory plugin’s default tool selection does not include memory-engine__add_oracle_knowledge. Instantiate MemoryPlugin explicitly and extend the default selection:
// src/main.ts
import {
  createOracleApp,
  MemoryPlugin,
  DEFAULT_MEMORY_TOOLS,
  MEMORY_ADD_ORACLE_KNOWLEDGE_MCP_NAME,
} from '@ixo/oracle-runtime';

const app = await createOracleApp({
  config,
  plugins: [
    new MemoryPlugin({
      selectedTools: [
        ...DEFAULT_MEMORY_TOOLS,
        MEMORY_ADD_ORACLE_KNOWLEDGE_MCP_NAME,
      ],
    }),
  ],
});
The loader dedupes by name, so this explicit instance overrides the bundled default with the same name.
3

Boot the oracle

pnpm dev
The boot log should list memory as loaded. The agent now has memory-engine__add_oracle_knowledge available.
4

Open the Portal and connect to your oracle

Pick the environment matching the network your oracle is registered on:
NetworkPortal URL
devnethttps://dev.portal.qi.space
testnethttps://test.portal.qi.space
mainnethttps://portal.qi.space
Navigate directly to your oracle’s connect page (replace <ENTITY_DID> with the value of ORACLE_ENTITY_DID from your .env):
https://dev.portal.qi.space/domain/<ENTITY_DID>/connect
Sign in as the entity owner/controller. On the connect page, click the highlighted “Connect” action — the Portal then opens a chat session bound to the oracle.
5

Drop in content and ask the oracle to save it as global knowledge

In the chat, drag and drop files (PDFs, markdown, text), paste links, or paste raw text — anything you want the oracle to know going forward. Then tell the oracle in plain language:
Save this into the global oracle knowledge.
The agent calls memory-engine__add_oracle_knowledge with the dropped content. The Memory Engine accepts the write because your delegation chain proves you are owner/controller of the oracle entity.
6

Wait ~5 minutes for indexing

Newly written knowledge takes about five minutes to index before it appears in memory-engine__search_memory_engine results. After indexing, every user’s session will be able to recall it through the normal memory search path.
memory-engine__add_oracle_knowledge writes are scoped to the oracle entity, not to the calling user. Anything you add is visible to every user who talks to this oracle. Treat it like a public knowledge base.

Opt out / Opt in

const app = await createOracleApp({
  config,
  features: { memory: false },   // never load
  // features: { memory: true },  // force load (will fail env validation if vars missing)
  // features: { memory: 'auto' }, // run autoDetect (default)
});

When to use it

  • First contact (no prior context loaded): greet, ask the user’s name and what they need help with, save the answer.
  • You learn something durable about the user — name, role, ongoing project, a constraint, a relationship.
  • You produce an artifact (file, document, edit, generated content) — record what it is, what it is for, the structural choices.
  • The user expresses satisfaction or dissatisfaction with something you produced — capture what worked or did not.
  • The user references something they told you before, or something you made before.

When NOT to use it

  • Ephemeral conversation-only state — use the current message thread.
  • Behavioural preferences about how to respond — use user-preferences.
  • Public web facts not specific to this user — use firecrawl.
  • Anything the user asked you to forget or framed as temporary.

Shared state

How userProfile flows to other plugins.

Add a tool

Pattern for exposing upstream MCP tools.