Memory
Each agent owns a private key-value store. Entries are plain text with optional JSON metadata, addressed by string keys, and persisted to the agent's filesystem directory under agent_dir/memory/. The MCP server surfaces every entry as a resource (juglans://memory/<key>) so MCP-aware hosts auto-load them on connect.
All memory endpoints require the read scope. Writes are still gated on read because every key the agent has minted carries it by default — split scopes if you want a stricter model.
Conventional keys
Memory is just a KV store, but a few keys carry semantic meaning across the platform. The MCP server, the chat workflow, and the agent integration UI all look for them:
| Key | Meaning |
|---|---|
persona |
The agent's system prompt — adopt as operating instructions. |
style |
Tone, voice, formatting preferences. |
rules |
Hard rules the agent must never violate. |
goals |
Long-term objectives. |
expertise |
Specialty domains. |
Anything else is free-form. Keep keys short, lowercase, and unambiguous (positions_strategy_2026q2 is fine; spaces and slashes are not).
Edit-source bookkeeping
Every entry tracks who last wrote it via the updated_by field — "user" for owner edits made through the JWT-side endpoints (/api/agents/{id}/memories), "agent" for self-edits made through the agent-scope endpoints documented here.
When an agent tries to overwrite an entry whose last editor was "user", the request fails with 409 Conflict. Pass "force": true in the body to override — useful when you intentionally want the agent to take over a key the human seeded.
GET /api/memory
List every memory entry the agent has saved.
Request
curl https://api.juglans.ai/api/memory \
-H "Authorization: Bearer jg_a_3f8a9c1..."
Response
{
"memories": [
{
"key": "persona",
"content": "You are Nora, a calm spread-trading assistant...",
"metadata": {},
"updated_at": "2026-04-12T18:42:11Z",
"updated_by": "user"
},
{
"key": "expertise",
"content": "Hyperliquid perps, basis trades, funding-rate arbitrage.",
"metadata": { "tags": ["perps", "funding"] },
"updated_at": "2026-04-15T09:13:00Z",
"updated_by": "agent"
}
]
}
GET /api/memory/search?q=<term>
Case-insensitive substring search over keys and content.
Request
curl "https://api.juglans.ai/api/memory/search?q=funding" \
-H "Authorization: Bearer jg_a_3f8a9c1..."
Response
{
"memories": [
{
"key": "expertise",
"content": "Hyperliquid perps, basis trades, funding-rate arbitrage.",
"metadata": { "tags": ["perps", "funding"] },
"updated_at": "2026-04-15T09:13:00Z",
"updated_by": "agent"
}
]
}
GET /api/memory/{key}
Read one entry by key.
Request
curl https://api.juglans.ai/api/memory/persona \
-H "Authorization: Bearer jg_a_3f8a9c1..."
Response
{
"key": "persona",
"content": "You are Nora, a calm spread-trading assistant...",
"metadata": {},
"updated_at": "2026-04-12T18:42:11Z",
"updated_by": "user"
}
404 Not Found if the key doesn't exist.
PUT /api/memory/{key}
Create or overwrite an entry.
Request
curl -X PUT https://api.juglans.ai/api/memory/expertise \
-H "Authorization: Bearer jg_a_3f8a9c1..." \
-H "Content-Type: application/json" \
-d '{
"content": "Hyperliquid perps, basis trades, funding-rate arbitrage.",
"metadata": { "tags": ["perps", "funding"] }
}'
| Field | Type | Notes |
|---|---|---|
content |
string | Required. The body of the memory. |
metadata |
object | Optional. Any JSON. Returned verbatim on read. |
force |
bool | Optional. Default false. Set true to overwrite a "user"-edited entry. |
Response
{
"key": "expertise",
"content": "Hyperliquid perps, basis trades, funding-rate arbitrage.",
"metadata": { "tags": ["perps", "funding"] },
"updated_at": "2026-04-29T14:02:00Z",
"updated_by": "agent"
}
Conflict
{
"error": "Conflict: Memory 'persona' was last edited by the user; pass force=true to overwrite"
}
DELETE /api/memory/{key}
Remove an entry. Idempotent — succeeds whether or not the key existed.
Request
curl -X DELETE https://api.juglans.ai/api/memory/scratch_2026q1 \
-H "Authorization: Bearer jg_a_3f8a9c1..."
Response
{ "deleted": true }
Reading agent memory from MCP
If the same memory needs to be visible to a host like Claude Code, you don't need to do anything extra — the MCP server reads from the same store. get_memory(key="persona") over MCP returns the same bytes as GET /api/memory/persona over HTTP. See the MCP page for more.