Stores facts about the user that outlive the session: who they are, what they prefer, which hosts and tools they run, what they are working on. Anything true tomorrow but not worth rediscovering belongs here; anything true only for this turn belongs in scratchpad.
Facts are scoped to the user. A save is an upsert on (category, key) — writing the same key again overwrites it rather than adding a second fact, so correct a wrong fact by saving over it.
| Parameter | Used by | Description | ||||
|---|---|---|---|---|---|---|
action |
required | save \ |
search \ |
forget \ |
list. |
|
query |
search |
Keywords describing what to look for. | ||||
category |
save, forget |
profile \ |
preferences \ |
technical \ |
projects \ |
other. |
key |
save, forget |
snake_case identifier, unique within the category. |
||||
value |
save |
The fact, one concise plain-text statement. | ||||
source |
save |
conversation (default) \ |
tool_call \ |
auto_discovery \ |
user_explicit. |
|
confidence |
save |
0–100, default 70. | ||||
expires_days |
save |
Days until the fact expires. Omit for "never". | ||||
source_context |
save |
Provenance, e.g. found via ip addr on localhost. |
Categories: profile = who they are, preferences = likes/dislikes, technical = OS/tools/servers, projects = ongoing work, other = everything else.
saveRequires category, key and value; omitting any of the three fails the call with a specific message. An invalid category is rejected; an invalid source is silently coerced to conversation, and confidence is clamped to 0–100.
{"action": "save", "category": "preferences", "key": "response_language",
"value": "Prefers all answers in Russian", "source": "user_explicit",
"confidence": 95, "source_context": "user asked directly in session"}
{"action": "save", "category": "technical", "key": "prod_server_ip",
"value": "Production runs on 192.168.1.168 (branch master, docker postgres)",
"source": "tool_call", "confidence": 95, "expires_days": 7,
"source_context": "found via ssh_exec hostname/ip addr"}
Calibrate the two numbers honestly — they are what makes a fact worth trusting later:
| How you learned it | source |
confidence |
|---|---|---|
| Ran a tool and read the output | tool_call |
95 |
| The user told you | user_explicit |
80–95 |
| Extracted from the conversation | conversation |
70 |
| Read it on the web | auto_discovery |
50 |
| Inferred / guessed | conversation |
30 |
System facts expire. An IP, a running service, a host's disk layout — set expires_days: 7. A stale host address is worse than no address, because it is trusted. Durable preferences and identity never expire.
searchRequires query. Returns up to 15 matching facts, each with its category, key, value and provenance (src, conf, ctx). This is the read path — search before saving, so you update an existing key instead of inventing a near-duplicate.
{"action": "search", "query": "server ip"}
{"action": "search", "query": "language preference"}
forgetRequires key; category optionally narrows it. Returns how many facts were deleted; deleting nothing is an error (not found), not a silent success.
{"action": "forget", "key": "prod_server_ip", "category": "technical"}
listReturns the categories that hold facts, not the facts themselves:
{"action": "list"}
Use it to see the shape of what is stored; use search to read the content.
home_server_ip and prod_server_ip are different facts; server holding three sentences is one unusable blob.value is a statement, not a field name: "Home server is 192.168.1.168", not "192.168.1.168".