11 KiB
summary, read_when, title
| summary | read_when | title | |||
|---|---|---|---|---|---|
| Context engine: pluggable context assembly, compaction, and subagent lifecycle |
|
Context engine |
A context engine controls how OpenClaw builds model context for each run: which messages to include, how to summarize older history, and how to manage context across subagent boundaries.
OpenClaw ships with a built-in legacy engine and uses it by default — most
users never need to change this. Install and select a plugin engine only when
you want different assembly, compaction, or cross-session recall behavior.
Quick start
Check which engine is active:
openclaw doctor
# or inspect config directly:
cat ~/.openclaw/openclaw.json | jq '.plugins.slots.contextEngine'
Installing a context engine plugin
Context engine plugins are installed like any other OpenClaw plugin. Install first, then select the engine in the slot:
# Install from npm
openclaw plugins install @martian-engineering/lossless-claw
# Or install from a local path (for development)
openclaw plugins install -l ./my-context-engine
Then enable the plugin and select it as the active engine in your config:
// openclaw.json
{
plugins: {
slots: {
contextEngine: "lossless-claw", // must match the plugin's registered engine id
},
entries: {
"lossless-claw": {
enabled: true,
// Plugin-specific config goes here (see the plugin's docs)
},
},
},
}
Restart the gateway after installing and configuring.
To switch back to the built-in engine, set contextEngine to "legacy" (or
remove the key entirely — "legacy" is the default).
How it works
Every time OpenClaw runs a model prompt, the context engine participates at four lifecycle points:
- Ingest — called when a new message is added to the session. The engine can store or index the message in its own data store.
- Assemble — called before each model run. The engine returns an ordered
set of messages (and an optional
systemPromptAddition) that fit within the token budget. - Compact — called when the context window is full, or when the user runs
/compact. The engine summarizes older history to free space. - After turn — called after a run completes. The engine can persist state, trigger background compaction, or update indexes.
Subagent lifecycle (optional)
OpenClaw calls two optional subagent lifecycle hooks:
- prepareSubagentSpawn — prepare shared context state before a child run
starts. The hook receives parent/child session keys,
contextMode(isolatedorfork), available transcript ids/files, and optional TTL. If it returns a rollback handle, OpenClaw calls it when spawn fails after preparation succeeds. - onSubagentEnded — clean up when a subagent session completes or is swept.
System prompt addition
The assemble method can return a systemPromptAddition string. OpenClaw
prepends this to the system prompt for the run. This lets engines inject
dynamic recall guidance, retrieval instructions, or context-aware hints
without requiring static workspace files.
The legacy engine
The built-in legacy engine preserves OpenClaw's original behavior:
- Ingest: no-op (the session manager handles message persistence directly).
- Assemble: pass-through (the existing sanitize → validate → limit pipeline in the runtime handles context assembly).
- Compact: delegates to the built-in summarization compaction, which creates a single summary of older messages and keeps recent messages intact.
- After turn: no-op.
The legacy engine does not register tools or provide a systemPromptAddition.
When no plugins.slots.contextEngine is set (or it's set to "legacy"), this
engine is used automatically.
Plugin engines
A plugin can register a context engine using the plugin API:
import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
export default function register(api) {
api.registerContextEngine("my-engine", () => ({
info: {
id: "my-engine",
name: "My Context Engine",
ownsCompaction: true,
},
async ingest({ sessionId, message, isHeartbeat }) {
// Store the message in your data store
return { ingested: true };
},
async assemble({ sessionId, messages, tokenBudget, availableTools, citationsMode }) {
// Return messages that fit the budget
return {
messages: buildContext(messages, tokenBudget),
estimatedTokens: countTokens(messages),
systemPromptAddition: buildMemorySystemPromptAddition({
availableTools: availableTools ?? new Set(),
citationsMode,
}),
};
},
async compact({ sessionId, force }) {
// Summarize older context
return { ok: true, compacted: true };
},
}));
}
Then enable it in config:
{
plugins: {
slots: {
contextEngine: "my-engine",
},
entries: {
"my-engine": {
enabled: true,
},
},
},
}
The ContextEngine interface
Required members:
| Member | Kind | Purpose |
|---|---|---|
info |
Property | Engine id, name, version, and whether it owns compaction |
ingest(params) |
Method | Store a single message |
assemble(params) |
Method | Build context for a model run (returns AssembleResult) |
compact(params) |
Method | Summarize/reduce context |
assemble returns an AssembleResult with:
messages— the ordered messages to send to the model.estimatedTokens(required,number) — the engine's estimate of total tokens in the assembled context. OpenClaw uses this for compaction threshold decisions and diagnostic reporting.systemPromptAddition(optional,string) — prepended to the system prompt.
Optional members:
| Member | Kind | Purpose |
|---|---|---|
bootstrap(params) |
Method | Initialize engine state for a session. Called once when the engine first sees a session (e.g., import history). |
ingestBatch(params) |
Method | Ingest a completed turn as a batch. Called after a run completes, with all messages from that turn at once. |
afterTurn(params) |
Method | Post-run lifecycle work (persist state, trigger background compaction). |
prepareSubagentSpawn(params) |
Method | Set up shared state for a child session before it starts. |
onSubagentEnded(params) |
Method | Clean up after a subagent ends. |
dispose() |
Method | Release resources. Called during gateway shutdown or plugin reload — not per-session. |
ownsCompaction
ownsCompaction controls whether Pi's built-in in-attempt auto-compaction stays
enabled for the run:
true— the engine owns compaction behavior. OpenClaw disables Pi's built-in auto-compaction for that run, and the engine'scompact()implementation is responsible for/compact, overflow recovery compaction, and any proactive compaction it wants to do inafterTurn().falseor unset — Pi's built-in auto-compaction may still run during prompt execution, but the active engine'scompact()method is still called for/compactand overflow recovery.
ownsCompaction: false does not mean OpenClaw automatically falls back to
the legacy engine's compaction path.
That means there are two valid plugin patterns:
- Owning mode — implement your own compaction algorithm and set
ownsCompaction: true. - Delegating mode — set
ownsCompaction: falseand havecompact()calldelegateCompactionToRuntime(...)fromopenclaw/plugin-sdk/coreto use OpenClaw's built-in compaction behavior.
A no-op compact() is unsafe for an active non-owning engine because it
disables the normal /compact and overflow-recovery compaction path for that
engine slot.
Configuration reference
{
plugins: {
slots: {
// Select the active context engine. Default: "legacy".
// Set to a plugin id to use a plugin engine.
contextEngine: "legacy",
},
},
}
The slot is exclusive at run time — only one registered context engine is
resolved for a given run or compaction operation. Other enabled
kind: "context-engine" plugins can still load and run their registration
code; plugins.slots.contextEngine only selects which registered engine id
OpenClaw resolves when it needs a context engine.
Relationship to compaction and memory
- Compaction is one responsibility of the context engine. The legacy engine delegates to OpenClaw's built-in summarization. Plugin engines can implement any compaction strategy (DAG summaries, vector retrieval, etc.).
- Memory plugins (
plugins.slots.memory) are separate from context engines. Memory plugins provide search/retrieval; context engines control what the model sees. They can work together — a context engine might use memory plugin data during assembly. Plugin engines that want the active memory prompt path should preferbuildMemorySystemPromptAddition(...)fromopenclaw/plugin-sdk/core, which converts the active memory prompt sections into a ready-to-prependsystemPromptAddition. If an engine needs lower-level control, it can still pull raw lines fromopenclaw/plugin-sdk/memory-host-coreviabuildActiveMemoryPromptSection(...). - Session pruning (trimming old tool results in-memory) still runs regardless of which context engine is active.
Tips
- Use
openclaw doctorto verify your engine is loading correctly. - If switching engines, existing sessions continue with their current history. The new engine takes over for future runs.
- Engine errors are logged and surfaced in diagnostics. If a plugin engine
fails to register or the selected engine id cannot be resolved, OpenClaw
does not fall back automatically; runs fail until you fix the plugin or
switch
plugins.slots.contextEngineback to"legacy". - For development, use
openclaw plugins install -l ./my-engineto link a local plugin directory without copying.
See also: Compaction, Context, Plugins, Plugin manifest.
Related
- Context — how context is built for agent turns
- Plugin Architecture — registering context engine plugins
- Compaction — summarizing long conversations