Skip to content

Enable OpenClaw Active Memory: Proactive Recall Guide

Ever feel like your AI’s memory is a bit too reactive? Usually, you have to prompt it to “remember this” or “search memory,” but by then, the natural flow of the conversation is already gone. Active memory fixes this by running a quick, blocking sub-agent before the main reply, giving the system a chance to pull relevant context exactly when it’s needed.

If you want to get Active Memory running with a safe, self-contained setup, you can just drop this configuration into your agent:

{
plugins: {
entries: {
"active-memory": {
enabled: true,
config: {
enabled: true,
agents: ["main"],
allowedChatTypes: ["direct"],
modelFallbackPolicy: "default-remote",
queryMode: "recent",
promptStyle: "balanced",
timeoutMs: 15000,
maxSummaryChars: 220,
persistTranscripts: false,
logging: true,
},
},
},
},
}

This setup enables the plugin for your main agent and limits it to direct-message sessions. It tries to use your current session model first but keeps a remote fallback ready just in case.

After you’ve updated the config, restart your gateway:

Terminal window
openclaw gateway

If you want to check what’s happening during a chat, use this command:

/verbose on

The most reliable way to set this up involves three steps: enable the plugin, point it at one conversational agent, and use logging while you’re fine-tuning things.

Start by adding this to your openclaw.json:

{
plugins: {
entries: {
"active-memory": {
enabled: true,
config: {
agents: ["main"],
allowedChatTypes: ["direct"],
modelFallbackPolicy: "default-remote",
queryMode: "recent",
promptStyle: "balanced",
timeoutMs: 15000,
maxSummaryChars: 220,
persistTranscripts: false,
logging: true,
},
},
},
},
}

Then, restart the gateway to apply the changes:

Terminal window
openclaw gateway

Here is a breakdown of what these settings do:

  • plugins.entries.active-memory.enabled: true switches the plugin on.
  • config.agents: ["main"] makes sure only the main agent uses active memory.
  • config.allowedChatTypes: ["direct"] limits it to direct-message style sessions.
  • If you leave config.model empty, it uses the model from your current session.
  • config.modelFallbackPolicy: "default-remote" ensures there is a backup model if needed.
  • config.promptStyle: "balanced" sets a general-purpose prompt style.
  • Active memory only triggers on eligible interactive chat sessions.

Active memory works by adding hidden system context for the model. You won’t see raw <active_memory_plugin>...</active_memory_plugin> tags in your client, as it keeps the technical markup out of the way.

You can pause or resume active memory for a specific chat session without touching your config files. Just use these commands:

/active-memory status
/active-memory off
/active-memory on

These commands only affect the current session. They won’t change your global enabled status or agent settings.

If you need to change the setting for every session and write it to your config, use the global flag:

/active-memory status --global
/active-memory off --global
/active-memory on --global

The global command updates plugins.entries.active-memory.config.enabled but keeps the plugin itself active so you can still use the commands later.

To see exactly what the memory system is thinking, turn on verbose mode:

/verbose on

When verbose is on, OpenClaw can show you:

  • A status line like Active Memory: ok 842ms recent 34 chars.
  • A debug summary such as Active Memory Debug: Lemon pepper wings with blue cheese..

These lines show you what’s being fed into the hidden context in a way that’s easy for you to read. Usually, the transcript from the memory sub-agent is deleted as soon as the run finishes.

Here is how a typical flow looks:

/verbose on
what wings should i order?

And this is the reply you should expect:

...normal assistant reply...
🧩 Active Memory: ok 842ms recent 34 chars
🔎 Active Memory Debug: Lemon pepper wings with blue cheese.

Active memory doesn’t just start on its own. You have to pass through two specific gates to get it working:

  1. Config opt-in You must enable the plugin and ensure the current agent id is listed in plugins.entries.active-memory.config.agents.
  2. Strict runtime eligibility Even with the right config, active memory only triggers for interactive persistent chat sessions that meet the criteria.

Here is the logic the system follows:

plugin enabled
+
agent id targeted
+
allowed chat type
+
eligible interactive persistent chat session
=
active memory runs

If you miss any of those requirements, active memory does not run.

You use config.allowedChatTypes to manage which kinds of conversations can use Active Memory.

The default setting is:

allowedChatTypes: ["direct"]

This means Active Memory runs in direct-message sessions. It won’t run in group or channel sessions unless you specifically add them to the list.

Check out these examples for your configuration:

allowedChatTypes: ["direct"]
allowedChatTypes: ["direct", "group"]
allowedChatTypes: ["direct", "group", "channel"]

