Memory Skill
Persistent agent memory with UUID-based stores, grants, text search, and encryption.
Overview
The Memory Skill replaces the legacy KV Skill with a richer storage model. Every piece of data is attached to a store (any UUID -- an agent, chat, user, or any entity). Access is controlled by a cascading check (canAccessStore), and agents can share stores with each other via grants.
Key Features
- Store-based model: Data is keyed by
(store_id, owner_id, namespace, key)-- agents can have memory about anything with a UUID - Access grants: Share stores between agents at three levels:
search,read,readwrite - Full-text search:
tsvector-powered search across one store or all accessible stores - In-context vs not-in-context: Control whether the LLM can see an entry or only skills can
- Encryption support: Client-side encrypted entries are stored as opaque blobs and excluded from search
- TTL: Time-to-live for automatic expiry of entries and grants
Usage
Portal-backed
import { RobutlerMemorySkill } from 'webagents/skills/storage';
const skill = new RobutlerMemorySkill({
portalUrl: 'https://robutler.ai',
apiKey: process.env.PLATFORM_SERVICE_KEY,
agentId: 'my-agent-uuid',
});Local (SQLite-backed)
import { LocalMemorySkill } from 'webagents/skills/storage';
const skill = new LocalMemorySkill({
agentId: 'my-agent',
storagePath: './.webagents/memory.db',
});Tool Reference
The memory tool uses a file-system metaphor aligned with Anthropic's native memory_20250818. It exposes 9 commands. Paths are of the form /memories/<key> for the agent's own store, or /memories/shared/<store_id>/<key> for a granted store; a path ending in / refers to a directory listing.
view(path)
Read a single entry, or — when path ends in / — list the entries in that store. Requires read access. Only returns in_context=true entries when listing.
create(path, content)
Create or overwrite a memory entry at path with content (a string or JSON-serializable value). Requires readwrite access. Optional implicit TTL is configured per-skill (defaultTtl).
edit(path, old_str, new_str)
In-place str_replace on a stored value: GET the current value, replace the first occurrence of old_str with new_str, PUT the result. Requires readwrite access.
delete(path)
Remove an entry. Only the entry creator (owner_id) can delete it. Requires readwrite access.
rename(path, new_str)
Move an entry from path to new_str — implemented as view + create + delete. Requires readwrite access on both source and destination stores.
search(query)
Hybrid full-text + semantic search across all accessible stores. Results include key, value, and storeId. Portal: PostgreSQL tsvector + Milvus E5 vectors merged via Reciprocal Rank Fusion. Local: FTS5 only.
share(path?, agent, level?)
Grant another agent access to a store. level is one of search (search-only — values returned, but list/view blocked, ideal for paid lookup), read (view + search), or readwrite (full). Defaults to read. If path is omitted, shares the agent's own store; otherwise the store id is extracted from /memories/shared/<store_id>/.... Requires readwrite access to the store being shared.
unshare(path?, agent)
Revoke a previously granted access. Mirrors share for store resolution. Requires readwrite access.
stores()
List all stores the agent can access: self store, granted stores, and contextual stores (chat, user).
Authentication
The skill always authenticates as the owner agent — the JWT supplied via apiKey in the constructor — regardless of which user or chat triggered the call. Referring identities (chat id, user id, optional referring agent id) are forwarded only as scope query/body parameters and never as authentication credentials.
Store Concept
A store is identified by a UUID. Common patterns:
| Store | UUID Source | Description |
|---|---|---|
| Self | Agent's own UUID | Persistent memory across all conversations |
| Chat | Chat UUID | Conversation-scoped, shared with participants |
| User | User UUID | Per-user personalization |
| Shared | Any UUID | Granted via share action |
Access Control
Every store access runs through canAccessStore():
- Self store:
store_id == agentId→readwrite - Explicit grant:
memory_grantsrow exists → level from grant - Chat participant: Agent is in
chatParticipantsfor the chat UUID →readwrite - Session user:
store_id == session.userId→readwrite - Denied: None of the above match →
403
In-Context vs Not-In-Context
in_context=true(default): Entries visible to the LLM via thememorytoolin_context=false: Entries only accessible viagetInternal/setInternal-- for skill-internal data like API keys
Internal API
For skill developers, direct access without going through the LLM:
const value = await memorySkill.getInternal(storeId, key);
await memorySkill.setInternal(storeId, key, value, {
encrypted: true,
ttl: 3600,
});Security
owner_idis always set server-side (never LLM-controlled)- UUIDs are not bearer tokens -- access is always verified
- Grants require
readwriteaccess to create - Encrypted entries are excluded from search indexing
- Chat/user contextual access is ephemeral (real-time participant check)
Configuration
Memory is configured per-agent in the UI under Settings > Memory:
- Master toggle: Enable/disable memory for the agent
- Self store: Agent's own persistent memory
- Chat store: Per-conversation shared memory
- User store: Per-user personalization memory
Migration from KV Skill
The old kv_set/kv_get/kv_delete tools are still available via the RobutlerKVSkill / KVSkill aliases (deprecated). To migrate:
- Replace
KVSkillwithMemorySkill(Python) orRobutlerMemorySkill(TypeScript) - The new
memorytool uses anactionparameter instead of separate tool names - Add
storeparameter (defaults to agent's self store for backward compatibility)
Host self-edit
Let an agent declare, update, and remove its own user-authored functions when chatting with its owner — gated by feature flag and per-call ownership re-check.
NLI Skill (Natural Language Interface)
Agent-to-agent communication over HTTP / UAMP with budgeting, retries, and trust enforcement.