OpenClaw context-engine plugin for OpenViking remote memory, context database, RAG and semantic retrieval.
This page is for the OpenClaw plugin package:
@openclaw/openviking
Do NOT install the plugin with clawhub install openviking — that installs the openviking AgentSkill (under skills/openviking), which is a different thing.
For agent-assisted plugin setup, ask the agent to follow INSTALL-AGENT.md. The primary install path is still openclaw plugins install @openclaw/openviking.
Ask your agent:
Install the OpenClaw plugin @openclaw/openviking for OpenViking remote memory. My server is at
http://my-server:1933and my API key issk-xxx.
Or in Chinese:
帮我安装 OpenViking 远程记忆插件 @openclaw/openviking。我的服务器地址是
http://my-server:1933,API key 是sk-xxx。
The agent will automatically run install → setup → restart → verify. No manual steps needed.
openclaw plugins install @openclaw/openviking
openclaw openviking setup --base-url http://my-server:1933 --api-key sk-xxx --json
openclaw gateway restart
openclaw openviking status --jsonThe setup command automatically activates the context-engine slot and validates the server connection.
@openclaw/openviking, openclaw openviking plugin, openviking remote memory plugin, OpenViking Context Database plugin, install-openviking-memory.
- Install and upgrade: INSTALL.md
- Chinese design and install guide: INSTALL-ZH.md
- Agent-oriented operator guide: INSTALL-AGENT.md
Use OpenViking as the long-term memory backend for OpenClaw. In OpenClaw, this plugin is registered as the openviking context engine.
The remainder of this document is an implementation-focused design note for integrators and engineers.
- OpenClaw still owns the agent runtime, prompt orchestration, and tool execution.
- OpenViking owns long-term memory retrieval, session archiving, archive summaries, and memory extraction.
examples/openclaw-pluginis not a narrow "memory lookup" plugin. It is an integration layer that spans the OpenClaw lifecycle.
In the current implementation, the plugin plays four roles at once:
context-engine: implementsassemble,afterTurn, andcompact- hook layer: handles
session_start,session_end, andbefore_reset - tool provider: registers memory/archive tools plus OpenViking resource and skill import tools
- runtime manager: connects to and monitors a remote OpenViking service
The diagram above reflects the current implementation boundary:
- OpenClaw remains the primary runtime on the left. The plugin does not take over agent execution.
- The middle layer combines hooks, the context engine, tools, and runtime management in one plugin registration.
- All HTTP traffic goes through
OpenVikingClient, which centralizesX-OpenViking-*headers and routing logs. - The OpenViking service owns sessions, memories, archives, and Phase 2 extraction, with storage under
viking://user/*,viking://agent/*, andviking://session/*.
That split lets OpenClaw stay focused on reasoning and orchestration while OpenViking becomes the source of truth for long-lived context.
The plugin does not send one fixed agent ID to OpenViking. It tries to keep OpenClaw session identity and OpenViking routing aligned.
The main rules are:
- reuse
sessionIddirectly when it is already a UUID - prefer
sessionKeywhen deriving a stableovSessionId - normalize unsafe path characters, or fall back to a stable SHA-256 when needed
- resolve
X-OpenViking-Agentper session, not per process - when
plugins.entries.openviking.config.agent_prefixis non-empty, prefix the session agent as<agent_prefix>_<sessionAgent> - when OpenClaw does not provide a session agent, use its default agent
main - send
X-OpenViking-Agenton OpenViking requests, including startup health checks - only add
X-OpenViking-Account/X-OpenViking-UserwhenaccountId/userIdare explicitly configured
This matters because the plugin is built to support multi-agent and multi-session OpenClaw usage without mixing memories across sessions.
The recommended remote-mode configuration only needs:
baseUrlapiKeyagent_prefix
In this setup:
apiKeyshould usually be a user keyaccountId/userIdare advanced options only when the deployment needs explicit identity headers, such as root-key or trusted-server flowsisolateUserScopeByAgent/isolateAgentScopeByUsermust match the server-side account namespace policy when using the PR #1356 canonical namespace modelagentScopeModeis a deprecated compatibility alias for older hash-based routing and should only be used against older servers
For OpenViking servers that include PR #1356, the plugin no longer treats agent or user scope as a locally computed hash. Instead it expands shorthand aliases into canonical URIs using the configured namespace policy:
viking://user/memoriesviking://user/<user_id>/memorieswhenisolateUserScopeByAgent=falseviking://user/<user_id>/agent/<agent_id>/memorieswhenisolateUserScopeByAgent=true
viking://agent/memoriesviking://agent/<agent_id>/memorieswhenisolateAgentScopeByUser=falseviking://agent/<agent_id>/user/<user_id>/memorieswhenisolateAgentScopeByUser=true
The plugin cannot auto-discover this policy today because /api/v1/system/status does not expose it. Configure the two booleans explicitly so they stay aligned with the server-side account policy.
Auto-recall now runs through assemble(). OpenClaw calls the same context engine method in two shapes, and the plugin assigns different responsibilities to each shape:
- Preflight assemble: params include
prompt;messagesis still old history. The plugin reads archive/session context back from OpenViking and rebuilds history. - transformContext assemble: params do not include
prompt; the latestmessagesentry is already the current user turn. The plugin only runs long-term recall and prepends the memory block to that user message content.
During recall, the plugin:
- Extracts query text from the latest user message.
- Resolves the agent routing for the current
sessionId/sessionKey. - Runs a quick availability precheck so model requests do not stall when OpenViking is unavailable.
- Queries both
viking://user/memoriesandviking://agent/memoriesin parallel. - Deduplicates, threshold-filters, reranks, and trims the results under a token budget.
- Prepends the selected memories as a
<relevant-memories>block to the current user message; it does not append a standalone synthetic user message.
The reranking logic is not pure vector-score sorting. The current implementation also considers:
- whether a result is a leaf memory with
level == 2 - whether it looks like a preference memory
- whether it looks like an event memory
- lexical overlap with the current query
Session handling is the main axis of this design. In the current implementation it covers history assembly, incremental append, asynchronous commit, and blocking compaction readback.
During preflight, assemble() is not just replaying old chat history. It reads session context back from OpenViking under a token budget, then rebuilds OpenClaw-facing messages:
latest_archive_overviewbecomes[Session History Summary]pre_archive_abstractsbecomes[Archive Index]- active session messages stay in message-block form
- assistant tool parts become
toolCall(input compatible:toolUse/inputis normalized totoolCall/arguments) - tool output becomes separate
toolResult - the final message list goes through a tool-use/result pairing repair pass
That means OpenClaw sees "compressed history summary + archive index + active messages", not an ever-growing raw transcript.
afterTurn() has a narrower job: append only the new turn into the OpenViking session.
- it slices only the newly added messages
- it keeps only
user/assistantcapture text - it preserves
toolCall/toolResultcontent in the serialized turn text - it strips injected
<relevant-memories>blocks and metadata noise before capture - it appends the sanitized turn text into the OpenViking session
After that, the plugin checks pending_tokens. Once the session crosses commitTokenThreshold, it triggers commit(wait=false):
- archive generation and Phase 2 memory extraction continue asynchronously on the server
- the current turn is not blocked waiting for extraction
- if
logFindRequestsis enabled, the logs include the task id and follow-up extraction detail
compact() is the stricter synchronous boundary:
- it calls
commit(wait=true)and blocks for completion - when an archive exists, it re-reads
latest_archive_overview - it returns updated token estimates, the latest archive id, and summary content
- if the summary is too coarse, the model can call
ov_archive_expandto reopen a specific archive
So afterTurn() is closer to "incremental append plus threshold-triggered async commit", while compact() is the explicit "wait for archive and compaction to finish" boundary.
Beyond automatic behavior, the plugin exposes seven tools directly:
memory_recall: explicit long-term memory searchmemory_store: write text into an OpenViking session and trigger commitmemory_forget: delete by URI, or search first and remove a single strong matchov_archive_expand: expand a concrete archive back into raw messagesadd_resource: import a document, directory, URL, or Git repository as an OpenViking resourceadd_skill: import or register an OpenViking agent skillmemory_search: search OpenViking resources and skills, especially after importing them
They serve different roles:
- automatic recall covers the default case where the model does not know what to search yet
memory_recallgives the model an explicit follow-up search pathmemory_storeis for immediately persisting clearly important informationov_archive_expandis the "go back to archive detail" escape hatch when summaries are not enoughadd_resourcelets the agent save explicit document or repository import requests without asking the user to remember slash commandsadd_skillimports skills into OpenViking, whileadd_resourceimports resourcesmemory_searchcloses the loop after import by letting the user or agent confirm and consume resources and skills
ov_archive_expand is especially important because assemble() normally returns archive summaries and indexes, not the full raw transcript.
Resource and skill imports are intentionally separate because they land in different OpenViking namespaces and use different server APIs:
- resources go through
/api/v1/resourcesand land underviking://resources/... - skills go through
/api/v1/skillsand land underviking://agent/skills/...
The plugin also registers explicit slash commands for manual imports:
/add-resource ./README.md --to viking://resources/openviking-readme --wait
/add-skill ./skills/install-openviking-memory --wait
/memory-search "OpenViking install" --uri viking://resources/openviking-readme
/memory-search "memory install skill" --uri viking://agent/skills
Resource import supports remote URLs, Git URLs, local files, local directories, and uploaded zip files. OpenViking's built-in parsers cover common documents and media such as Markdown, text, PDF, HTML, Word, PowerPoint, Excel, EPUB, images, audio, and video. Directory imports also accept common code, documentation, and config file extensions such as .py, .js, .ts, .go, .rs, .java, .cpp, .json, .yaml, .toml, .csv, .rst, .proto, .tf, and .vue.
For HTTP safety, the plugin never sends a direct local filesystem path to the OpenViking server. Local files and directories are first uploaded through /api/v1/resources/temp_upload; directories are zipped locally with a pure JavaScript zip implementation before upload.
The plugin operates exclusively in remote mode as a pure HTTP client:
baseUrland optionalapiKeycome from plugin config- no local subprocess is started or managed
- session context, memory search/read, commit, and archive expansion behavior stays the same
The OpenViking service must be deployed and running independently before the plugin can connect to it.
The repo also contains a more future-looking design draft at docs/design/openclaw-context-engine-refactor.md. It is important not to conflate the two:
- this README describes current implemented behavior
- the older draft discusses a stronger future move into context-engine-owned lifecycle control
- in the current version, the main automatic recall path lives in
assemble(): preflight rebuilds history, transformContext injects long-term memories - in the current version,
afterTurn()already appends to the OpenViking session, but commit remains threshold-triggered and asynchronous on that path - in the current version,
compact()already usescommit(wait=true), but it is still focused on synchronous commit plus readback rather than owning every orchestration concern
That distinction matters, otherwise the future design draft is easy to misread as already shipped behavior.
If you need to debug this plugin, start with these entry points.
openclaw openviking status --json
openclaw plugins list
openclaw config get plugins.entries.openviking.config
openclaw config get plugins.slots.contextEngineOpenClaw plugin logs:
openclaw logs --followOpenViking service logs:
cat ~/.openviking/data/log/openviking.logpython -m openviking.console.bootstrap --host 0.0.0.0 --port 8020 --openviking-url http://127.0.0.1:1933ov tui| Symptom | More likely cause | First check |
|---|---|---|
plugins.slots.contextEngine is not openviking |
The plugin slot was never set, or another plugin replaced it | openclaw config get plugins.slots.contextEngine |
| Cannot connect to OpenViking service | baseUrl is wrong or the service is down |
Check baseUrl in config and test connectivity manually |
| recall behaves inconsistently across sessions | Routing identity is not what you expected | Enable logFindRequests, then inspect openclaw logs --follow |
| long chats stop extracting memory | pending_tokens never crosses the threshold, or Phase 2 fails server-side |
Check plugin config and ~/.openviking/data/log/openviking.log |
| summaries are too coarse for detailed questions | You need archive-level detail, not just summary | Use an ID from [Archive Index] with ov_archive_expand |
For installation, upgrade, and uninstall operations, use INSTALL.md.