Active memory is designed as a conversational enrichment feature. It is not a platform-wide inference tool.

SurfaceRuns active memory?
Control UI / web chat persistent sessionsYes, if the plugin is enabled and the agent is targeted
Other interactive channel sessions on the same persistent chat pathYes, if the plugin is enabled and the agent is targeted
Headless one-shot runsNo
Heartbeat/background runsNo
Generic internal agent-command pathsNo
Sub-agent/internal helper executionNo

You should use active memory when:

  • The session is persistent and user-facing.
  • The agent has meaningful long-term memory to search.
  • Continuity matters more than raw prompt determinism.
  • Personalization is a key requirement for the experience.

It works well for:

  • Stable preferences.
  • Recurring habits.
  • Long-term user context.
  • Context that should surface naturally.

It is a poor fit for:

  • Automation.
  • Internal workers.
  • One-shot API tasks.
  • Places where hidden personalization would be surprising.

When you send a message, the system doesn’t just jump to a reply. It runs a background process to see if there is anything relevant in your past interactions. Here is the runtime shape of that flow:

flowchart LR
U["User Message"] --> Q["Build Memory Query"]
Q --> R["Active Memory Blocking Memory Sub-Agent"]
R -->|NONE or empty| M["Main Reply"]
R -->|relevant summary| I["Append Hidden active_memory_plugin System Context"]
I --> M["Main Reply"]

This blocking memory sub-agent is focused. It only has access to two specific tools:

  • memory_search
  • memory_get

If your connection is weak, the system is designed to stay out of your way and will return NONE to keep things moving.

You can use config.queryMode to manage the “field of vision” for the blocking memory sub-agent. This setting determines how much of your current conversation history the sub-agent can see when it tries to figure out what to search for.

The config.promptStyle setting is your way of telling the sub-agent how to behave. You can make it very picky or very eager to find matches.

Here are the styles you can choose from:

  • balanced: This is the general-purpose default when you use recent mode.
  • strict: The most conservative option. Use this if you want to avoid context bleed.
  • contextual: This prioritizes continuity and works best when the conversation history is important.
  • recall-heavy: This makes the agent more likely to surface memories even if the match is a bit soft.
  • precision-heavy: This is the opposite; it prefers NONE unless the match is very clear.
  • preference-only: This is specifically tuned for your habits, routines, tastes, and recurring facts.

If you don’t set config.promptStyle, the system uses these default mappings:

message -> strict
recent -> balanced
full -> contextual

If you want to force a specific behavior, you can override it in your config like this:

promptStyle: "preference-only"

If you leave config.model empty, Active Memory follows a specific hierarchy to find a model to use:

explicit plugin model
-> current session model
-> agent primary model
-> optional built-in remote fallback

You can control that final step using config.modelFallbackPolicy. By default, it uses:

modelFallbackPolicy: "default-remote"

If you prefer the plugin to simply stop and skip the recall process instead of using the built-in remote default, you can switch to this option:

modelFallbackPolicy: "resolved-only"

This is useful if you want to ensure the plugin only runs when your specific preferred models are available.

Sometimes you need to go beyond the standard setup. These options are tucked away because they aren’t part of the recommended path, but they give you granular control when you need it.

You can use config.thinking to override how much the blocking memory sub-agent “thinks”:

thinking: "medium"

By default, it is set to:

thinking: "off"

You shouldn’t enable this by default. Since Active Memory runs right in the reply path, any extra thinking time adds latency that your users will notice.

If you need to add specific instructions, config.promptAppend puts your text after the default Active Memory prompt but before the conversation context:

promptAppend: "Prefer stable long-term preferences over one-off events."

If you want total control, config.promptOverride replaces the default prompt entirely. OpenClaw still attaches the conversation context at the end:

promptOverride: "You are a memory search agent. Return NONE or one compact user fact."

I wouldn’t recommend customizing the prompt unless you are testing a specific recall contract. The default is already tuned to give the main model exactly what it needs—either NONE or a compact user-fact context.

In this mode, only the latest user message gets sent to the agent.

Latest user message only

You should use this when you need the fastest possible response and want to prioritize stable preference recall. It is also the right choice if your follow-up turns don’t really need the previous conversational context.

Recommended timeout:

  • Start around 3000 to 5000 ms.

This sends the latest user message along with a short tail of the conversation.

Recent conversation tail:
user: ...
assistant: ...
user: ...
Latest user message:
...

This is a good choice when you want a balance between speed and conversational grounding, especially if follow-up questions often depend on the last few messages.

Recommended timeout:

  • Start around 15000 ms.

This sends the entire conversation to the blocking memory sub-agent.

