@tablestore/openclaw-tablestore-memory
v0.2.0
Published
OpenClaw memory plugin backed by Alibaba Cloud TableStore memory APIs
Readme
tablestore-mem
tablestore-mem is an OpenClaw memory plugin backed by Alibaba Cloud TableStore memory APIs via the @tablestore/agent-storage SDK (AgentStorageClient). It supports both AccessKey (AK/SK) and API Key authentication.
It provides:
- Automatic retrieval before each turn through
before_prompt_buildwith hidden system-context injection - Automatic incremental writeback after each successful run through
agent_end(only the new turn, chunked to TableStore limits) - Automatic offline Dream memory consolidation (background + on-demand) to deduplicate, supersede, and clean up long-term memory
- Full access to the memory-service API surface: every one of the SDK's 22 memory methods is reachable through the CLI (see Full Memory API Reference)
- Slash commands:
/tablestore-mem-search/tablestore-mem-add/tablestore-mem-get/tablestore-mem-dream-status
- CLI commands:
openclaw tablestore-mem searchopenclaw tablestore-mem addopenclaw tablestore-mem doctoropenclaw tablestore-mem dreamopenclaw tablestore-mem call(generic passthrough to any memory API)openclaw tablestore-mem memory get|update|deleteopenclaw tablestore-mem stores list|deleteopenclaw tablestore-mem messages/requestsopenclaw tablestore-mem tasks list|getopenclaw tablestore-mem dream-tasks list|cancelopenclaw tablestore-mem dream-actions list|apply
Features
- Native OpenClaw memory slot plugin
- Minimal required configuration
- Automatic Beijing instance provisioning and reuse when instance config is omitted
- Shared
instance.jsonreuse across CLI and conversation hooks - Automatic memory store creation
- Hermes-style scope mapping adapted for OpenClaw
- Cross-agent and cross-run retrieval under the same tenant
- CLI for direct add/search verification
- CLI doctor command for diagnosing connection, memory store, and scoped memory listing
Requirements
- Node.js
>=20 - OpenClaw
>=2026.3.23 - Valid TableStore access key pair
Installation
Install from a local directory:
cd /root/openclaw/tablestore-mem
npm install
openclaw plugins install /root/openclaw/tablestore-mem
openclaw plugins enable tablestore-memFor OpenClaw 2026.4.26+, if you want automatic writeback through agent_end, you must explicitly trust this non-bundled plugin to read conversation content:
{
"plugins": {
"entries": {
"tablestore-mem": {
"hooks": {
"allowConversationAccess": true
}
}
}
}
}This is an OpenClaw security policy flag, not a TableStore plugin business setting.
After publish, install from npm:
npm install -g @tablestore/openclaw-tablestore-memoryOr use it as a package source for your OpenClaw plugin deployment workflow.
Authentication
The plugin accepts either authentication mode:
- AccessKey (AK/SK) — full functionality, including managed-instance auto-create when the endpoint/instance are omitted.
{ "accessKeyId": "<your-ak>", "accessKeySecret": "<your-sk>" } - API Key — set
apiKey; it is used instead of AK/SK. Because the API Key only reaches the memory service (not the control plane), managed-instance auto-create is unavailable, so an explicit httpsendpointandotsInstanceNameare required.{ "apiKey": "<your-api-key>", "endpoint": "https://<instance>.cn-beijing.ots.aliyuncs.com", "otsInstanceName": "<instance>" }
Resolution: if apiKey is set it takes precedence; otherwise accessKeyId + accessKeySecret are required.
Required Configuration
With AccessKey, only these two fields are required:
{
"accessKeyId": "<your-ak>",
"accessKeySecret": "<your-sk>"
}Example OpenClaw config:
{
"plugins": {
"slots": {
"memory": "tablestore-mem"
},
"entries": {
"tablestore-mem": {
"enabled": true,
"hooks": {
"allowConversationAccess": true
},
"config": {
"accessKeyId": "<your-ak>",
"accessKeySecret": "<your-sk>"
}
}
}
}
}Important:
accessKeyIdandaccessKeySecretare still the only required plugin business configuration values.plugins.entries.tablestore-mem.hooks.allowConversationAccess=trueis a separate OpenClaw trust flag required by OpenClaw2026.4.26+if you want the plugin'sagent_endwriteback hook to run.- If you omit that flag, CLI commands and automatic retrieval through
before_prompt_buildstill work, but automatic writeback after a conversation turn is blocked by OpenClaw.
Optional Configuration
These fields are optional:
otsInstanceName: optional instance name override; if unset, the plugin auto-creates one managed instance incn-beijingand reuses it laterendpoint: optional endpoint override; if unset, the plugin deriveshttps://<instance>.cn-beijing.ots.aliyuncs.comappId: optional override, defaults toopenclawtenantId: optional tenant override; if configured, it takes precedence over runtime session user identitymemoryStoreName: defaults toopenclaw_memmemoryStoreDescription: optional memory-store description applied atCreateMemoryStoretime; defaults toOpenClaw long-term memoryextractInstructions: optional memory-store-level custom extraction prompt (≤4096 chars) that guides which long-term memories are extracted; applied on store creation and reconciled onto an existing store viaUpdateMemoryStoreautoCreateMemoryStore: defaults totruewritebackEnabled: defaults totruewritebackCursorPersist: defaults totrue; persists the per-session writeback position to disk ($OPENCLAW_HOME/plugins/tablestore-mem/writeback-state.json) so a gateway restart does not re-ingest the in-progress session's history. Setfalsefor memory-only behaviorincludeScores: defaults totruesearchTopK: defaults to5minSimilarity: defaults to0(no filter);0..1— drops retrieved memories whose normalized cosine similarity is below the thresholdminQueryLength: defaults to6enableRerank: defaults totruedreamEnabled: defaults totruedreamIntervalHours: defaults to24dreamMinIntervalHours: defaults todreamIntervalHoursdreamApplyMode: defaults tosafe_auto(orproposal)dreamConfidenceThreshold: defaults to0.9— the single confidence (0..1)safe_autorequires to auto-applyadd/update/mergeactions when no per-action override is setdreamConfidenceThresholds: optional per-actionsafe_autothresholds, e.g.{"add":0.95,"update":0.85,"merge":0.8}; each is0..1, and any unset action falls back todreamConfidenceThreshold(DELETEis never auto-applied)dreamInstructions: optional custom consolidation instructions (≤4000 chars) passed to every Dream task (background,session_end, and CLI)dreamMaxScopesPerRun: defaults to20(max20)dreamOnSessionEnd: defaults totrue
If openclaw_mem does not exist, the plugin creates it automatically on first use.
If both otsInstanceName and endpoint are omitted, the plugin:
- creates a TableStore VCU instance in
cn-beijingon first use through the control-planeCreateVCUInstanceAPI - waits for the instance status to become ready
- updates the instance ACL through
UpdateInstanceto enable public data-plane access - waits for the data endpoint DNS to become resolvable before first data-plane use
- persists the created
instanceNameand derived endpoint under the local OpenClaw home - reuses that same instance on later runs
Connection resolution priority:
- If
otsInstanceNameis configured, use it. - If
endpointis also configured, use that endpoint. - If
otsInstanceNameis configured butendpointis omitted, derivehttps://<otsInstanceName>.cn-beijing.ots.aliyuncs.com. - If only
endpointis configured and it matcheshttps://<instance>.cn-beijing.ots.aliyuncs.com, parse the instance name from the endpoint and use it. - If
otsInstanceNameis omitted and no usable configured endpoint is available, read the persisted auto-created instance from$OPENCLAW_HOME/plugins/tablestore-mem/instance.jsonand wait for its endpoint to become usable. - If no persisted instance exists, create one in
cn-beijing, persist it, wait for readiness, and use it.
When OPENCLAW_HOME is not set, OpenClaw home defaults to ~/.openclaw, so the auto-created instance state is stored at:
~/.openclaw/plugins/tablestore-mem/instance.jsonEnvironment variable overrides:
TABLESTORE_MEMORY_APP_IDTABLESTORE_MEMORY_TENANT_IDTABLESTORE_MEMORY_API_KEY
Scope Design
The plugin follows the Hermes-style scope design, adapted for OpenClaw.
appId
- Source priority:
- plugin config
appIdorapp_id TABLESTORE_MEMORY_APP_ID
- plugin config
- Default:
openclaw
tenantId
- Source priority:
- plugin config
tenantIdortenant_id TABLESTORE_MEMORY_TENANT_ID- current OpenClaw session
user_id,userId, or OpenAI-compatibleuser
- plugin config
- Default:
__default__
agentId
- Source: OpenClaw runtime context
agent_identityagentIdentityagentId- derived from
sessionKeyif needed
- Default:
openclaw
runId
- Source priority:
gateway_session_keyorgatewaySessionKeysession_titleorsessionTitle- current
sessionId
- Default:
__default__
Read vs Write Scope
Writes preserve runtime agent/run identity. tenantId uses the configured tenant when set; otherwise it falls back to the current session user identity:
{
"appId": "<configured-app-or-openclaw>",
"tenantId": "<configured-tenant-or-current-user>",
"agentId": "<runtime-agent>",
"runId": "<runtime-session-identity>"
}Reads intentionally search across all agents and runs under the same effective tenant:
{
"appId": "<configured-app-or-openclaw>",
"tenantId": "<configured-tenant-or-current-user>",
"agentId": "*",
"runId": "*"
}This allows a memory written by one OpenClaw agent to be recalled by another agent under the same user scope.
Memory Consolidation (Dream)
Over time the long-term store accumulates duplicate, evolving, and stale memories. The plugin uses the TableStore Dream task to consolidate them (rewrite/merge/supersede/drop), keeping the store precise.
How it works:
- Each successful writeback queues its concrete scope (
appId/tenantId/agentId/runId) for consolidation. - A background scheduler runs every
dreamIntervalHours(default 24h), draining up todreamMaxScopesPerRunqueued scopes per cycle and consolidating each withapplyMode=safe_auto,incremental=true. - When
dreamOnSessionEndis enabled (default), a session's scope is also consolidated as soon as it ends (rotation/reset/idle/compaction) via thesession_endhook — the same scope the turn was written to.session_endis not a conversation hook, so it works withoutallowConversationAccess. It shares the per-scope watermark anddreamMinIntervalHours, so it never double-consolidates a scope the background cycle just handled. safe_autoauto-appliesadd/update/mergeactions whose confidence reaches the configured threshold;DELETEis never auto-applied. Thresholds resolve per action as CLI--threshold(all actions) > per-actiondreamConfidenceThresholds> singledreamConfidenceThreshold(default 0.9). A per-scope watermark indream-state.jsonplusdreamMinIntervalHoursprevents re-consolidating a scope too often.- Every Dream task (background,
session_end, and CLI) carries the configureddreamInstructionswhen set, letting you steer how memories are merged/rewritten. - Consolidation always targets concrete scopes (not wildcards) and keeps results in place (
preserve_scope) — this is the configuration the service auto-applies. It runs entirely off the hot path; failures are logged and never affect retrieval or writeback. - The background scheduler only runs while the OpenClaw process is alive. For environments that are not long-running, drive consolidation with cron via the CLI below.
On-demand consolidation:
# Consolidate one user's memories now and wait for the result
openclaw tablestore-mem dream --uid alice --wait
# Generate proposals only (no auto-apply)
openclaw tablestore-mem dream --uid alice --apply-mode proposal --wait
# Override the safe_auto confidence threshold for all actions (0..1)
openclaw tablestore-mem dream --uid alice --threshold 0.8 --wait
# Steer this run with custom consolidation instructions
openclaw tablestore-mem dream --uid alice --instructions "Prefer merging duplicate preferences" --waitThe CLI enumerates the tenant's concrete scopes via ListMemoryStoreScopes and consolidates up to dreamMaxScopesPerRun of them. --wait prints the dreamId, final status, and action counts. --threshold <0..1> overrides the auto-apply confidence for all actions this run; --instructions <text> overrides dreamInstructions for this run; --task-type <memory|skill|profile> and --no-incremental are also available.
To disable automatic consolidation, set dreamEnabled=false (the dream CLI still works on demand).
CLI Usage
Add one memory:
openclaw tablestore-mem add "Alice likes jasmine tea" --uid aliceSearch memory:
openclaw tablestore-mem search "what does Alice like" --uid alice
# optional similarity-threshold filter (0..1)
openclaw tablestore-mem search "what does Alice like" --uid alice --min-similarity 0.3Show help:
openclaw tablestore-mem --help
openclaw tablestore-mem add --help
openclaw tablestore-mem doctor --help
openclaw tablestore-mem search --helpWithout --uid, the CLI uses the default/global tenant scope and is mainly useful for maintenance or debugging.
The CLI uses the same connection resolution and instance.json reuse flow as the automatic OpenClaw hooks.
Doctor:
openclaw tablestore-mem doctor --uid aliceDoctor checks:
- resolved endpoint and
otsInstanceName - memory store existence and metadata through
GetMemoryStore - scoped memory listing through
ListMemories - a small sample of returned memories for quick inspection
On the first AK/SK-only run, doctor may take longer because it can create a new instance and wait for the endpoint DNS to become ready.
Doctor returns structured JSON so users can share the output for troubleshooting.
Slash Commands
Inside an OpenClaw session:
/tablestore-mem-add Alice likes jasmine tea
/tablestore-mem-search jasmine tea/tablestore-mem-get <memoryId> fetches a single memory in the current scope,
and /tablestore-mem-dream-status lists the recent Dream consolidation tasks for
the current scope. Only read-only, low-risk operations are exposed as slash
commands; destructive operations (delete/cancel) are CLI-only.
Slash command search intentionally returns visible text because it is an explicit user command. Automatic retrieval uses hidden system context and is not printed into the visible session transcript.
Full Memory API Reference
Every memory-service method of the @tablestore/agent-storage SDK is reachable
through the CLI. High-value methods have first-class subcommands; the rest are
reachable through the generic call passthrough.
Generic passthrough
# Call any memory method by name (camelCase) or /PascalCase path.
openclaw tablestore-mem call listMemoryStores --json '{}'
openclaw tablestore-mem call getMemory --uid alice --json '{"memoryId":"mem-1"}'
openclaw tablestore-mem call listMemoryTasks --uid alice --file ./body.json- Body source precedence:
--json>--file> (falls back to{}). memoryStoreNameis injected from config when the body omits it.--uidinjects the read scope only when the body has noscope.- The method must be one of the 22 allowed memory methods, otherwise the call is rejected with the supported list.
First-class commands
# Memory items
openclaw tablestore-mem memory get --id mem-1 --uid alice
openclaw tablestore-mem memory update --id mem-1 --uid alice --text "new text" --metadata '{"topic":"tea"}'
openclaw tablestore-mem memory delete --id mem-1 --uid alice --yes # destructive
# Stores
openclaw tablestore-mem stores list
openclaw tablestore-mem stores delete --name openclaw_mem --yes # destructive
# Audit / observability
openclaw tablestore-mem messages --uid alice --limit 20
openclaw tablestore-mem requests --uid alice --operation AddMemories
openclaw tablestore-mem tasks list --uid alice --status running
openclaw tablestore-mem tasks get --request-id req-1 --uid alice
# Dream tasks and actions
openclaw tablestore-mem dream-tasks list --uid alice --status completed
openclaw tablestore-mem dream-tasks cancel --dream-id d-1 --yes # destructive
openclaw tablestore-mem dream-actions list --dream-id d-1 --status proposed
openclaw tablestore-mem dream-actions apply --dream-id d-1 --action-ids a1,a2,a3Destructive commands (memory delete, stores delete, dream-tasks cancel)
require --yes; without it they abort and make no API call. All list commands
accept --limit / --next-token and echo back nextToken for pagination.
Unlike search/add/doctor, these commands are faithful API wrappers and do
not auto-create the memory store; a call against a missing store returns the
service error rather than silently provisioning one.
OpenClaw Hook Trust
OpenClaw 2026.4.26+ treats some typed hooks as conversation-sensitive for non-bundled plugins.
For this plugin:
before_prompt_builddoes not requireallowConversationAccessagent_enddoes requireallowConversationAccess
That means:
- retrieval can still work without the flag
- writeback will be blocked without the flag
Recommended config:
{
"plugins": {
"entries": {
"tablestore-mem": {
"enabled": true,
"hooks": {
"allowConversationAccess": true
},
"config": {
"accessKeyId": "<your-ak>",
"accessKeySecret": "<your-sk>"
}
}
}
}
}How to verify:
openclaw plugins inspect tablestore-mem --jsonExpected result when writeback is enabled:
typedHookscontains bothbefore_prompt_buildandagent_endpolicy.allowConversationAccessistruediagnosticsdoes not contain a warning aboutagent_endbeing blocked
Expected result when the trust flag is missing:
before_prompt_buildis still presentagent_endis missingdiagnosticscontains a warning like:typed hook "agent_end" blocked because non-bundled plugins must set plugins.entries.tablestore-mem.hooks.allowConversationAccess=true
Runtime Behavior
Before prompt build:
- extracts the latest user prompt
- ensures the TableStore instance is resolved or auto-created
- waits for a newly auto-created instance to become ready before the first data-plane call
- ensures the memory store exists, creating
openclaw_memby default when missing - searches TableStore memory using tenant-wide read scope
- calls
SearchMemorieswithenableRerank=trueby default - injects matched memories into hidden system context
- does not print retrieved memories into the visible session transcript
- logs retrieval count and scope at debug level
After agent end:
- ensures the TableStore instance is resolved or auto-created
- reuses the same persisted
instance.jsonstate as CLI and retrieval hooks - ensures the memory store exists, creating
openclaw_memby default when missing - collects user/assistant messages from the completed turn
- writes them into TableStore using runtime write scope
- calls
AddMemorieswithsync=falseby default
OpenClaw 2026.4.26+ note:
- this
agent_endpath only runs whenplugins.entries.tablestore-mem.hooks.allowConversationAccess=true - if that trust flag is missing, OpenClaw blocks
agent_endbefore the plugin can see conversation messages
The plugin does not call ListMemories as a fallback. Search results are exactly the results returned by SearchMemories; server-side scope filtering is trusted.
Verification
Plugin inspection:
openclaw plugins inspect tablestore-memExpected shape:
- Typed hooks:
before_prompt_build,agent_end - Commands:
tablestore-mem-search,tablestore-mem-add - CLI doctor:
tablestore-mem doctor - CLI commands:
tablestore-mem
Syntax check:
npm run checkPackage dry run:
npm run pack:checkPackaged-plugin cold-start smoke test:
npm run smoke:packThis check is the new release gate for “fresh install but unusable” failures. It:
- runs
npm pack - installs the packed tarball into a brand new OpenClaw profile
- verifies the plugin loads from the packed artifact
- writes the minimal AK/SK config directly into that fresh profile
- verifies hooks, slash commands, and
openclaw tablestore-memCLI registration - verifies
doctor,add, andsearchsubcommand help can start successfully
Optional live OpenClaw smoke test against a real TableStore environment:
TABLESTORE_MEM_LIVE_ACCESS_KEY_ID="<ak>" \
TABLESTORE_MEM_LIVE_ACCESS_KEY_SECRET="<sk>" \
npm run smoke:liveOptional live overrides:
TABLESTORE_MEM_LIVE_ENDPOINTTABLESTORE_MEM_LIVE_OTS_INSTANCE_NAMETABLESTORE_MEM_LIVE_TENANT_ID
When TABLESTORE_MEM_LIVE_ENDPOINT and TABLESTORE_MEM_LIVE_OTS_INSTANCE_NAME are both omitted, npm run smoke:live exercises the AK/SK-only managed-instance path and verifies that a newly created instance.json is persisted and reused on the second doctor run.
Publishing
Pre-publish checklist:
- Update
versioninpackage.json - Run
npm install - Run
npm run release:check - If you rely on the managed AK/SK-only path, run one live smoke:
TABLESTORE_MEM_LIVE_ACCESS_KEY_ID=... TABLESTORE_MEM_LIVE_ACCESS_KEY_SECRET=... npm run smoke:live - If you want additional business validation, verify one real
doctor, one realadd, one realsearch
npm run release:check runs:
npm run checknpm run testnpm run pack:checknpm run smoke:pack
This means npm publish now fails before publish if the packed tarball cannot be installed into a clean OpenClaw profile or if the plugin fails to register its hooks and CLI after minimal configuration.
Publish:
npm publishThe package is configured for public publish under:
@tablestore/openclaw-tablestore-memoryNote:
- npm package names cannot use
tablestore/openclaw-tablestore-memorydirectly - the valid npm scoped package name is
@tablestore/openclaw-tablestore-memory
Notes
- The plugin uses the
@tablestore/agent-storageSDK (AgentStorageClient) directly, with AccessKey or API Key auth. - It does not depend on
message:preprocessed. - It does not register model-callable memory tools.
- Retrieval uses
SearchMemoriesresults directly and does not performListMemoriesfallback. agent_endwriteback persists only the new turn increment per session and chunks to TableStore limits (<=20messages /<=32000chars per call).- When no tenant/user identity can be resolved and no
tenantIdis configured, the scope falls back to the shared__default__tenant. - Dream consolidation auto-applies only within concrete scopes; it runs off the hot path and never blocks retrieval or writeback.
