Complete the Basic Memory integration with OpenClaw's native memory lifecycle so BM works as a decorator around the default OpenClaw flow instead of relying on agent_start / agent_end shims.
The target model is:
- OpenClaw owns session state, context assembly pipeline, and compaction.
- Basic Memory owns durable knowledge, cross-session recall, and long-term capture.
- This plugin enriches the default flow without replacing it.
This plan is for issue #34, updated to match the "complement, don't replace" direction discussed there.
We will use the new OpenClaw ContextEngine lifecycle introduced in OpenClaw 2026.3.7 on March 6, 2026, but we will not implement a custom compaction strategy.
- Do not replace or override OpenClaw compaction behavior.
- Do not compete with lossless-claw or other alternate context engines.
- Do not turn BM into the canonical source of current-session state.
- Do not remove existing BM tools such as
memory_search,memory_get,search_notes,read_note, and note CRUD tools. - Do not add aggressive semantic retrieval on every turn.
The plugin should behave like a wrapper around the default OpenClaw memory model:
- OpenClaw tracks the live conversation.
- BM stores durable notes, tasks, decisions, and cross-session context.
- The plugin bridges the two systems at official lifecycle boundaries.
Where the ContextEngine API requires behavior that OpenClaw already provides well, we should pass through to the default behavior instead of re-implementing it.
BM should improve:
- session bootstrap recall
- durable post-turn capture
- subagent memory inheritance
- cross-session continuity through notes and graph search
BM should not try to improve:
- session-local compaction
- low-level pruning logic
- runtime token budgeting heuristics
Today the plugin uses:
api.on("agent_start", ...)for recallapi.on("agent_end", ...)for capture- composited
memory_search/memory_gettools for explicit retrieval
This works, but it lives beside OpenClaw's memory lifecycle instead of inside it.
Relevant current files:
index.tshooks/recall.tshooks/capture.tstools/memory-provider.tstypes/openclaw.d.ts
Current dependency constraint:
package.jsoncurrently pinsopenclawpeer support to>=2026.1.29- the local installed dependency is
openclaw@2026.2.6 - ContextEngine work requires moving to the
2026.3.7+SDK surface
Add a BasicMemoryContextEngine that composes with the default OpenClaw flow.
Expected lifecycle usage:
bootstrap- initialize BM session-side recall state
- gather small, high-signal context such as active tasks and recent activity
assemble- pass through OpenClaw messages
- optionally add a compact BM recall block when useful
afterTurn- persist durable takeaways from the completed turn into BM
prepareSubagentSpawn- prepare a minimal BM handoff for a child session
onSubagentEnded- capture child results back into BM
compact- do not customize
- use legacy/default pass-through behavior only if the interface requires it
feat(context-engine): move recall and capture into native lifecycle
- bump OpenClaw compatibility to
2026.3.7+ - replace the local SDK shim with the real ContextEngine-capable SDK types where possible
- add a
BasicMemoryContextEngine - register the engine through
api.registerContextEngine(...) - migrate recall behavior from
agent_startintobootstrap - migrate capture behavior from
agent_endintoafterTurn - keep existing BM tools and service startup behavior intact
- keep compaction fully default
- session startup still recalls active tasks and recent activity
- turns still get captured into BM
- plugin behavior is functionally similar to today, but now uses official lifecycle hooks
- engine registration works
bootstrapreturns expected initialized state when recall finds databootstrapis a no-op when recall finds nothingafterTurncaptures only valid turn contentafterTurnhandles failures without breaking the run- existing service startup and BM client lifecycle tests still pass
feat(context-engine): add bounded assemble-time BM recall
- implement a minimal
assemblehook - preserve incoming OpenClaw messages in order
- add an optional BM recall block only when there is useful context
- bound the size of injected BM context so it stays cheap and predictable
- avoid per-turn graph-heavy retrieval unless explicitly configured later
- the model sees a small BM memory summary automatically when helpful
- explicit
memory_searchandmemory_getremain available for deeper retrieval - OpenClaw remains in charge of the actual context pipeline and compaction
assemblereturns original messages unchanged when no recall block existsassembleadds a BM block when recall content exists- injected content is size-bounded
- assembly remains stable across repeated turns when recall content is unchanged
feat(context-engine): add subagent memory handoff
- implement
prepareSubagentSpawn - implement
onSubagentEnded - create a small BM handoff model for parent to child context transfer
- capture child outputs or summaries back into the parent knowledge base
- keep subagent integration lightweight and failure-tolerant
- subagents start with relevant BM context instead of a cold memory start
- useful child outputs become durable BM knowledge after completion
- failures in handoff/capture do not break subagent execution
- child handoff is created for subagent sessions
- rollback path works if spawn fails after preparation
- child completion writes back expected BM artifacts
- delete/release/sweep paths are handled safely
Prefer a small, explicit implementation instead of pushing logic back into index.ts.
Likely new files:
context-engine/basic-memory-context-engine.tscontext-engine/basic-memory-context-engine.test.ts- optional small helper modules for recall/capture formatting
After Phase 1 lands, the old event-hook path in index.ts should be removed or disabled so we do not double-capture or double-recall.
The BM tool surface remains part of the product even after lifecycle integration:
- composited
memory_searchandmemory_get - graph CRUD tools
- schema tools
- slash commands and CLI commands
Lifecycle integration complements explicit retrieval; it does not replace it.
This work should be shipped as the canonical BM integration path for OpenClaw 2026.3.7+.
If we need a temporary compatibility story for older OpenClaw versions, keep it shallow and time-boxed. The long-term target should be one code path based on the native lifecycle.
OpenClaw currently resolves one contextEngine slot, not a middleware stack.
Implication:
- our engine must behave like "default behavior plus BM enrichment"
- we should not assume we can stack with other context engines automatically
If assemble injects too much, BM could bloat prompt cost and work against the default system.
Mitigation:
- keep Phase 2 narrow
- bound injected size
- prefer summaries over raw note dumps
If old hooks and new lifecycle paths run together, recall and capture may happen twice.
Mitigation:
- Phase 1 should explicitly remove or disable the legacy hook wiring
- add tests that assert only one capture path is active
This feature is complete when:
- recall and capture happen through ContextEngine lifecycle hooks, not event shims
- BM enriches default session context without taking over compaction
- subagents inherit and return useful durable memory
- explicit BM tools remain intact
- the architecture clearly reflects "BM decorates OpenClaw memory"
feat(context-engine): move recall and capture into native lifecyclefeat(context-engine): add bounded assemble-time BM recallfeat(context-engine): add subagent memory handoff
- custom
compactlogic - BM-driven token budgeting
- replacing post-compaction context reinjection
- new retrieval heuristics beyond a compact recall block
- multi-engine composition support inside OpenClaw core