Full conversation context:
user: ...
assistant: ...
user: ...
...

Use this when recall quality is more important to you than latency, or if the conversation has critical setup info buried deep in the thread.

Recommended timeout:

  • You’ll need to increase this significantly compared to message or recent.
  • Start at 15000 ms or higher, depending on how long your threads get.

As a general rule, your timeout should scale with the context size:

message < recent < full

When the Active Memory blocking memory sub-agent runs, it creates a session.jsonl transcript. Usually, this transcript is just a temporary file that lives in a temp directory and is only used for that specific run. It gets deleted the moment the run ends.

If you need to keep these transcripts for debugging or to see what’s happening under the hood, you can turn on persistence explicitly:

{
plugins: {
entries: {
"active-memory": {
enabled: true,
config: {
agents: ["main"],
persistTranscripts: true,
transcriptDir: "active-memory",
},
},
},
},
}

When you enable this, Active Memory saves transcripts in a separate folder within the target agent’s sessions directory. They won’t clutter your main user conversation transcripts.

The layout looks like this:

agents/<agent>/sessions/active-memory/<blocking-memory-sub-agent-session-id>.jsonl

You can use config.transcriptDir to change that subdirectory name.

Just be careful with this setting. Transcripts can pile up fast on busy sessions, especially since full query mode duplicates a lot of context. Also, remember that these files contain hidden prompt context and recalled memories.

You can find all your active memory settings under this specific path:

plugins.entries.active-memory

These are the primary fields you’ll be working with:

KeyTypeMeaning
enabledbooleanEnables the plugin itself
config.agentsstring[]Agent ids that may use active memory
config.modelstringOptional blocking memory sub-agent model ref; when unset, active memory uses the current session model
config.queryMode"message" | "recent" | "full"Controls how much conversation the blocking memory sub-agent sees
config.promptStyle"balanced" | "strict" | "contextual" | "recall-heavy" | "precision-heavy" | "preference-only"Controls how eager or strict the blocking memory sub-agent is when deciding whether to return memory
config.thinking"off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive"Advanced thinking override for the blocking memory sub-agent; default off for speed
config.promptOverridestringAdvanced full prompt replacement; not recommended for normal use
config.promptAppendstringAdvanced extra instructions appended to the default or overridden prompt
config.timeoutMsnumberHard timeout for the blocking memory sub-agent
config.maxSummaryCharsnumberMaximum total characters allowed in the active-memory summary
config.loggingbooleanEmits active memory logs while tuning
config.persistTranscriptsbooleanKeeps blocking memory sub-agent transcripts on disk instead of deleting temp files
config.transcriptDirstringRelative blocking memory sub-agent transcript directory under the agent sessions folder

If you need to fine-tune the performance, these fields are quite helpful:

KeyTypeMeaning
config.maxSummaryCharsnumberMaximum total characters allowed in the active-memory summary
config.recentUserTurnsnumberPrior user turns to include when queryMode is recent
config.recentAssistantTurnsnumberPrior assistant turns to include when queryMode is recent
config.recentUserCharsnumberMax chars per recent user turn
config.recentAssistantCharsnumberMax chars per recent assistant turn
config.cacheTtlMsnumberCache reuse for repeated identical queries

I recommend starting with the recent mode. It provides a solid balance for most tasks.

{
plugins: {
entries: {
"active-memory": {
enabled: true,
config: {
agents: ["main"],
queryMode: "recent",
promptStyle: "balanced",
timeoutMs: 15000,
maxSummaryChars: 220,
logging: true,
},
},
},
},
}

If you want to check how it’s behaving in real-time while you tune it, just use /verbose on in the session. You don’t need to look for a separate debug command.

Once you’re comfortable, you can adjust the mode based on your needs:

  • Switch to message if you want lower latency.
  • Switch to full if you decide the extra context is worth a slower blocking memory sub-agent.

If active memory isn’t showing up where you expect, you can try these steps to get things back on track:

  1. Confirm the plugin is enabled under plugins.entries.active-memory.enabled.
  2. Confirm the current agent id is listed in config.agents.
  3. Confirm you are testing through an interactive persistent chat session.
  4. Turn on config.logging: true and watch the gateway logs.
  5. Verify memory search itself works with openclaw memory status --deep.

If you find that memory hits are getting a bit noisy, you should tighten maxSummaryChars.

If active memory feels too slow, you have a few options to speed it up:

  • lower queryMode
  • lower timeoutMs
  • reduce recent turn counts
  • reduce per-turn char caps
OpenClaw

OpenClaw Expert

Still stuck?

If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.