Best Practices

Enagram's memory pipeline is designed to build a persistent, evolving model of an agent's interactions over time. Getting the most from it requires being deliberate about what you send, when you send it, and what you rely on it for.


What memory is for

Enagram is designed to answer one question: what does this agent know about this user, and how should that shape its behaviour going forward?

Good uses of memory:

  • User preferences and communication style — tone, verbosity, language, format preferences revealed through conversation.
  • Stated facts about the user — their role, domain, goals, constraints, recurring topics of interest.
  • Behavioural patterns — things that consistently lead to positive outcomes, corrections the user repeatedly makes, procedures the agent has learned work well.
  • Identity signals — durable characteristics that should influence every interaction, such as expertise level, values, or long-term objectives.
  • Outcomes and corrections — explicit feedback that teaches the pipeline what works and what doesn't.

What memory is not for

Enagram is a cognitive layer, not a data store. It is not a replacement for:

  • Document or knowledge base storage — if your agent needs to retrieve files, PDFs, or large structured documents, use a dedicated vector store or document retrieval system. Enagram is not designed for chunk-level retrieval of static content.
  • Session state — short-term conversational context (the last few turns) belongs in your prompt, not in memory. Enagram operates on patterns across sessions, not within a single turn.
  • Audit logs or compliance records — memory is a probabilistic, salience-weighted system. Items below the commit threshold are discarded, and memories decay over time. Do not rely on it for complete or authoritative records.
  • Structured application data — user account data, preferences stored in a database, permissions, and settings should live in your own data layer. Memory is for learned behavioural context, not authoritative state.

Do not send tool calls to memory

Tool calls — function invocations, API calls, database queries made by your agent — should generally not be sent to Enagram unless you specifically want the agent to learn that it used a tool, and under what circumstances.

The memory pipeline extracts meaning from natural language events. A raw tool call payload ({ "function": "search_docs", "args": { "query": "..." } }) carries little semantic signal and will either be discarded (low salience) or pollute the memory with meaningless procedural noise.

Instead:

  • Send the outcome of a tool call as a natural language event if it is semantically meaningful. For example, if a search returned a result the user found useful, send an outcome: positive event describing what worked.
  • If you want the agent to learn when to use a tool, frame it as a procedure: send a correction or outcome event that describes the context and result in natural language.

Separate memory from document retrieval

A common pattern is to combine Enagram with a vector store (Pinecone, Weaviate, pgvector, etc.). These serve distinct purposes and should not be conflated:

EnagramVector store
PurposeBehavioural memory about a userRetrieval of static content
InputInteraction eventsDocument chunks
OutputWorking memory contextRelevant passages
DecayYes — memories fade over timeNo
LearnsYes — reinforced by outcomesNo

A well-architected agent uses both: retrieve relevant documents from your vector store, retrieve behavioural context from Enagram, and combine both into the system prompt.


Be consistent with session IDs

The session_id field groups events into a session. Enagram uses session boundaries to understand episode structure — events within a session form a coherent episode that gets compiled into memory together.

  • Use a stable, unique identifier per conversation — a UUID generated at the start of each session works well.
  • Do not reuse session IDs across unrelated conversations.
  • Do not use a single global session ID for all interactions — this collapses all events into one episode and degrades memory quality significantly.

Send assistant messages, not just user messages

The pipeline extracts more signal when it can see both sides of the conversation. Sending only user messages means the agent cannot learn from its own responses — it cannot identify what it said that led to a positive outcome, or detect patterns in how it communicates.

Send assistant_message events alongside user_message events for every turn.


Use outcomes when you have a real signal

The memory pipeline compiles automatically after every model_response event — you do not need to send an explicit outcome for memory to work. Outcomes are an optional quality signal, not a requirement.

Send an outcome when you genuinely know the result:

  • A user clicks thumbs up or thumbs down.
  • A task completes successfully or fails (e.g. a booking confirmed, a test suite passed).
  • A user makes a correction — send a correction event type to flag that the prior response was wrong.
  • A support ticket is closed as resolved or unresolved.

Do not manufacture outcomes by having the LLM rate its own response — models are systematically overconfident and success from the model itself carries no useful signal. If you have no external quality signal, omit the outcome entirely and let the pipeline default to neutral weighting.


Respect the salience threshold

The commit_threshold configuration controls how selective the pipeline is. Raising it means only high-signal events are stored; lowering it stores more but with more noise.

Avoid the temptation to lower the threshold to "store everything" — a noisy memory degrades working memory quality. The default threshold is calibrated for general conversational agents. Adjust it only if you have a clear reason based on observed memory quality.